Java - Jak utworzyć nowy wpis (klucz, wartość)

291

Chciałbym utworzyć nowy element, który podobnie jak Util.Map.Entryktóry będzie zawierał strukturę key, value.

Problem polega na tym, że nie mogę utworzyć instancji, Map.Entryponieważ jest to interfejs.

Czy ktoś wie, jak utworzyć nowy ogólny obiekt klucz / wartość dla Map.Entry?

Człowiek Pająk
źródło

Odpowiedzi:

79

Możesz po prostu Map.Entry<K, V>samodzielnie zaimplementować interfejs:

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

A następnie użyj go:

Map.Entry<String, Object> entry = new MyEntry<String, Object>("Hello", 123);
System.out.println(entry.getKey());
System.out.println(entry.getValue());
Jesper
źródło
117
oczywiście - po prostu zastanawiałem się, czy nie ma gotowego rozwiązania. Staram się, aby mój kod był jak najbardziej standardowy ...
Spiderman
1
Czy możesz wyjaśnić, dlaczego niektóre implementacje Map mają klucz jako ostateczny (jak w HashMap, ConcurrentHashMap), ale nie w innych implementacjach, takich jak TreeMap, WeakHashMap?
AKS,
7
Podany kod nie jest w pełni poprawny, ponieważ nie zastępuje równości i hashCode, który jest wymagany przez interfejs Map.Entry
John Tang Boyland
Począwszy od wersji Java 7 Update 80, zaimplementowałem powyżej i działało ( pastebin ). Żadne inne metody nie zostały zastąpione.
srebrny
806

Jest public static class AbstractMap.SimpleEntry<K,V>. Nie daj się Abstractzwieść części nazwy: w rzeczywistości NIE jest to abstractklasa (ale jej najwyższy poziomAbstractMap to).

Fakt, że jest to staticklasa zagnieżdżona, oznacza, że NIE potrzebujesz otaczającej AbstractMapinstancji, aby utworzyć jej instancję, więc coś takiego wygląda dobrze:

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

Jak zauważono w innej odpowiedzi, Guava ma również wygodną staticmetodę fabryczną Maps.immutableEntry, z której można skorzystać.


Powiedziałeś:

Nie mogę użyć Map.Entrysiebie, ponieważ najwyraźniej jest to obiekt tylko do odczytu, którego nie mogę utworzyćinstanceof

To nie do końca dokładne. Powodem, dla którego nie można utworzyć go bezpośrednio (tj. Za pomocą new) jest to, że jest to plik interface Map.Entry.


Zastrzeżenie i wskazówka

Jak zauważono w dokumentacji, AbstractMap.SimpleEntryjest@since 1.6 , więc jeśli utkniesz do 5,0, to nie jest dostępne.

Aby poszukać innej znanej klasy implements Map.Entry, możesz przejść bezpośrednio do javadoc. Z wersji Java 6

Interfejs Mapa. ​​Wejście

Wszystkie znane klasy wdrożeniowe :

Niestety wersja 1.5 nie zawiera żadnej znanej klasy implementacyjnej, której możesz użyć, więc być może utknąłeś przy implementacji własnej.

środki smarujące wielotlenowe
źródło
Powyższa linia zwraca błąd kompilacji dla mnie (używam java 5, BTW) - komunikat o błędzie to: „Typ AbstractMap.SimpleEntry nie jest widoczny”
Spiderman
6
To dlatego, że AbstractMap.SimpleEntrynie było publiczne aż do Java 6, jak widać w dokumentacji.
Jesper
OK, podsumowując krótką dyskusję - nie ma gotowego rozwiązania w Javie 5 - powinienem użyć własnej implementacji.
Spiderman
4
+1 za wskazanie AbstractMap.SimpleEntry. Chyba uczysz się czegoś nowego każdego dnia!
Priidu Neemre
co rozumiesz przez „załączenie instancji AbstractMap”. Czy Enclosing wnioskuje o języku technicznym lub czymś w języku Java? proszę, prowadź mnie.
grafika C
70

Począwszy od Java 9, pojawiła się nowa metoda narzędziowa, która pozwala stworzyć niezmienny wpis, którym jest Map#entry(Object, Object).

Oto prosty przykład:

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

Jak to jest niezmienne, wołanie setValue rzuci an UnsupportedOperationException. Inne ograniczenia polegają na tym, że nie można go przekształcić do nullpostaci szeregowej, a ponieważ klucz lub wartość są zabronione, jeśli nie jest to dla Ciebie do przyjęcia, musisz użyć AbstractMap.SimpleImmutableEntrylub AbstractMap.SimpleEntryzamiast tego.

Uwaga: jeśli potrzebujesz bezpośrednio utworzyćMap od 0 do 10 par (klucz, wartość), możesz zamiast tego użyć metod pisania Map.of(K key1, V value1, ...).

Nicolas Filotto
źródło
53

Spróbuj Maps.immutableEntry z Guava

Ma to tę zaletę, że jest kompatybilny z Javą 5 (w przeciwieństwie do AbstractMap.SimpleEntrywymaganej Java 6.)

finnw
źródło
34

Przykład AbstractMap.SimpleEntry:

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

Utwórz wystąpienie:

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

Dodaj wiersze:

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

Pobierz wiersze:

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

Powinien wydrukować:

2
3
20
30
2
4

Jest dobry do definiowania krawędzi struktur graficznych. Jak te między neuronami w twojej głowie.

Eric Leschinski
źródło
18

Możesz faktycznie użyć: Map.Entry<String, String> en= Maps.immutableEntry(key, value);

Juan David Ortega Tapias
źródło
To jest użyteczne. github.com/google/guava Guava to zestaw podstawowych bibliotek Java firmy Google, który zawiera nowe typy kolekcji (takie jak multimap i multiset), niezmienne kolekcje, bibliotekę wykresów oraz narzędzia do współbieżności, operacji we / wy, mieszania, buforowania, prymitywy, łańcuchy i wiele więcej! Jest szeroko stosowany w większości projektów Java w Google, a także w wielu innych firmach.
Languoguang
13

Dlaczego Map.Entry ? Myślę, że coś w rodzaju pary klucz-wartość pasuje do tego przypadku.

Posługiwać się java.util.AbstractMap.SimpleImmutableEntry lubjava.util.AbstractMap.SimpleEntry

Tanghao
źródło
6

org.apache.commons.lang3.tuple.Pair narzędzia java.util.Map.Entry i może być również używany samodzielnie.

Podobnie jak inni wspominali o Guava com.google.common.collect.Maps.immutableEntry(K, V) robi lewę.

Wolę Pairze względu na płynną Pair.of(L, R)składnię.

parxier
źródło
2
Czy ImmutablePairzamiast tego mogę zasugerować ?
beluchin
Naprawdę lubię klasę org.apache.commons.lang3.tuple.Pair, jest niesamowita!
Laurens Op 't Zandt
Jedyne, co mi się nie podoba, to to, że serializuje się na lewo, prawo, klucz, wartość gdzie left = klucz i prawo = wartość. Tylko 2 dodatkowe bezużyteczne (być może) wartości w serializowanym ciągu.
Vikrant Goel
4

Zdefiniowałem ogólną klasę Pair, z której cały czas korzystam. Wspaniale. Jako bonus, definiując statyczną metodę fabryczną (Pair.create), muszę tylko pisać argumenty typu o połowę częściej.

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
źródło
1
Przepraszam, opublikowałem to przed przeczytaniem wszystkich innych komentarzy. Wygląda na to, że chcesz czegoś, co jest zawarte w standardowej bibliotece ...
Nels Beckman,
2
Google Guava dobrze rozumie, dlaczego Pairwdrożenia są złe. Źródło
Ingo Bürk
3

Jeśli używasz Clojure, masz inną opcję:

(defn map-entry
  [k v]
  (clojure.lang.MapEntry/create k v))
Radon Rosborough
źródło