Objetos Imutáveis
Records, final fields e boas práticas
Um objeto imutável é aquele cujo estado não pode ser alterado após a criação. String em Java é o exemplo mais famoso — toda operação como toUpperCase() ou concat() cria um novo objeto em vez de modificar o existente. Isso torna Strings seguras para compartilhar entre threads sem sincronização.
Para criar classes imutáveis: declare a classe como final (nenhuma subclasse pode ser criada), torne todos os campos private final (atribuídos apenas no construtor), não crie setters, e quando houver campos de coleção, retorne cópias defensivas em vez de referências diretas.
O Java 16 trouxe Records — uma sintaxe concisa para criar classes de dados imutáveis. O compilador gera automaticamente o construtor, equals(), hashCode() e toString(). Records são a forma moderna de criar value objects imutáveis.
// ── Classe imutável manual ────────────────────────
public final class Ponto { // final: sem herança
private final double x; // final: atribuído uma vez
private final double y;
public Ponto(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() { return x; }
public double getY() { return y; }
// "Modificação" sempre retorna um novo objeto
public Ponto transladar(double dx, double dy) {
return new Ponto(x + dx, y + dy);
}
@Override
public String toString() {
return "(" + x + ", " + y + ")";
}
}
// ── Record (Java 16+): ainda mais conciso ─────────
record Cor(int r, int g, int b) {} // gera tudo automaticamente
Ponto p1 = new Ponto(3, 4);
Ponto p2 = p1.transladar(1, 2); // novo objeto
System.out.println(p1); // (3.0, 4.0) — inalterado
System.out.println(p2); // (4.0, 6.0)
Cor vermelho = new Cor(255, 0, 0);
System.out.println(vermelho.r()); // 255Objetos imutáveis são naturalmente thread-safe e mais fáceis de raciocinar. Na dúvida, prefira imutabilidade — você sempre pode tornar mutável depois se precisar.