Menu
Coddy logo textTech

Records (Java 16+)

Parte da seção Programação Orientada a Objetos do Journey de Java da Coddy — lição 51 de 87.

Ao criar classes simples de transporte de dados, você frequentemente escreve código boilerplate repetitivo: campos privados, um construtor, getters, toString(), equals() e hashCode(). O Java 16 introduziu records para eliminar esse tédio.

Um record é uma classe especial projetada para conter dados imutáveis. Você o declara com a palavra-chave record seguida pela lista de componentes:

record Person(String name, int age) { }

// Essa única linha fornece automaticamente:
// - campos private final: name e age
// - um construtor: Person(String name, int age)
// - métodos de acesso: name() e age()
// - toString(), equals(), e hashCode()

Usar um record é simples:

Person p = new Person("Alice", 30);
System.out.println(p.name());    // Alice
System.out.println(p.age());     // 30
System.out.println(p);           // Person[name=Alice, age=30]

Observe que os métodos de acesso não usam o prefixo get — eles são simplesmente nomeados com base nos campos. Records são implicitamente final, portanto não podem ser estendidos. Todos os campos também são final, tornando os records inerentemente imutáveis.

Você pode adicionar métodos personalizados e sobrescrever os gerados automaticamente, se necessário. Você também pode adicionar validação em um construtor compacto:

record Person(String name, int age) {
    public Person {
        if (age < 0) throw new IllegalArgumentException("Age cannot be negative");
    }
}

Records são perfeitos para DTOs, respostas de API ou qualquer cenário onde você precise de um contêiner de dados simples e imutável sem escrever código boilerplate.

challenge icon

Desafio

Fácil

Vamos construir um sistema de reserva de ingressos de cinema que demonstra a elegância dos Java records. Você verá como os records eliminam o código boilerplate, permitindo ainda a adição de métodos personalizados e validação.

Você organizará seu código em três arquivos:

  • Movie.java: Crie um record representando um filme com três componentes: title (String), genre (String) e durationMinutes (int). Adicione um método personalizado chamado getFormattedDuration() que retorna a duração em um formato amigável: [hours]h [minutes]m (por exemplo, 142 minutos tornam-se 2h 22m). Use divisão inteira e módulo para calcular as horas e os minutos restantes.
  • Ticket.java: Crie um record representando um ingresso de cinema com três componentes: movie (Movie), seatNumber (String) e price (double). Adicione um construtor compacto que valida o preço—se o preço for menor ou igual a zero, lance uma IllegalArgumentException com a mensagem Price must be positive. Também adicione um método personalizado chamado printTicket() que retorna uma string de várias linhas:
    ========== TICKET ==========
    Movie: [movie title]
    Genre: [movie genre]
    Duration: [formatted duration from movie]
    Seat: [seatNumber]
    Price: $[price]
    ============================
  • Main.java: Reúna seu sistema de reservas! Você receberá cinco entradas: título do filme (String), gênero (String), duração em minutos (int), número do assento (String) e preço do ingresso (double).

    Crie um record Movie com as três primeiras entradas e, em seguida, crie um record Ticket com o filme, o número do assento e o preço. Imprima o resultado da chamada de printTicket() no seu ingresso.

Você receberá cinco entradas em ordem: título do filme, gênero, duração (minutos), número do assento e preço.

Observe como os records são muito mais limpos em comparação com as classes tradicionais—não há necessidade de escrever construtores, getters, toString(), equals() ou hashCode(). O construtor compacto permite adicionar validação sem repetir as atribuições de campos, e você ainda pode adicionar métodos personalizados quando necessário!

Folha de consulta

Java 16 introduziu records para eliminar código boilerplate para classes simples de transporte de dados. Um record é uma classe especial projetada para conter dados imutáveis.

Declare um record com a palavra-chave record seguida pela lista de componentes:

record Person(String name, int age) { }

Isso fornece automaticamente:

  • Campos private final
  • Um construtor
  • Métodos acessores (sem o prefixo get)
  • toString(), equals(), e hashCode()

Usando um record:

Person p = new Person("Alice", 30);
System.out.println(p.name());    // Alice
System.out.println(p.age());     // 30
System.out.println(p);           // Person[name=Alice, age=30]

Records são implicitamente final e não podem ser estendidos. Todos os campos são final, tornando os records inerentemente imutáveis.

Adicione validação usando um construtor compacto:

record Person(String name, int age) {
    public Person {
        if (age < 0) throw new IllegalArgumentException("Age cannot be negative");
    }
}

Você pode adicionar métodos personalizados aos records:

record Person(String name, int age) {
    public String getInfo() {
        return name + " is " + age + " years old";
    }
}

Experimente você mesmo

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Ler entradas
        String title = scanner.nextLine();
        String genre = scanner.nextLine();
        int durationMinutes = Integer.parseInt(scanner.nextLine());
        String seatNumber = scanner.nextLine();
        double price = Double.parseDouble(scanner.nextLine());
        
        // TODO: Criar um record Movie com title, genre, e durationMinutes
        
        // TODO: Criar um record Ticket com o movie, seatNumber, e price
        
        // TODO: Imprimir o ticket usando o método printTicket()
        
    }
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos