Collections.emptyMap () vs new HashMap ()

143

Quais são algumas das situações em que posso usar Collections.emptyMap()? A documentação diz que posso usar esse método se quiser que minha coleção seja imutável.

Por que eu iria querer uma coleção vazia imutável? Qual é o ponto?

Vinoth Kumar CM
fonte
12
+1 para a pergunta, porque eu nunca vi esse método estático antes
Tim Bender
você também pode dar uma olhada nas lentes scala do google scala . O emptyMap e o immutableMap podem ser usados ​​para criar objetos imutáveis. emptyMap é o ponto inicial. Cada vez que um elemento é adicionado, o próprio mapa é substituído por um mapa que contém o elemento antigo e os novos elementos. O ponto é que os acessos ao objeto são seguros.
22613 Michael
1
É como o Objective-C [NSArray array], retorna um objeto que, embora não seja utilizável, mas existe. Então você pode brincar com ele como um objeto normal e não cometer um erro.
Shane Hsu

Respostas:

144

Desde Effective Java , Item # 43 - "Return empty arrays or collections, not null"demonstra retornando uma coleção vazia e talvez até mesmo demonstra o uso destas emptyList(), emptySet()e emptyMap()métodos de classe as coleções para obter uma coleção vazia, que também tem o benefício adicional de ser imutável. Do item # 15 "Minimize Mutability" .

De Collections-emptySet-Collections-emptyList-Collections

É um tipo de idioma de programação. Isso é para pessoas que não desejam variáveis ​​nulas. Portanto, antes que o conjunto seja inicializado, eles podem usar o conjunto vazio.

Nota: O código abaixo é apenas um exemplo (altere-o de acordo com seu caso de uso):

private Set myset = Collections.emptySet();

void initSet() {
   myset = new HashSet();
}
void deleteSet() {
   myset = Collections.emptySet();
}

Esses métodos oferecem algumas vantagens:

  1. Eles são mais concisos porque você não precisa digitar explicitamente o tipo genérico da coleção - geralmente é apenas inferido a partir do contexto da chamada do método.

  2. Eles são mais eficientes porque não se preocupam em criar novos objetos; eles apenas reutilizam um objeto vazio e imutável existente. Esse efeito geralmente é muito pequeno, mas ocasionalmente (bem, raramente) é importante.

Sumit Singh
fonte
15
+1 para a referência efetiva do Java. Um detalhe: eu recomendaria parametrizar Sete HashSetem seus exemplos, já que o objetivo principal do emptySet()método e dos amigos (em oposição às constantes Collections.EMPTY_SETetc.) é que eles joguem bem com genéricos. Além disso, o uso de um recurso (tipos brutos) que foi descontinuado desde o Java 5 não é uma boa ajuda de ensino.
Daniel Pryden
4
Continuo não convencido ... Não é o ponto principal de usar um em Collectionvez de nullevitar Exceptionsser jogado nas seguintes operações? Usar uma coleção imutável resultaria em algum outro tipo de exceção que eu imagino. E atribuir nullcertamente não é menos eficiente do que atribuir uma constante imutável.
fgysin restabelece Monica
14
@fgysin: Se você tem uma API em que os clientes devem modificar a coleção, sim, não faz sentido retornar uma coleção imutável. Porém, se você tiver uma API na qual retorne uma coleção na qual os clientes não devem modificar e apenas repita, o retorno de uma visualização para a coleção subjacente faz todo o sentido para garantir que um cliente "ruim" não modifique acidentalmente as coleções pertencentes por você. Retornar uma coleção vazia em vez de nula significa que seu cliente não precisa fazer uma verificação nula antes de usar a coleção, tornando o código do cliente mais claro.
31713 Jean Hominal
4
public boolean setExists() { return !myset.equals(Collections.emptySet()); }
Assilias
5
No seu exemplo, você está verificando explicitamente o conjunto vazio e usando-o como um valor sentinela, e sua classe é mutável. Seu pequeno exemplo usa sentinelas e mutabilidade, que é exatamente o que o Collections.emptySet () está tentando impedir.
Marc O'MÓRÁIN
33

É, na minha experiência pessoal, reconhecidamente, muito útil nos casos em que uma API requer uma coleção de parâmetros, mas você não tem nada a fornecer. Por exemplo, você pode ter uma API que se parece com isso e não permite referências nulas:

public ResultSet executeQuery(String query, Map<String, Object> queryParameters);

Se você tem uma consulta que não aceita nenhum parâmetro, é certamente um pouco desperdício criar um HashMap, que envolve a alocação de uma matriz, quando você pode simplesmente passar o 'Empty Map', que é efetivamente uma constante, da maneira como é implementado no java.util.Collections.

Affe
fonte
22

Por que eu iria querer uma coleção vazia imutável? Qual é o ponto?

Existem dois conceitos diferentes aqui que parecem estranhos quando vistos juntos. Faz mais sentido quando você trata os dois conceitos separadamente.

  • Em primeiro lugar, você deve preferir usar uma coleção imutável, em vez de mutável, sempre que possível. Os benefícios da imutabilidade estão bem documentados em outros lugares .

  • Em segundo lugar, você deve preferir usar uma coleção vazia em vez de usar null como sentinela. Isso está bem descrito aqui . Isso significa que você terá um código muito mais limpo e fácil de entender, com menos lugares para os bugs ocultarem.

Portanto, quando você tem um código que requer um mapa, é melhor passar um mapa vazio em vez de um nulo para indicar a ausência de um mapa. E na maioria das vezes quando você está usando um mapa, é melhor usar um mapa imutável. Portanto, é por isso que existe uma função de conveniência para criar um mapa vazio imutável.

Marc O'Morain
fonte
8

Há alguns casos em que você prefere usar mapas, listas, conjuntos ou outros tipos de coleções imutáveis.

O primeiro e discutível caso de uso mais importante é sempre que você retorna um resultado de uma consulta ou um cálculo que retornaria um conjunto (ou lista ou mapa) de resultados; você deve preferir usar estruturas de dados imutáveis.

Nesse caso, prefiro retornar versões imutáveis ​​delas, pois isso reflete a imutabilidade factual de um conjunto de resultados de uma computação muito mais claramente - não importa o que você faça com os dados posteriormente, o conjunto de resultados que você recebeu da sua consulta não deve mudança.

O segundo caso de uso comum é quando você precisa fornecer um argumento como uma entrada para um método ou serviço. A menos que você espere que a coleção de entrada seja modificada pelo serviço ou método (que geralmente é uma péssima idéia de design), passar uma coleção imutável em vez da mutável pode ser a escolha razoável e segura em muitos casos.

Eu penso nisso como uma convenção de "passar por valor" .

Mais geralmente - é uma prática sensata usar estruturas de dados imutáveis ​​sempre que os dados ultrapassam os limites do módulo ou do serviço. Isso facilita muito o raciocínio sobre as diferenças entre entrada / saída (imutável) e estado interno mutável.

Como um efeito colateral muito benéfico, isso aumenta a segurança e a segurança dos threads de seus módulos / serviços e garante uma separação mais limpa das preocupações.

Outra boa razão para usar Collections.empty*()métodos é a notável falta de detalhamento. Na era pré-Java7, se você tinha uma coleção genérica, precisava espalhar anotações de tipo genérico por todo o lado.

Basta comparar estas duas declarações:

Map<Foo, Comparable<? extends Bar>> fooBarMap = new HashMap<Foo, Comparable<? extends Bar>>();

versus:

Map<Foo, Comparable<? extends Bar>> fooBarMap = Collections.emptyMap();

O último ganha claramente a legibilidade de duas maneiras importantes:

  1. Na primeira declaração, toda a instanciação de um mapa vazio é escondida no ruído das declarações de tipo genéricas, tornando uma declaração essencialmente trivial muito mais enigmática do que precisa ser.
  2. Além da notável falta de anotação de tipo genérico no lado direito, a segunda versão indica claramente que o mapa é inicializado em um mapa vazio. Além disso - sabendo que esse método retorna um mapa imutável, agora é mais fácil descobrir onde fooBarMapestá sendo atribuído outro valor não vazio apenas pesquisando /fooBarMap =/.
Roland Tepp
fonte
5

Por um lado, você pode se safar do compartilhamento de referências. Um new HashMap()etc exigirá um objeto alocado e, possivelmente, alguns elementos extras para armazenar os dados, mas você só precisa de uma cópia de uma coleção vazia imutável (lista, conjunto, mapa ou qualquer outro). Isso torna uma escolha óbvia quando um método que você está chamando precisa aceitar um mapa, mas não precisa editá-lo.

Sugiro verificar o Java efetivo de Josh Bloch , que lista alguns atributos muito agradáveis ​​de objetos imutáveis ​​(incluindo segurança de threads).

Jeff Bowman
fonte
3

Pode ser útil quando você tem uma função que retorna immutable collectione, em alguma situação, não há dados a serem retornados, portanto, em vez de retornar, nullvocê pode retornaremptyMap()

Torna seu código mais fácil e evita NullPointerException

iTech
fonte
3

Na maioria das vezes, usamos a constructorpara criar um novo empty map. Mas a Collections methodsoferta oferece algumas vantagens para criar um empty mapusostatic method java.util.Collections.emptyMap()

  1. Eles são mais concisos porque você não precisa digitar explicitamente o tipo genérico da coleção - geralmente é apenas inferido a partir do contexto da chamada do método.

  2. Eles são mais eficientes porque não se preocupam em criar novos objetos; eles apenas reutilizam um objeto vazio e imutável existente. Esse efeito geralmente é muito pequeno, mas ocasionalmente (bem, raramente) é importante.

subodh
fonte
2

Por que eu iria querer uma coleção vazia imutável? Qual é o ponto?

Pela mesma razão que você usaria Collections.unmodifiableMap()em algum momento. Você deseja retornar uma instância de Map que lança uma exceção se o usuário tentar modificá-la. É apenas um caso especial: o mapa vazio.

Ryan Stewart
fonte
1

Por que eu iria querer uma coleção vazia imutável? Qual é o ponto?

Pelas mesmas razões pelas quais você pode querer objetos imutáveis. Principalmente porque você pode dormir em segurança à noite, sabendo que vários encadeamentos podem acessar a mesma instância de um objeto e que todos estarão vendo os mesmos valores. Não ter itens em uma coleção ainda é um valor válido, que você deseja manter.

vegemite4me
fonte