Objetos imutáveis ​​em Java

Objetos imutáveis ​​em Java

1. Visão geral

Neste tutorial, aprenderemos o que torna um objeto imutável, como alcançar a imutabilidade em Java e quais as vantagens de fazer isso.

2. O que é um objeto imutável?

Um objeto imutável é umobject whose internal state remains constant after it has been entirely created.

Isso significa que a API pública de um objeto imutável nos garante que ele se comportará da mesma maneira durante toda a sua vida útil.

Se dermos uma olhada na classeString, podemos ver que mesmo quando sua API parece nos fornecer um comportamento mutável com seu métodoreplace, oString original não muda:

String name = "example";
String newName = name.replace("dung", "----");

assertEquals("example", name);
assertEquals("bael----", newName);

A API fornece métodos somente leitura, nunca deve incluir métodos que alteram o estado interno do objeto.

3. A palavra-chavefinal em Java

Antes de tentar alcançar a imutabilidade em Java, devemos falar sobre a palavra-chavefinal.

Em Java,variables are mutable by default, meaning we can change the value they hold.

Usando a palavra-chavefinal ao declarar uma variável, o compilador Java não nos deixará alterar o valor dessa variável. Em vez disso, ele relatará um erro em tempo de compilação:

final String name = "example";
name = "bael...";

Observe quefinal apenas nos proíbe de alterar a referência que a variável contém, não nos protege de alterar o estado interno do objeto ao qual se refere usando sua API pública:

final List strings = new ArrayList<>();
assertEquals(0, strings.size());
strings.add("example");
assertEquals(0, strings.size());

O segundoassertEquals falhará porque adicionar um elemento à lista altera seu tamanho, portanto, não é um objeto imutável.

4. Imutabilidade em Java

Agora que sabemos como evitar alterações no conteúdo de uma variável, podemos usá-la para criar a API de objetos imutáveis.

Construir a API de um objeto imutável exige que garantamos que seu estado interno não mudará, independentemente de como usarmos sua API.

Um passo adiante na direção certa é usarfinal ao declarar seus atributos:

class Money {
    private final double amount;
    private final Currency currency;

    // ...
}

Observe que o Java nos garante que o valor deamount não mudará, esse é o caso com todas as variáveis ​​de tipo primitivo.

No entanto, em nosso exemplo, temos apenas a garantia de quecurrency não mudará, entãowe must rely on the CurrencyAPI to protect itself from changes.

Na maioria das vezes, precisamos dos atributos de um objeto para armazenar valores personalizados, e o local para inicializar o estado interno de um objeto imutável é seu construtor:

class Money {
    // ...
    public Money(double amount, Currency currency) {
        this.amount = amount;
        this.currency = currency;
    }

    public Currency getCurrency() {
        return currency;
    }

    public double getAmount() {
        return amount;
    }
}

Como dissemos antes, para atender aos requisitos de uma API imutável, nossa classeMoney tem apenas métodos somente leitura.

Usando a API de reflexão, podemos quebrar a imutabilidade echange immutable objects. No entanto, a reflexão viola a API pública do objeto imutável e, normalmente, devemos evitar fazer isso.

5. Benefícios

Como o estado interno de um objeto imutável permanece constante no tempo,we can share it safely among multiple threads.

Também podemos usá-lo livremente, e nenhum dos objetos que fazem referência a ele notará qualquer diferença, podemos dizer queimmutable objects are side-effects free.

6. Conclusão

Objetos imutáveis ​​não mudam seu estado interno com o tempo, eles são thread-safe e sem efeitos colaterais. Devido a essas propriedades, objetos imutáveis ​​também são especialmente úteis ao lidar com ambientes com vários threads.

Você pode encontrar os exemplos usados ​​neste artigoover on GitHub.