Java: cómo crear una nueva entrada (clave, valor)

291

Me gustaría crear un nuevo elemento que de igual forma a Util.Map.Entryque contendrá la estructura key, value.

El problema es que no puedo crear una instancia Map.Entryporque es una interfaz.

¿Alguien sabe cómo crear un nuevo objeto clave / valor genérico para Map.Entry?

hombre araña
fuente

Respuestas:

79

Puede implementar la Map.Entry<K, V>interfaz usted mismo:

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

Y luego úsalo:

Map.Entry<String, Object> entry = new MyEntry<String, Object>("Hello", 123);
System.out.println(entry.getKey());
System.out.println(entry.getValue());
Jesper
fuente
117
por supuesto, me preguntaba si no hay una solución lista para usar. Estoy tratando de hacer que mi código sea lo más estándar posible ...
Spiderman
1
¿Puede explicar por qué algunas implementaciones de Map tienen la clave como final (como en HashMap, ConcurrentHashMap), pero no en algunas otras implementaciones como TreeMap, WeakHashMap?
AKS
77
El código dado no es completamente correcto, ya que no anula iguales y hashCode, lo cual es requerido por la interfaz Map.Entry
John Tang Boyland
A partir de Java 7 Update 80, he implementado anteriormente y funcionó ( pastebin ). No se anularon otros métodos.
plata
807

Hay public static class AbstractMap.SimpleEntry<K,V>. No permita que la Abstractparte del nombre lo engañe: de hecho, NO es una abstractclase (pero su nivel superior sí lo AbstractMapes).

El hecho de que sea una staticclase anidada significa que NO necesita una AbstractMapinstancia de cierre para crear una instancia, por lo que algo como esto se compila bien:

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

Como se señaló en otra respuesta, Guava también tiene un staticmétodo de fábrica conveniente Maps.immutableEntryque puede usar.


Tu dijiste:

No puedo usarlo Map.Entryporque aparentemente es un objeto de solo lectura del que no puedo crear instancias nuevasinstanceof

Eso no es del todo exacto. La razón por la que no puede crear una instancia directamente (es decir, con new) es porque es un interface Map.Entry.


Advertencia y propina

Como se señala en la documentación, AbstractMap.SimpleEntryes decir @since 1.6, si está atascado en 5.0, entonces no está disponible para usted.

Para buscar otra clase conocida que implements Map.Entry, de hecho, puede ir directamente al javadoc. Desde la versión Java 6

Mapa de interfaz.

Todas las clases de implementación conocidas :

Lamentablemente, la versión 1.5 no enumera ninguna clase de implementación conocida que pueda usar, por lo que es posible que no haya implementado la suya propia.

poligenelubricantes
fuente
La línea anterior me devuelve un error de compilación (estoy usando Java 5, por cierto) - el mensaje de error es: 'El tipo AbstractMap.SimpleEntry no es visible'
Spiderman
66
Eso es porque AbstractMap.SimpleEntryno era público hasta Java 6, como puede ver en la documentación.
Jesper
OK, así que para resumir la breve discusión (no hay una solución lista para usar en Java 5), ​​debería usar mi propia implementación.
Spiderman
44
+1 por señalar AbstractMap.SimpleEntry. ¡Supongo que aprendes algo nuevo todos los días!
Priidu Neemre
¿Qué quiere decir con encerrar en "una instancia de AbstractMap que encierra". ¿Encierre está inferiendo un término técnico o algo en Java? por favor guíame.
Gráficos C
70

A partir de Java 9, hay un nuevo método de utilidad que permite crear una entrada inmutable que es Map#entry(Object, Object).

Aquí hay un ejemplo simple:

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

Como es inmutable, llamar setValuearrojará un UnsupportedOperationException. Las otras limitaciones son el hecho de que no es serializable y, nullcomo la clave o el valor están prohibidos, si no es aceptable para usted, deberá usarlo AbstractMap.SimpleImmutableEntryo, en su AbstractMap.SimpleEntrylugar.

NB: si su necesidad es crear directamente a Mapcon 0 a hasta 10 pares (clave, valor), puede utilizar los métodos de tipo Map.of(K key1, V value1, ...).

Nicolas Filotto
fuente
53

Prueba Maps.immutableEntry desde Guava

Esto tiene la ventaja de ser compatible con Java 5 (a diferencia de lo AbstractMap.SimpleEntryque requiere Java 6.)

finnw
fuente
34

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

Agregar filas:

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

Obtener filas:

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

Debería imprimir:

2
3
20
30
2
4

Es bueno para definir aristas de estructuras gráficas. Como las que hay entre las neuronas en tu cabeza.

Eric Leschinski
fuente
18

Realmente podrías ir con: Map.Entry<String, String> en= Maps.immutableEntry(key, value);

Juan David Ortega Tapias
fuente
Es útil. github.com/google/guava Guava es un conjunto de bibliotecas principales de Java de Google que incluye nuevos tipos de colección (como multimap y multiset), colecciones inmutables, una biblioteca de gráficos y utilidades para concurrencia, E / S, hash, almacenamiento en caché, ¡primitivas, cadenas y más! Es ampliamente utilizado en la mayoría de los proyectos de Java dentro de Google, y también lo utilizan muchas otras compañías.
Languoguang
13

¿Por qué Map.Entry? Supongo que algo así como un par clave-valor es adecuado para el caso.

Use java.util.AbstractMap.SimpleImmutableEntryojava.util.AbstractMap.SimpleEntry

Tanghao
fuente
6

org.apache.commons.lang3.tuple.Pairimplementa java.util.Map.Entryy también se puede utilizar de forma independiente.

También como otros mencionaron, Guava's com.google.common.collect.Maps.immutableEntry(K, V)hace el truco.

Prefiero Pairpor su Pair.of(L, R)sintaxis fluida .

parxier
fuente
2
¿Puedo sugerir en su ImmutablePairlugar?
beluchin
Realmente me gusta la clase org.apache.commons.lang3.tuple.Pair, ¡es increíble!
Laurens Op 't Zandt
Lo único que no me gusta es que se serializa a izquierda, derecha, clave, valor donde left = key y right = value. Solo 2 valores inútiles adicionales (tal vez) en la cadena serializada.
Vikrant Goel
4

Definí una clase de par genérico que uso todo el tiempo. Es genial. Como beneficio adicional, al definir un método de fábrica estático (Pair.create) solo tengo que escribir los argumentos de tipo la mitad de las veces.

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
fuente
1
Lo siento, publiqué esto antes de leer todos los otros comentarios. Parece que quieres algo que está incluido en la biblioteca estándar ...
Nels Beckman
2
Google Guava señala bien por qué las Pairimplementaciones son malas. Fuente
Ingo Bürk
3

Si está utilizando Clojure, tiene otra opción:

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