Cópia Defensiva e Imutabilidade¶
A cópia defensiva estabelece posse ao impedir que chamador e receptor alterem o mesmo estado inesperadamente. A imutabilidade vai além: após a construção, o estado observável nunca muda. Ambas reduzem acoplamento temporal e facilitam compartilhamento seguro.
Cópia na entrada e na saída¶
public final class Route {
private final List<String> stops;
public Route(Collection<String> stops) {
this.stops = List.copyOf(stops);
if (this.stops.stream().anyMatch(Objects::isNull)) {
throw new IllegalArgumentException("stops cannot contain null");
}
}
public List<String> stops() {
return stops;
}
}
List.copyOf impede modificação estrutural pela lista retornada e a separa da
fonte mutável. É cópia rasa: elementos mutáveis ainda permitem alterar estado
alcançável. Imutabilidade profunda exige elementos imutáveis ou cópias em todo limite de posse.
Arrays, Date, builders, buffers e coleções frequentemente precisam de cópias.
Uma view não modificável não é cópia; mudanças por outra referência continuam visíveis.
Records e builders¶
Records reduzem sintaxe, mas não tornam componentes profundamente imutáveis. Use construtor compacto para normalizar e copiar. Um builder pode ser mutável durante a construção, mas o objeto final não deve reter seu armazenamento mutável.
Concorrência e publicação¶
Objetos imutáveis bem construídos são mais fáceis de publicar e compartilhar. Isso não torna atômicas operações sobre recursos mutáveis externos. Um snapshot também fica obsoleto; atualidade é outro contrato.
Compromissos¶
Cópias custam tempo e memória. Prefira transferência clara de posse, valores imutáveis, estruturas persistentes ou snapshots limitados. Meça antes de evitar uma cópia necessária e documente APIs que emprestam armazenamento do chamador.
Teste mutação das entradas, retornos e elementos aninhados, além da estabilidade de igualdade e hash em coleções ou chaves de cache.