Pular para conteúdo

Igualdade, Hashing e Imutabilidade

Contratos de igualdade

Para referências não-nulas, equals deve ser reflexivo, simétrico, transitivo e consistente, e deve retornar falso para null. Objetos iguais devem ter códigos hash iguais durante uma execução.

Identidade (==) pergunta se referências denotam o mesmo objeto. Igualdade de valor (equals) pergunta se objetos representam o mesmo valor sob seu contrato.

record BookId(String value) {
    BookId {
        Objects.requireNonNull(value, "value");
        if (value.isBlank()) throw new IllegalArgumentException("blank id");
    }
}

Um record deriva igualdade e hashing de seus componentes. O record é tão profundamente imutável quanto seus componentes; um componente que referencie uma lista mutável ainda exigirá cópia defensiva.

Projetando classes imutáveis

  • tornar privado e final o estado que mantém os invariantes;
  • validar construção;
  • não expor estruturas internas mutáveis;
  • copiar entradas e saídas mutáveis onde propriedade não é transferida;
  • impedir a mutação por subclasses quando o contrato exigir.

Imutabilidade simplifica raciocínio, publicação segura, hashing e compartilhamento entre threads. Não torna automaticamente uma operação atômica sobre múltiplos valores imutáveis.

O guia prático expande essas regras para cópias rasas, vistas imutáveis, records, builders, snapshots e chaves de cache.

Consistência do comparador

Conjuntos e mapas ordenados usam a comparação para determinar a distinção entre chaves. Se um comparador retornar zero para objetos que equals considera diferentes, a coleção pode parecer "perder" uma chave. Ou torne a ordenação consistente com igualdade ou documente a relação de equivalência alternativa.

Exercícios

  1. Explique por que a igualdade baseada em subclasses frequentemente quebra a simetria.
  2. Tornar uma classe contendo um List<String> profundamente imutável.
  3. Descrever a falha causada por mutar uma chave hash após inserção.