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?

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.


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.


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.


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.


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.


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();

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)


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
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.