Java - Comment créer une nouvelle entrée (clé, valeur)

291

Je voudrais créer un nouvel élément qui, comme Util.Map.Entrycelui-ci, contiendra la structure key,value .

Le problème est que je ne peux pas instancier un Map.Entry car c'est une interface.

Quelqu'un sait-il comment créer un nouvel objet clé / valeur générique pour Map.Entry?

Homme araignée
la source

Réponses:

79

Vous pouvez simplement implémenter l' Map.Entry<K, V>interface vous-même:

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

Et puis utilisez-le:

Map.Entry<String, Object> entry = new MyEntry<String, Object>("Hello", 123);
System.out.println(entry.getKey());
System.out.println(entry.getValue());
Jesper
la source
117
bien sûr - je me demandais simplement s'il n'y avait pas de solution prête à l'emploi. J'essaie de rendre mon code aussi standard que possible ...
Spiderman
1
Pouvez-vous expliquer pourquoi certaines implémentations de Map ont une clé finale (comme dans HashMap, ConcurrentHashMap), mais pas dans d'autres implémentations comme TreeMap, WeakHashMap?
AKS
7
Le code donné n'est pas entièrement correct car il ne remplace pas égal et hashCode aussi, ce qui est requis par l'interface Map.Entry
John Tang Boyland
Depuis Java 7 Update 80, j'ai implémenté ci-dessus et cela a fonctionné ( pastebin ). Aucune autre méthode n'a été remplacée.
argent
807

Voilà public static class AbstractMap.SimpleEntry<K,V>. Ne laissez pas la Abstractpartie du nom vous induire en erreur: ce n'est en fait PAS une abstractclasse (mais son niveau supérieurAbstractMap est).

Le fait qu'il s'agisse d'une staticclasse imbriquée signifie que vous N'AVEZ PAS besoin d'une AbstractMapinstance englobante pour l'instancier, donc quelque chose comme ça se compile bien:

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

Comme indiqué dans une autre réponse, Guava a également une staticméthode d'usine pratique Maps.immutableEntryque vous pouvez utiliser.


Tu as dit:

Je ne peux pas Map.Entrym'utiliser car apparemment c'est un objet en lecture seule que je ne peux pas instancier de nouveauinstanceof

Ce n'est pas tout à fait exact. La raison pour laquelle vous ne pouvez pas l'instancier directement (c'est-à-dire avec new) est que c'est un interface Map.Entry.


Avertissement et conseil

Comme il est indiqué dans la documentation, AbstractMap.SimpleEntryest@since 1.6 , donc si vous êtes bloqué sur 5.0, alors il n'est pas disponible pour vous.

Pour rechercher une autre classe connue qui implements Map.Entry, vous pouvez en fait aller directement au javadoc. Depuis la version Java 6

Carte d'interface.

Toutes les classes d'implémentation connues :

Malheureusement, la version 1.5 ne répertorie aucune classe d'implémentation connue que vous pouvez utiliser, vous pouvez donc être bloqué par l'implémentation de la vôtre.

polygénelubrifiants
la source
La ligne ci-dessus renvoie une erreur de compilation pour moi (j'utilise java 5, BTW) - le message d'erreur est: "Le type AbstractMap.SimpleEntry n'est pas visible"
Spiderman
6
C'est parce que ce AbstractMap.SimpleEntryn'était pas public avant Java 6, comme vous pouvez le voir dans la documentation.
Jesper
OK, donc pour résumer la brève discussion - il n'y a pas de solution prête à l'emploi dans Java 5 - je devrais utiliser ma propre implémentation.
Spiderman
4
+1 pour avoir souligné AbstractMap.SimpleEntry. Je suppose que vous apprenez quelque chose de nouveau chaque jour!
Priidu Neemre
que voulez-vous dire par enfermer dans "une instance AbstractMap englobante". Est-ce que Enclosing infère un terme technique ou quelque chose en java? Guidez-moi s'il-vous-plaît.
C graphics
70

A partir de Java 9, il existe une nouvelle méthode utilitaire permettant de créer une entrée immuable qui l'est Map#entry(Object, Object).

Voici un exemple simple:

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

Comme il est immuable, l'appel setValuelancera un UnsupportedOperationException. Les autres limitations sont le fait qu'il n'est pas sérialisable et nullque la clé ou la valeur est interdite, si elle n'est pas acceptable pour vous, vous devrez utiliser AbstractMap.SimpleImmutableEntryou à la AbstractMap.SimpleEntryplace.

NB: Si votre besoin est de créer directement un Mapavec 0 à 10 paires (clé, valeur), vous pouvez utiliser à la place les méthodes de type Map.of(K key1, V value1, ...).

Nicolas Filotto
la source
53

Essayez Maps.immutableEntry from Guava

Cela a l'avantage d'être compatible avec Java 5 (contrairement à AbstractMap.SimpleEntryce qui nécessite Java 6.)

finnw
la source
34

Exemple de AbstractMap.SimpleEntry:

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

Instancier:

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

Ajouter des lignes:

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

Récupérer les lignes:

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

Devrait imprimer:

2
3
20
30
2
4

C'est bon pour définir les bords des structures de graphe. Comme ceux entre les neurones de votre tête.

Eric Leschinski
la source
18

Vous pourriez en fait aller avec: Map.Entry<String, String> en= Maps.immutableEntry(key, value);

Juan David Ortega Tapias
la source
C'est utile. github.com/google/guava Guava est un ensemble de bibliothèques Java de base de Google qui comprend de nouveaux types de collections (telles que multimap et multiset), des collections immuables, une bibliothèque de graphiques et des utilitaires pour la concurrence, les E / S, le hachage, la mise en cache, primitives, chaînes et plus encore! Il est largement utilisé sur la plupart des projets Java de Google et largement utilisé par de nombreuses autres sociétés.
Languoguang
13

Pourquoi Map.Entry ? Je suppose que quelque chose comme une paire clé-valeur convient à l'affaire.

Utilisez java.util.AbstractMap.SimpleImmutableEntryoujava.util.AbstractMap.SimpleEntry

tanghao
la source
6

org.apache.commons.lang3.tuple.Pair met en oeuvre java.util.Map.Entry et peut également être utilisé de manière autonome.

Aussi, comme d'autres l'ont mentionné, la goyave com.google.common.collect.Maps.immutableEntry(K, V) fait l'affaire.

Je préfère Pairsa Pair.of(L, R)syntaxe fluide .

parxier
la source
2
Puis-je suggérer à la ImmutablePairplace?
beluchin
J'aime vraiment la classe org.apache.commons.lang3.tuple.Pair, c'est génial!
Laurens Op 't Zandt
La seule chose que je n'aime pas, c'est qu'il est sérialisé à gauche, à droite, à clé, à valeur où gauche = clé et droite = valeur. Juste 2 valeurs inutiles supplémentaires (peut-être) dans la chaîne sérialisée.
Vikrant Goel,
4

J'ai défini une classe Pair générique que j'utilise tout le temps. C'est bien. En prime, en définissant une méthode d'usine statique (Pair.create), je n'ai qu'à écrire les arguments de type deux fois moins souvent.

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
la source
1
Désolé, j'ai posté ceci avant de lire tous les autres commentaires. On dirait que vous voulez quelque chose qui est inclus dans la bibliothèque standard ...
Nels Beckman
2
Google Guava explique pourquoi les Pairimplémentations sont une mauvaise chose. Source
Ingo Bürk
3

Si vous utilisez Clojure, vous avez une autre option:

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