Collections.emptyList () vs. nova instância

241

Na prática, é melhor retornar uma lista vazia como esta :

return Collections.emptyList();

Ou como esta :

return new ArrayList<Foo>();

Ou isso é completamente dependente do que você fará com a lista retornada?

senhor
fonte

Respostas:

300

A principal diferença é que Collections.emptyList()retorna uma lista imutável , ou seja, uma lista à qual você não pode adicionar elementos. (O mesmo se aplica ao List.of()introduzido no Java 9.)

Nos casos raros em que você não deseja modificar a lista retornada, Collections.emptyList()e List.of(), portanto, são não uma boa escolha.

Eu diria que retornar uma lista imutável é perfeitamente adequado (e até a maneira preferida), desde que o contrato (documentação) não explique explicitamente de maneira diferente.


Além disso, emptyList() pode não criar um novo objeto a cada chamada.

As implementações desse método não precisam criar um objeto List separado para cada chamada. O uso desse método provavelmente terá um custo comparável ao uso do campo com o mesmo nome. (Diferentemente deste método, o campo não fornece segurança de tipo.)

A implementação da emptyListaparência é a seguinte:

public static final <T> List<T> emptyList() {
    return (List<T>) EMPTY_LIST;
}

Portanto, se seu método (que retorna uma lista vazia) for chamado com muita frequência, essa abordagem poderá fornecer um desempenho um pouco melhor, tanto na CPU quanto na memória.

aioobe
fonte
4
Então, seria Collections.emptyList()mais adequado para, digamos, verificação de erros e afins?
quer
1
Os clientes da API não receberão NullPointerExceptionretornando em Collections.emptyList()vez de null.
realPK
@PK_J faz uma observação importante. Collections.emptyList()é iterável e retorna um comprimento, para que possa ser usado em loops sem que uma exceção seja lançada.
Ndm13
que tal usar List.of()?
4
@AJW, sim. Mas comparado a, digamos, new ArrayList<>()também torna clara a decisão de design; elementos não serão adicionados a esta lista.
precisa saber é
51

A partir do Java 5.0, você pode especificar o tipo de elemento no contêiner:

Collections.<Foo>emptyList()

Concordo com as outras respostas que, nos casos em que você deseja retornar uma lista vazia que permanece vazia, você deve usar essa abordagem.

Paul Jackson
fonte
38
Começando com Java 7, você pode deixar o compilador inferir o parâmetro tipo de invocação de método genérico do tipo de destino:List<Foo> list = Collections.emptyList()
Paul Jackson
28

Collections.emptyList é imutável; portanto, há uma diferença entre as duas versões; portanto, você deve considerar os usuários do valor retornado.

O retorno new ArrayList<Foo>sempre cria uma nova instância do objeto, por isso tem um custo extra muito pequeno associado a ele, o que pode lhe dar um motivo para usá-lo Collections.emptyList. Eu gosto de usar emptyListapenas porque é mais legível.

Jeff Foster
fonte
14

Tenha cuidado, porém. Se você retornar Collections.emptyList()e tentar fazer algumas alterações com algo assim add(), você terá um UnsupportedOperationException()porque Collections.emptyList()retorna um objeto imutável.

Sergey Frolov
fonte
7

Eu aceitaria Collections.emptyList()se a lista retornada não estivesse sendo modificada de forma alguma (como a lista é imutável), caso contrário, eu iria com a opção 2.

O benefício de Collections.emptyList()é que a mesma instância estática é retornada a cada vez e, portanto, não há criação de instância ocorrendo para cada chamada.

S73417H
fonte
3

Use Collections.emptyList () se quiser garantir que a lista retornada nunca seja modificada. É isso que é retornado ao chamar emptyList ():

/**
 * The empty list (immutable). 
 */
public static final List EMPTY_LIST = new EmptyList();
Atul
fonte
Cheguei aqui tentando descobrir se a ligação Collections.emptyList()tinha um custo de construção. Ver os detalhes da implementação (embora provavelmente não seja o mesmo em todas as JVMs) confirma que não. @Atul, de que JVM é essa?
Wjl 29/08/13
2

As respostas dadas enfatizam o fato de emptyList()retornar um imutável, Listmas não fornecer alternativas. Os ArrayList(int initialCapacity)casos especiais do Construtor , 0portanto, retornar em new ArrayList<>(0)vez de new ArrayList<>()também pode ser uma solução viável:

/**
 * Shared empty array instance used for empty instances.
 */
private static final Object[] EMPTY_ELEMENTDATA = {};

[...]

/**
 * Constructs an empty list with the specified initial capacity.
 *
 * @param  initialCapacity  the initial capacity of the list
 * @throws IllegalArgumentException if the specified initial capacity
 *         is negative
 */
public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    }
}

(fontes do Java 1.8.0_72)

René
fonte
Eu discordo da sua abordagem. Você economiza um pouco de memória e CPU na inicialização, mas se a lista retornada for modificada, você perderá o tempo em que a lista realocar uma nova matriz. Se muitos elementos forem adicionados à lista ao longo do tempo, isso poderá se tornar um gargalo de desempenho devido à taxa de crescimento muito mais lenta . Eu prefiro manter a convenção de uma lista vazia não modificável ou de uma lista modificável e utilizável.
Patrick M
1
Como tentei enfatizar com minhas palavras ( pode ser viável ): tudo depende do seu caso de uso. I, em geral, quer voltar mutáveis ou Colecções unmutable, não seja uma mistura dependendo meteorológicas eles estão vazios ou não. E para contrariar a "reivindicação muito mais lenta": esta é a implementação atual.
René
Oh cara, olhe para mim citando as principais versões do JDK 2 desatualizadas. Portanto, o java8 evita totalmente o gargalo, saltando para a capacidade padrão a partir de um tamanho inicial de 0. Desculpe, eu estava errado.
Patrick M