Java - Come creare una nuova voce (chiave, valore)


291

Mi piacerebbe creare nuovo elemento che in modo simile a Util.Map.Entryche conterrà la struttura key, value.

Il problema è che non posso creare un'istanza Map.Entryperché è un'interfaccia.

Qualcuno sa come creare un nuovo oggetto chiave / valore generico per Map.Entry?

Risposte:


79

Puoi semplicemente implementare l' Map.Entry<K, V>interfaccia da solo:

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 poi usalo:

Map.Entry<String, Object> entry = new MyEntry<String, Object>("Hello", 123);
System.out.println(entry.getKey());
System.out.println(entry.getValue());

117
ovviamente - mi chiedevo solo se non ci fosse una soluzione pronta all'uso. Sto cercando di rendere il mio codice il più standard possibile ...
Spiderman,

1
Puoi spiegare perché alcune implementazioni di Map hanno la chiave come final (come in HashMap, ConcurrentHashMap), ma non in alcune altre implementazioni come TreeMap, WeakHashMap?
AKS

7
Il codice dato non è completamente corretto poiché non sovrascrive uguali e anche hashCode che è richiesto dall'interfaccia Map.Entry
John Tang Boyland

A partire dall'aggiornamento 80 di Java 7, ho implementato sopra e ha funzionato ( pastebin ). Nessun altro metodo è stato ignorato.
argento,

807

C'è public static class AbstractMap.SimpleEntry<K,V>. Non lasciare che la Abstractparte del nome ti induca in errore: in realtà NON è una abstractclasse (ma il suo livello principale AbstractMapè).

Il fatto che sia una staticclasse nidificata significa che NON è necessaria AbstractMapun'istanza chiusa per istanziarla, quindi qualcosa di simile si compila bene:

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

Come notato in un'altra risposta, Guava ha anche un comodo staticmetodo di fabbrica Maps.immutableEntryche puoi usare.


Tu hai detto:

Non posso usare Map.Entryse stesso perché apparentemente è un oggetto di sola lettura che non posso creare un'istanza di nuovoinstanceof

Non è del tutto esatto. Il motivo per cui non puoi istanziarlo direttamente (cioè con new) è perché è un interface Map.Entry.


Avvertenza e punta

Come indicato nella documentazione, AbstractMap.SimpleEntryè@since 1.6 , quindi se sei bloccato su 5.0, non è disponibile per te.

Per cercare un'altra classe conosciuta che implements Map.Entry, in effetti, puoi andare direttamente al javadoc. Dalla versione Java 6

Interface Map.Entry

Tutte le classi di esecuzione conosciute :

Sfortunatamente la versione 1.5 non elenca nessuna classe di implementazione nota che puoi usare, quindi potresti essere bloccato con l'implementazione della tua.


La riga sopra restituisce un errore di compilazione per me (sto usando Java 5, BTW) - il messaggio di errore è: 'Il tipo AbstractMap.SimpleEntry non è visibile'
Spiderman

6
Questo perché AbstractMap.SimpleEntrynon era pubblico fino a Java 6, come puoi vedere nella documentazione.
Jesper,

OK, quindi per riassumere la breve discussione - non esiste una soluzione pronta all'uso in Java 5 - Dovrei usare la mia propria implementazione.
Spiderman,

4
+1 per sottolineare AbstractMap.SimpleEntry. Immagino che impari qualcosa di nuovo ogni giorno!
Priidu Neemre,

cosa intendi per "racchiudere un'istanza di AbstractMap". Racchiudere significa dedurre un termine tecnico o qualcosa del genere in Java? per favore guidami.
Grafica C

70

A partire da Java 9, esiste un nuovo metodo di utilità che consente di creare una voce immutabile che è Map#entry(Object, Object).

Qui c'è un semplice esempio:

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

Poiché è immutabile, la chiamata setValuegenererà un UnsupportedOperationException. Le altre limitazioni sono il fatto che non è serializzabile e nullcome chiave o valore è proibito, se non è accettabile per te, dovrai usare AbstractMap.SimpleImmutableEntryo AbstractMap.SimpleEntryinvece.

NB: Se hai bisogno di creare direttamente una Mapcoppia da 0 a un massimo di 10 (chiave, valore), puoi invece usare i metodi di tipo Map.of(K key1, V value1, ...).



34

Esempio di AbstractMap.SimpleEntry:

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

Instantiate:

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

Aggiungi righe:

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

Recupera righe:

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

Dovrebbe stampare:

2
3
20
30
2
4

È utile per definire i bordi delle strutture grafiche. Come quelli tra i neuroni nella tua testa.


18

In realtà potresti andare con: Map.Entry<String, String> en= Maps.immutableEntry(key, value);


È utile github.com/google/guava Guava è un insieme di librerie Java di base di Google che include nuovi tipi di raccolte (come multimap e multiset), raccolte immutabili, una biblioteca di grafici e utilità per la concorrenza, I / O, hash, cache, primitive, archi e altro! È ampiamente utilizzato sulla maggior parte dei progetti Java all'interno di Google e ampiamente utilizzato anche da molte altre società.
Languoguang,

13

Perché Map.Entry ? Immagino che qualcosa come una coppia chiave-valore sia adatto al caso.

Usa java.util.AbstractMap.SimpleImmutableEntryojava.util.AbstractMap.SimpleEntry


6

org.apache.commons.lang3.tuple.Pairimplementa java.util.Map.Entrye può anche essere usato autonomamente.

Inoltre, come altri hanno già detto, Guava com.google.common.collect.Maps.immutableEntry(K, V)fa il trucco.

Preferisco Pairper la sua Pair.of(L, R)sintassi fluida .


2
Posso suggerire ImmutablePairinvece?
Beluchin,

Mi piace molto la classe org.apache.commons.lang3.tuple.Pair, è fantastico!
Laurens Op 't Zandt,

L'unica cosa che non mi piace è che viene serializzato su sinistra, destra, chiave, valore dove left = key e right = value. Solo 2 valori inutili (forse) extra nella stringa serializzata.
Vikrant Goel,

4

Ho definito una classe Pair generica che utilizzo sempre. È ottimo. Come bonus, definendo un metodo factory statico (Pair.create) devo solo scrivere gli argomenti di tipo la metà delle volte.

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

}

1
Siamo spiacenti, l'ho pubblicato prima di leggere tutti gli altri commenti. Sembra che tu voglia qualcosa che è incluso nella libreria standard ...
Nels Beckman,

2
Google Guava spiega bene perché le Pairimplementazioni sono una cosa negativa. Fonte
Ingo Bürk,

3

Se stai usando Clojure, hai un'altra opzione:

(defn map-entry
  [k v]
  (clojure.lang.MapEntry/create k v))
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.