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.asListnã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.ofe qualquer coleção desde Java 1.5 não permite nullcomo um elemento. A tentativa de passar nullcomo 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 nulls.
listOf.contains(null); // NullPointerException
unmodif.contains(null); // allowed
asList.contains(null); // allowed
Formulário serializado
Como List.offoi 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.asListchamadas internamente new ArrayList, o que garante a desigualdade de referência.
List.ofdepende 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.offor 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.ofimplementaçõ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.oftambé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 UnmodifiableListinvólucro e alguns centavos. Em última análise, a economia no HashSetequivalente é mais convincente.
Tempo de conclusão: use List.ofquando quiser uma lista que não muda e Arrays.asListquando quiser uma lista que pode mudar (como mostrado acima).