Sobes.tech
Middle

Como tornar uma classe em Java imutável?

sobes.tech IA

Resposta da IA

Para tornar uma classe em Java imutável, deve seguir-se os seguintes princípios:

  1. Marcar a classe como final. Isto impedirá a herança, que pode levar a alterações no estado.
  2. Tornar todos os campos da classe privados (private). Isto limitará o acesso direto aos campos de fora da classe.
  3. Não fornecer setters (métodos para modificar o estado dos campos).
  4. Tornar todos os campos mutáveis da classe final. Isto garante que as referências a objetos mutáveis não possam ser alteradas após a inicialização.
  5. Se a classe contiver referências a objetos mutáveis (por exemplo, java.util.Date, coleções), ao retorná-los dos getters ou passá-los ao construtor, deve criar e devolver cópias desses objetos. Isto é chamado de "cópia profunda".

Exemplo:

// Exemplo de classe imutável
final class ImmutablePerson {
    private final String name;
    private final int age;
    private final List<String> hobbies; // Campo mutável

    // Construtor com cópia profunda dos campos mutáveis
    public ImmutablePerson(String name, int age, List<String> hobbies) {
        this.name = name;
        this.age = age;
        // Criar uma cópia da lista hobbies
        this.hobbies = new ArrayList<>(hobbies);
    }

    // Getters
    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    // Devolver uma cópia da lista hobbies para evitar alterações externas
    public List<String> getHobbies() {
        return Collections.unmodifiableList(new ArrayList<>(this.hobbies));
    }

    // Sobrescrever toString para conveniência
    @Override
    public String toString() {
        return "ImmutablePerson{" +
               "name='" + name + '\'' +
               ", age=" + age +
               ", hobbies=" + hobbies +
               '}';
    }
}

Exemplo de uso:

// Exemplo de uso de uma classe imutável
List<String> initialHobbies = new ArrayList<>();
initialHobbies.add("Reading");
initialHobbies.add("Hiking");

ImmutablePerson person = new ImmutablePerson("Alice", 30, initialHobbies);

// Tentar modificar a lista obtida resultará numa exceção
List<String> retrievedHobbies = person.getHobbies();
// retrievedHobbies.add("Coding"); // Lançará UnsupportedOperationException

// A alteração da lista original não afetará o objeto ImmutablePerson
initialHobbies.add("Painting");

System.out.println(person); // Saída: ImmutablePerson{name='Alice', age=30, hobbies=[Reading, Hiking]}
System.out.println(initialHobbies); // Saída: [Reading, Hiking, Painting]