Java - Como criar uma nova entrada (chave, valor)

291

Eu gostaria de criar um novo item que de forma semelhante ao Util.Map.Entryque conterá a estrutura key, value.

O problema é que não consigo instanciar um Map.Entryporque é uma interface.

Alguém sabe como criar um novo objeto de chave / valor genérico para o Map.Entry?

Homem Aranha
fonte

Respostas:

79

Você pode simplesmente implementar o Map.Entry<K, V> interface:

import java.util.Map;

final class MyEntry<K, V> implements Map.Entry<K, V> {
    private final K key;
    private V value;

    public MyEntry(K key, V value) {
        this.key = key;
        this.value = value;
    }

    @Override
    public K getKey() {
        return key;
    }

    @Override
    public V getValue() {
        return value;
    }

    @Override
    public V setValue(V value) {
        V old = this.value;
        this.value = value;
        return old;
    }
}

E então use-o:

Map.Entry<String, Object> entry = new MyEntry<String, Object>("Hello", 123);
System.out.println(entry.getKey());
System.out.println(entry.getValue());
Jesper
fonte
117
é claro - eu me perguntei se não havia uma solução pronta para uso. Eu estou tentando fazer o meu código como padrão possível ...
Spiderman
1
Você pode explicar por que algumas implementações do Map têm chave como final (como no HashMap, ConcurrentHashMap), mas não em outras implementações como o TreeMap, o WeakHashMap?
AKS 29/08
7
O código dado não é totalmente correta, uma vez que não sobrescrever equals e hashCode também que é exigido por Map.Entry Interface
John Tang Boyland
No Java 7, atualização 80, eu implementei acima e funcionou ( pastebin ). Nenhum outro método foi substituído.
silver
807

Está aí public static class AbstractMap.SimpleEntry<K,V>. Não deixe que a Abstractparte do nome o engane: na verdade, NÃO é uma abstractclasse (mas AbstractMapé de nível superior ).

O fato de ser uma staticclasse aninhada significa que você NÃO precisa de uma AbstractMapinstância anexa para instancia-la, portanto, algo assim compila bem:

Map.Entry<String,Integer> entry =
    new AbstractMap.SimpleEntry<String, Integer>("exmpleString", 42);

Conforme observado em outra resposta, o Guava também possui um staticmétodo conveniente de fábrica Maps.immutableEntryque você pode usar.


Você disse:

Não consigo usar Map.Entry-me porque, aparentemente, é um objeto somente leitura que não consigo instanciar novosinstanceof

Isso não é totalmente preciso. A razão pela qual você não pode instanciar diretamente (isto é, com new) é porque é um interface Map.Entry.


Advertência e dica

Conforme observado na documentação, AbstractMap.SimpleEntryé@since 1.6 , portanto, se você estiver preso ao 5.0, ele não estará disponível para você.

Para procurar outra classe conhecida que implements Map.Entry, na verdade, você pode ir diretamente para o javadoc. A partir da versão Java 6

Interface Map.Entry

Todas as classes de implementação conhecidas :

Infelizmente, a versão 1.5 não lista nenhuma classe de implementação conhecida que você possa usar; portanto, você pode ter dificuldades em implementar sua própria.

poligenelubricants
fonte
O erro acima da linha de retornos compilação para mim (estou usando java 5, BTW) - mensagem de erro é: 'O tipo AbstractMap.SimpleEntry não é visível'
Spiderman
6
Isso porque AbstractMap.SimpleEntrynão era público até o Java 6, como você pode ver na documentação.
Jesper
OK, então, para resumir a breve discussão - não há uma solução pronta para uso em Java 5 - devo usar minha própria implementação.
Spiderman
4
+1 para apontar AbstractMap.SimpleEntry. Eu acho que você aprende algo novo todos os dias!
Priidu Neemre
o que você quer dizer com encerrando em "uma instância AbstractMap anexa". O Enclosing está inferindo um termo técnico ou algo em java? Por favor me guie.
C graphics
70

A partir do Java 9, existe um novo método utilitário que permite criar uma entrada imutável que éMap#entry(Object, Object) .

Aqui está um exemplo simples:

Entry<String, String> entry = Map.entry("foo", "bar");

Como é imutável, a chamada setValuelançará um UnsupportedOperationException. As outras limitações são o fato de não ser serializável e, nullcomo a chave ou o valor é proibido, se não for aceitável para você, será necessário usar AbstractMap.SimpleImmutableEntryouAbstractMap.SimpleEntry .

Nota: se você precisar criar diretamente um Mapcom 0 a até 10 pares (chave, valor), você poderá usar os métodos do tipo Map.of(K key1, V value1, ...).

Nicolas Filotto
fonte
53

Experimente Maps.immutableEntry de Guava

Isso tem a vantagem de ser compatível com o Java 5 (diferente do AbstractMap.SimpleEntryque requer o Java 6.)

finnw
fonte
34

Exemplo de AbstractMap.SimpleEntry:

import java.util.Map; 
import java.util.AbstractMap;
import java.util.AbstractMap.SimpleEntry;

Instanciar:

ArrayList<Map.Entry<Integer, Integer>> arr = 
    new ArrayList<Map.Entry<Integer, Integer>>();

Adicione linhas:

arr.add(new AbstractMap.SimpleEntry(2, 3));
arr.add(new AbstractMap.SimpleEntry(20, 30));
arr.add(new AbstractMap.SimpleEntry(2, 4));

Buscar linhas:

System.out.println(arr.get(0).getKey());
System.out.println(arr.get(0).getValue());
System.out.println(arr.get(1).getKey());
System.out.println(arr.get(1).getValue());
System.out.println(arr.get(2).getKey());
System.out.println(arr.get(2).getValue());

Deve imprimir:

2
3
20
30
2
4

É bom para definir arestas de estruturas gráficas. Como aqueles entre neurônios em sua cabeça.

Eric Leschinski
fonte
18

Você pode realmente ir com: Map.Entry<String, String> en= Maps.immutableEntry(key, value);

Juan David Ortega Tapias
fonte
É útil. O github.com/google/guava Guava é um conjunto de principais bibliotecas Java do Google que inclui novos tipos de coleções (como multimap e multiset), coleções imutáveis, uma biblioteca de gráficos e utilitários para simultaneidade, E / S, hash, cache, primitivas, strings e muito mais! É amplamente utilizado na maioria dos projetos Java no Google e amplamente utilizado por muitas outras empresas.
Languoguang
13

Por quê Map.Entry ? Eu acho que algo como um par de valores-chave é adequado para o caso.

Use java.util.AbstractMap.SimpleImmutableEntryoujava.util.AbstractMap.SimpleEntry

tanghao
fonte
6

org.apache.commons.lang3.tuple.Pairimplementa java.util.Map.Entrye também pode ser usado de forma independente.

Também como outros mencionaram a goiaba com.google.common.collect.Maps.immutableEntry(K, V) faz o truque.

Eu prefiro Pairpor sua Pair.of(L, R)sintaxe fluente .

parxier
fonte
2
Em ImmutablePairvez disso , posso sugerir ?
beluchin
Eu realmente gosto da classe org.apache.commons.lang3.tuple.Pair, é incrível!
Laurens Op 't Zandt
A única coisa que eu não gosto é que ele é serializado para esquerda, direita, chave, valor onde left = key e right = value. Apenas 2 valores extras inúteis (talvez) na string serializada.
Vikrant Goel
4

Eu defini uma classe Pair genérica que eu uso o tempo todo. É ótimo. Como um bônus, definindo um método estático de fábrica (Pair.create), eu só tenho que escrever os argumentos de tipo pela metade com a mesma frequência.

public class Pair<A, B> {

    private A component1;
    private B component2;

    public Pair() {
            super();
    }

    public Pair(A component1, B component2) {
            this.component1 = component1;
            this.component2 = component2;
    }

    public A fst() {
            return component1;
    }

    public void setComponent1(A component1) {
            this.component1 = component1;
    }

    public B snd() {
            return component2;
    }

    public void setComponent2(B component2) {
            this.component2 = component2;
    }

    @Override
    public String toString() {
            return "<" + component1 + "," + component2 + ">";
    }

    @Override
    public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result
                            + ((component1 == null) ? 0 : component1.hashCode());
            result = prime * result
                            + ((component2 == null) ? 0 : component2.hashCode());
            return result;
    }

    @Override
    public boolean equals(Object obj) {
            if (this == obj)
                    return true;
            if (obj == null)
                    return false;
            if (getClass() != obj.getClass())
                    return false;
            final Pair<?, ?> other = (Pair<?, ?>) obj;
            if (component1 == null) {
                    if (other.component1 != null)
                            return false;
            } else if (!component1.equals(other.component1))
                    return false;
            if (component2 == null) {
                    if (other.component2 != null)
                            return false;
            } else if (!component2.equals(other.component2))
                    return false;
            return true;
    }

    public static <A, B> Pair<A, B> create(A component1, B component2) {
            return new Pair<A, B>(component1, component2);
    }

}
Nels Beckman
fonte
1
Desculpe, eu postei isso antes de ler todos os outros comentários. Parece que você quer algo que está incluído no lib padrão ...
Nels Beckman
2
O Google Guava mostra bem por que as Pairimplementações são ruins. Fonte
Ingo Bürk
3

Se você estiver usando o Clojure, você tem outra opção:

(defn map-entry
  [k v]
  (clojure.lang.MapEntry/create k v))
Radon Rosborough
fonte