Java Immutable Collections


115

Da documentação do Java 1.6 Collection Framework :

Coleções que não oferecem suporte a nenhuma operação de modificação (como add, removee clear) são chamadas de não modificáveis . [...] Coleções que garantem adicionalmente que nenhuma mudança no objeto Coleção será visível são chamadas de imutáveis .

O segundo critério me confunde um pouco. Dado que a primeira coleção não pode ser modificada, e supondo que a referência da coleção original tenha sido descartada, quais são as mudanças mencionadas na segunda linha? Está se referindo às mudanças nos elementos mantidos na coleção, ou seja, o estado dos elementos?

Segunda questão:
para que uma coleção seja imutável, como se faz para fornecer as garantias adicionais especificadas? Se o estado de um elemento na coleção for atualizado por um encadeamento, é suficiente para a imutabilidade que essas atualizações no estado não sejam visíveis no encadeamento que contém a coleção imutável?

Para que uma coleção seja imutável, como fornecer as garantias adicionais especificadas?


Em geral (especialmente em linguagens funcionais), a coleção imutável (também conhecida como persistente) pode mudar no sentido de que você pode obter um novo estado dessa coleção, mas ao mesmo tempo o estado antigo ainda estará disponível em outros links. Por exemplo, newCol = oldCol.add("element")produzirá uma nova coleção que é uma cópia da antiga com mais 1 elemento, e todas as referências a oldColainda apontarão para a mesma coleção antiga inalterada.
ffriend,

Respostas:


154

Coleções não modificáveis ​​são geralmente visualizações somente leitura (invólucros) de outras coleções. Você não pode adicionar, remover ou apagá-los, mas a coleção subjacente pode mudar.

Coleções imutáveis ​​não podem ser alteradas de forma alguma - elas não envolvem outra coleção - elas têm seus próprios elementos.

Aqui está uma citação de goiaba ImmutableList

Ao contrário Collections.unmodifiableList(java.util.List<? extends T>), que é uma exibição de uma coleção separada que ainda pode ser alterada, uma instância de ImmutableListcontém seus próprios dados privados e nunca será alterada.

Então, basicamente, para obter uma coleção imutável de uma mutável, você precisa copiar seus elementos para a nova coleção e proibir todas as operações.


@Bhaskar - veja meu último parágrafo.
Bozho,

1
se a coleção que está embalada dentro de outra coleção não modificável não possui nenhuma outra referência a ela, então o bahaviour da coleção não modificável é exatamente o mesmo para uma coleção imutável?
Bhaskar,

1
@Bozho, se a referência à coleção de apoio não for fornecida, e apenas a referência do wrapper da coleção não modificável for fornecida, não há como alterá-la. Então, por que você diz "Você não pode ter certeza"? Ele aponta para um cenário onde algum encadeamento ou de alguma forma é modificado porque a coleção de apoio é modificável?
AKS de

@AKS: Quando uma coleção é agrupada unmodifiableList, o código que recebe apenas uma referência a essa lista não será capaz de modificá-la, mas qualquer código que tivesse uma referência à lista original e pudesse modificá-la antes que o wrapper fosse criado ainda será ser capaz de fazer isso depois. Se o código que criou a lista original sabe o que aconteceu com cada referência que já existiu para ele e sabe que nenhuma delas cairá nas mãos de um código que possa modificar a lista, então ele pode saber que a lista nunca será modificado. Se a referência foi recebida de um código externo, no entanto ...
supercat

... não há como o unmodifiableList, nem qualquer código que o use, saber se ou como a coleção agrupada pode ser alterada.
supercat

86

A diferença é que você não pode ter uma referência a uma coleção imutável que permite mudanças. Coleções não modificáveis ​​são inalteráveis por meio dessa referência , mas algum outro objeto pode apontar para os mesmos dados por meio dos quais pode ser alterado.

por exemplo

List<String> strings = new ArrayList<String>();
List<String> unmodifiable = Collections.unmodifiableList(strings);
unmodifiable.add("New string"); // will fail at runtime
strings.add("Aha!"); // will succeed
System.out.println(unmodifiable);

1
quais as várias causas, se houver, podem trazer uma mudança em uma coleção que não pode ser modificada, desde que a referência da coleção original não seja usada para modificar a coleção subjacente?
Bhaskar,

21
Collection<String> c1 = new ArrayList<String>();
c1.add("foo");
Collection<String> c2 = Collections.unmodifiableList(c1);

c1é mutável (ou seja, nem não modificável nem imutável ).
c2é unmodifiable : ela não pode ser alterado em si, mas se mais tarde eu mudar c1, em seguida, que a mudança será visível no c2.

Isso ocorre porque c2é simplesmente um invólucro c1e não realmente uma cópia independente. Guava fornece a ImmutableListinterface e algumas implementações. Eles funcionam criando uma cópia da entrada (a menos que a entrada seja uma coleção imutável por conta própria).

Com relação à sua segunda pergunta:

A mutabilidade / imutabilidade de uma coleção não depende da mutabilidade / imutabilidade dos objetos nela contidos. Modificar um objeto contido em uma coleção não conta como uma "modificação da coleção" para esta descrição. Claro, se você precisa de uma coleção imutável, normalmente também quer que ela contenha objetos imutáveis.


2
@John: não, não é. Pelo menos não de acordo com a definição citada pelo OP.
Joachim Sauer,

@JohnVint, realmente? Acho que não, porque usando c1, ainda posso adicionar elementos a ele e essa adição será visível para c2. Isso não significa que não seja imutável?
Bhaskar,

Bem, acho que se c1 pudesse escapar, então não seria imutável, mas imutabilidade também se refere ao conteúdo da coleção. Eu estava mais me referindo a uma coleção não modificável de java.util.Date's
John Vint,

1
@Vint: "se c1não escapa" não é uma consideração diferenciada em qualquer lugar da especificação. Na minha opinião, se você pode usar a coleção de uma forma que a torne não imutável, você deve sempre considerá-la não imutável.
Joachim Sauer,

1
Deixe-me citar a definição: "Coleções que garantem adicionalmente ..." (grifo meu). Collection.unmodifiableList() não pode garantir isso, porque não pode garantir que seu argumento não escape. A goiaba ImmutableList.of sempre produz um imutável List, mesmo que você deixe escapar seus argumentos.
Joachim Sauer,

17

Agora java 9 tem métodos de fábrica para Immutable List, Set, Map e Map.Entry.

No Java SE 8 e em versões anteriores, podemos usar os métodos utilitários da classe Collections, como unmodifiableXXX, para criar objetos Immutable Collection.

No entanto, esses métodos Collections.unmodifiableXXX são uma abordagem muito tediosa e detalhada. Para superar essas deficiências, o Oracle Corp adicionou alguns métodos utilitários às interfaces List, Set e Map.

Agora em java 9: ​​- interfaces List e Set têm métodos “of ()” para criar uma Lista Imutável vazia ou não vazia ou objetos Set conforme mostrado abaixo:

Exemplo de lista vazia

List immutableList = List.of();

Exemplo de lista não vazia

List immutableList = List.of("one","two","three");

2
E em Java 10 List.copyOfe Set.copyOfforam adicionados que permitem criar uma cópia não modificável de uma lista / conjunto, ou retornar a coleção dada se ela já estiver inalterada, veja JDK-8191517
Marcono1234

6

Acredito que o ponto aqui é que mesmo que uma coleção seja Imodificável, isso não garante que ela não possa ser alterada. Considere, por exemplo, uma coleção que despeja elementos se eles forem muito antigos. Imodificável significa apenas que o objeto que contém a referência não pode mudá-la, não que ele não pode mudar. Um verdadeiro exemplo disso éCollections.unmodifiableList método. Ele retorna uma visão não modificável de uma lista. A referência de Lista que foi passada para este método ainda é modificável e, portanto, a lista pode ser modificada por qualquer detentor da referência que foi passada. Isso pode resultar em ConcurrentModificationExceptions e outras coisas ruins.

Imutável, significa que de forma alguma a coleção pode ser alterada.

Segunda questão: Uma coleção Imutável não significa que os objetos contidos na coleção não mudarão, apenas que a coleção não mudará no número e na composição dos objetos que contém. Em outras palavras, a lista de referências da coleção não mudará. Isso não significa que as partes internas do objeto referenciado não possam mudar.


Um bom!! Portanto, se eu criar um wrapper sobre Unmodifiable Collection e tornar a referência de coleção modificável privada, posso ter certeza de que é imutável. certo?
AKS de

Se eu entendo sua pergunta, a resposta é não. O empacotamento de Unmodifiable não faz nada para protegê-lo de que a coleção seja passada para unmodifiableListmodificada. Se você quiser fazer isso, use ImmutableList.
John B de

0

Pure4J apóia o que você , de duas maneiras.

Primeiro, ele fornece uma @ImmutableValueanotação, para que você possa anotar uma classe para dizer que ela é imutável. Existe um plugin maven para permitir que você verifique se o seu código é realmente imutável (uso definal etc.).

Em segundo lugar, ele fornece as coleções persistentes do Clojure (com genéricos adicionados) e garante que os elementos adicionados às coleções sejam imutáveis. O desempenho deles é aparentemente muito bom. As coleções são imutáveis, mas implementam interfaces de coleções java (e genéricos) para inspeção. Mutation retorna novas coleções.

Isenção de responsabilidade: eu sou o desenvolvedor deste

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.