Existe alguma maneira de inicializar um Java HashMap como este?
Map<String,String> test =
new HashMap<String, String>{"test":"test","test":"test"};
Qual seria a sintaxe correta? Eu não encontrei nada sobre isso. Isso é possível? Estou procurando a maneira mais curta / rápida de colocar alguns valores "finais / estáticos" em um mapa que nunca mudam e são conhecidos antecipadamente ao criar o Mapa.
Respostas:
Todas versões
Caso você precise de apenas uma entrada: Existe
Collections.singletonMap("key", "value")
.Para Java Versão 9 ou superior:
Sim, isso é possível agora. No Java 9, foram adicionados alguns métodos de fábrica que simplificam a criação de mapas:
No exemplo acima, tanto
test
etest2
será o mesmo, apenas com maneiras diferentes de expressar o Mapa. OMap.of
método é definido para até dez elementos no mapa, enquanto oMap.ofEntries
método não terá esse limite.Observe que, nesse caso, o mapa resultante será um mapa imutável. Se você deseja que o mapa seja mutável, você pode copiá-lo novamente, por exemplo, usando
mutableMap = new HashMap<>(Map.of("a", "b"));
(Veja também JEP 269 e Javadoc )
Para até Java Versão 8:
Não, você precisará adicionar todos os elementos manualmente. Você pode usar um inicializador em uma subclasse anônima para tornar a sintaxe um pouco mais curta:
No entanto, a subclasse anônima pode introduzir comportamento indesejado em alguns casos. Isso inclui, por exemplo:
O uso de uma função para inicialização também permitirá gerar um mapa em um inicializador, mas evita efeitos colaterais desagradáveis:
fonte
Collections.singletonMap()
:)entry
documentado?Essa é uma maneira.
No entanto, você deve ter cuidado e entender o código acima (ele cria uma nova classe que herda do HashMap). Portanto, você deve ler mais aqui: http://www.c2.com/cgi/wiki?DoubleBraceInitialization , ou simplesmente usar o Guava:
fonte
Se você permitir bibliotecas de terceiros, poderá usar o ImmutableMap do Guava para obter uma brevidade literal:
Isso funciona para até 5 pares de chave / valor , caso contrário, você pode usar seu construtor :
fonte
Não existe uma maneira direta de fazer isso - o Java não possui literais de mapa (ainda - acho que eles foram propostos para o Java 8).
Algumas pessoas assim:
Isso cria uma subclasse anônima do HashMap, cujo inicializador de instância coloca esses valores. (A propósito, um mapa não pode conter o dobro do mesmo valor, seu segundo put substituirá o primeiro. Usarei valores diferentes para os próximos exemplos.)
A maneira normal seria esta (para uma variável local):
Se o seu
test
mapa for uma variável de instância, coloque a inicialização em um construtor ou inicializador de instância:Se o seu
test
mapa for uma variável de classe, coloque a inicialização em um inicializador estático:Se você deseja que seu mapa nunca mude, após a inicialização, envolva seu mapa
Collections.unmodifiableMap(...)
. Você também pode fazer isso em um inicializador estático:(Não tenho certeza se agora você pode fazer a
test
final ... experimente e relate aqui.)fonte
fonte
HashMap
nessa subclasse. Isso só funciona se você realmente os fornecer. (Com um novo HashMap (vazio), os argumentos de tipo não são relevantes.)Uma alternativa, usando classes e varargs Java 7 simples: crie uma classe
HashMapBuilder
com este método:Use o método como este:
fonte
tl; dr
Use
Map.of…
métodos no Java 9 e posterior.Map.of
O Java 9 adicionou uma série de
Map.of
métodos estáticos para fazer exatamente o que você deseja: Instancie um imutávelMap
usando a sintaxe literal .O mapa (uma coleção de entradas) é imutável, portanto você não pode adicionar ou remover entradas após instanciar. Além disso, a chave e o valor de cada entrada são imutáveis, não podem ser alterados. Consulte o Javadoc para outras regras, como NULLs não permitidos, chaves duplicadas não permitidas e a ordem de iteração dos mapeamentos é arbitrária.
Vejamos esses métodos, usando alguns dados de amostra para um mapa do dia da semana para uma pessoa que esperamos que funcione nesse dia.
Map.of()
Map.of
cria um vazioMap
. Não modificável, então você não pode adicionar entradas. Aqui está um exemplo desse mapa, vazio sem entradas.Map.of( … )
Map.of( k , v , k , v , …)
Existem vários métodos que levam de 1 a 10 pares de valores-chave. Aqui está um exemplo de duas entradas.Map.ofEntries( … )
Map.ofEntries( Map.Entry , … )
leva qualquer número de objetos implementando aMap.Entry
interface. O Java agrupa duas classes implementando essa interface, uma mutável e a outra imutável:AbstractMap.SimpleEntry
,AbstractMap.SimpleImmutableEntry
. Mas não precisamos especificar uma classe concreta. Nós apenas precisamos chamarMap.entry( k , v )
método, passar nossa chave e nosso valor e retornar um objeto de umaMap.Entry
interface de implementação de alguma classe .Map.copyOf
O Java 10 adicionou o método
Map.copyOf
. Passe um mapa existente, receba de volta uma cópia imutável desse mapa.Notas
Observe que a ordem do iterador dos mapas produzidos via não
Map.of
é garantida. As entradas têm uma ordem arbitrária. Não escreva código com base no pedido visto, pois a documentação avisa que o pedido está sujeito a alterações.Observe que todos esses
Map.of…
métodos retornam umMap
de uma classe não especificada . A classe concreta subjacente pode até variar de uma versão do Java para outra. Esse anonimato permite que o Java escolha entre várias implementações, o que for melhor para seus dados específicos. Por exemplo, se suas chaves vierem de uma enumeração , o Java pode usar umaEnumMap
sob as cobertas.fonte
Você poderia criar seu próprio
Map.of
método (que está disponível apenas no Java 9 e superior) facilmente de duas maneiras fáceisFaça com uma quantidade definida de parâmetros
Exemplo
Faça usando uma lista
Você também pode fazer isso usando uma lista, em vez de criar muitos métodos para um determinado conjunto de parâmetros.
Exemplo
Nota Não é recomendável usar isso para tudo, pois isso cria uma classe anônima toda vez que você o usa.
fonte
JAVA 8
No java 8 simples, você também tem a possibilidade de usar
Streams/Collectors
para fazer o trabalho.Isso tem a vantagem de não criar uma classe anônima.
Observe que as importações são:
Obviamente, como observado em outras respostas, no java 9 em diante, você tem maneiras mais simples de fazer o mesmo.
fonte
Infelizmente, o uso de varargs se o tipo de chaves e valores não for o mesmo não é muito razoável, pois você precisaria usar
Object...
e perder completamente a segurança do tipo. Se você sempre deseja criar, por exemploMap<String, String>
, a , é claro que atoMap(String... args)
seria possível, mas não muito bonita, pois seria fácil misturar chaves e valores, e um número ímpar de argumentos seria inválido.Você pode criar uma subclasse de HashMap que tenha um método encadeado como
e use-o como
new ChainableMap<String, Object>().set("a", 1).set("b", "foo")
Outra abordagem é usar o padrão do construtor comum:
e use-o como
new MapBuilder<String, Object>().put("a", 1).put("b", "foo").build();
No entanto, a solução que usei de vez em quando utiliza varargs e a
Pair
classe:Map<String, Object> map = Maps.of(Pair.create("a", 1), Pair.create("b", "foo");
A verbosidade de
Pair.create()
me incomoda um pouco, mas isso funciona muito bem. Se você não se importa com importações estáticas, é claro que você pode criar um auxiliar:Map<String, Object> map = Maps.of(p("a", 1), p("b", "foo");
(Em vez de
Pair
se imaginar usandoMap.Entry
, mas como é uma interface, é necessária uma classe de implementação e / ou um método auxiliar de fábrica. Também não é imutável e contém outra lógica que não é útil para esta tarefa.)fonte
Você pode usar Streams In Java 8 (este é o exemplo de Set):
Ref: https://www.baeldung.com/java-double-brace-initialization
fonte
Se você precisar colocar apenas um par de valores-chave, poderá usar Collections.singletonMap (key, value);
fonte