Veja os JavaDocs e esta palestra de Stuart Marks (ou versões anteriores).
Usarei o seguinte para os exemplos de código:
List<Integer> listOf = List.of(...);
List<Integer> asList = Arrays.asList(...);
List<Integer> unmodif = Collections.unmodifiableList(asList);
Imutabilidade estrutural (Ou: inalterabilidade)
Qualquer tentativa de mudança estruturalList.of
resultará em um UnsupportedOperationException
. Isso inclui operações como adicionar , definir e remover . Você pode, entretanto, alterar o conteúdo dos objetos na lista (se os objetos não forem imutáveis), para que a lista não seja "completamente imutável".
Este é o mesmo destino para listas não modificáveis criadas com Collections.unmodifiableList
. Apenas esta lista é uma visualização da lista original, portanto, ela pode mudar se você alterar a lista original.
Arrays.asList
não é completamente imutável, não tem uma restrição sobre set
.
listOf.set(1, "a"); // UnsupportedOperationException
unmodif.set(1, "a"); // UnsupportedOperationException
asList.set(1, "a"); // modified unmodif! unmodif is not truly unmodifiable
Da mesma forma, alterar a matriz de apoio (se você a mantiver) mudará a lista.
A imutabilidade estrutural vem com muitos efeitos colaterais relacionados à codificação defensiva, simultaneidade e segurança que estão além do escopo desta resposta.
Hostilidade nula
List.of
e qualquer coleção desde Java 1.5 não permite null
como um elemento. A tentativa de passar null
como um elemento ou mesmo uma pesquisa resultará em um NullPointerException
.
Como Arrays.asList
é uma coleção de 1.2 (o Framework de coleções), ele permite null
s.
listOf.contains(null); // NullPointerException
unmodif.contains(null); // allowed
asList.contains(null); // allowed
Formulário serializado
Como List.of
foi introduzido no Java 9 e as listas criadas por esse método têm sua própria forma serializada (binária), elas não podem ser desserializadas em versões anteriores do JDK (sem compatibilidade binária ). No entanto, você pode cancelar / serializar com JSON, por exemplo.
Identidade
Arrays.asList
chamadas internamente new ArrayList
, o que garante a desigualdade de referência.
List.of
depende da implementação interna. As instâncias retornadas podem ter igualdade de referência, mas como isso não é garantido, você não pode confiar nela.
asList1 == asList2; // false
listOf1 == listOf2; // true or false
Vale ressaltar que as listas são iguais (via List.equals
) se contiverem os mesmos elementos na mesma ordem, independentemente de como foram criadas ou das operações que suportam.
asList.equals(listOf); // true i.f.f. same elements in same order
Implementação (aviso: os detalhes podem mudar nas versões)
Se o número de elementos na lista de List.of
for 2 ou menos, os elementos serão armazenados em campos de uma classe especializada (interna). Um exemplo é a lista que armazena 2 elementos (fonte parcial):
static final class List2<E> extends AbstractImmutableList<E> {
private final E e0;
private final E e1;
List2(E e0, E e1) {
this.e0 = Objects.requireNonNull(e0);
this.e1 = Objects.requireNonNull(e1);
}
}
Caso contrário, eles são armazenados em uma matriz de maneira semelhante a Arrays.asList
.
Eficiência de tempo e espaço
As List.of
implementações baseadas em campo (tamanho <2) têm um desempenho ligeiramente mais rápido em algumas operações. Como exemplos, size()
pode retornar uma constante sem buscar o comprimento do array e contains(E e)
não requer sobrecarga de iteração.
Construir uma lista não modificável via List.of
também é mais rápido. Compare o construtor acima com 2 atribuições de referência (e até mesmo aquele para quantidade arbitrária de elementos) para
Collections.unmodifiableList(Arrays.asList(...));
que cria 2 listas mais outra sobrecarga. Em termos de espaço, você economiza o UnmodifiableList
invólucro e alguns centavos. Em última análise, a economia no HashSet
equivalente é mais convincente.
Tempo de conclusão: use List.of
quando quiser uma lista que não muda e Arrays.asList
quando quiser uma lista que pode mudar (como mostrado acima).