Java - Как создать новую запись (ключ, значение)

291

Я хотел бы создать новый элемент , который так же , Util.Map.Entryкоторая будет содержать структуру key, value.

Проблема в том, что я не могу создать экземпляр, Map.Entryпотому что это интерфейс.

Кто-нибудь знает, как создать новый объект общего ключа / значения для Map.Entry?

Человек-паук
источник

Ответы:

79

Вы можете просто реализовать Map.Entry<K, V>интерфейс самостоятельно:

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

И затем используйте это:

Map.Entry<String, Object> entry = new MyEntry<String, Object>("Hello", 123);
System.out.println(entry.getKey());
System.out.println(entry.getValue());
Jesper
источник
117
конечно - я просто удивился, если нет готового решения для этого. Я пытаюсь сделать свой код как можно более стандартным ...
Человек-паук
1
Не могли бы вы объяснить, почему в некоторых реализациях Map ключ имеет конечный (как в HashMap, ConcurrentHashMap), а не в некоторых других реализациях, таких как TreeMap, WeakHashMap?
AKS
7
Данный код не является полностью корректным, так как он не переопределяет equals и hashCode, что требуется для интерфейса Map.Entry
Джон Тан Бойленд,
Начиная с Java 7 Update 80, я реализовал выше, и он работал ( pastebin ). Другие методы не были отменены.
серебро
807

Там же public static class AbstractMap.SimpleEntry<K,V>. Не позволяйте Abstractчасти имени вводить вас в заблуждение: это на самом деле НЕabstract класса (но его верхний уровеньAbstractMap является).

Тот факт, что это staticвложенный класс, означает, что вы НЕ нужен включающий AbstractMapэкземпляр для его создания, поэтому что-то вроде этого компилируется нормально:

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

Как отмечается в другом ответе, в Guava также есть удобный staticфабричный метод, Maps.immutableEntryкоторый вы можете использовать.


Ты сказал:

Я не могу использовать Map.Entryсебя, потому что, очевидно, это объект только для чтения, который я не могу создать новыйinstanceof

Это не совсем точно. Причина, по которой вы не можете создать экземпляр непосредственно (то есть с помощью new), заключается в том, что это interface Map.Entry.


Будьте осторожны

Как отмечено в документации, AbstractMap.SimpleEntryэто@since 1.6 , поэтому, если вы застряли на 5.0, то он вам недоступен.

Чтобы найти другой известный класс implements Map.Entry, вы можете перейти непосредственно к Javadoc. С версии Java 6

Интерфейс Map.Entry

Все известные классы реализации :

К сожалению, версия 1.5 не содержит ни одного известного класса реализации, который вы можете использовать, так что вы, возможно, застряли в реализации своего собственного.

polygenelubricants
источник
Приведенная выше строка возвращает ошибку компиляции для меня (я использую Java 5, BTW) - сообщение об ошибке: «Тип AbstractMap.SimpleEntry не виден»
Человек-паук
6
Это потому, что AbstractMap.SimpleEntryне было общедоступным до Java 6, как вы можете видеть в документации.
Джеспер
Итак, подведем итог краткому обсуждению - в Java 5 нет готового решения для этого - я должен использовать свою собственную реализацию для него.
Человек-паук
4
+1 за указание AbstractMap.SimpleEntry. Я думаю, вы узнаете что-то новое каждый день!
Прииду Нимре
что вы подразумеваете под включением в «включающий экземпляр AbstractMap». Является ли Enclosing выводить технический термин или что-то в Java? пожалуйста, ведите меня.
C графика
70

Начиная с Java 9, появился новый служебный метод, позволяющий создавать неизменяемую запись, котораяMap#entry(Object, Object) .

Вот простой пример:

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

Поскольку это является неизменным, вызов setValueвызовет UnsupportedOperationException. Другими ограничениями является тот факт, что он не сериализуем и, nullпоскольку ключ или значение запрещены, если он неприемлем для вас, вам придется использовать его AbstractMap.SimpleImmutableEntryили AbstractMap.SimpleEntryвместо него.

NB. Если вам нужно напрямую создать Mapпары от 0 до 10 (ключ, значение), вы можете вместо этого использовать методы типа Map.of(K key1, V value1, ...).

Николас Филотто
источник
53

Попробуйте Maps.immutableEntry из гуавы

Это имеет преимущество совместимости с Java 5 (в отличие от AbstractMap.SimpleEntryкоторого требуется Java 6.)

finnw
источник
34

Пример 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>>();

Добавить строки:

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

Выбрать строки:

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

Следует напечатать:

2
3
20
30
2
4

Это хорошо для определения ребер графовых структур. Как между нейронами в твоей голове.

Эрик Лещинский
источник
18

Вы могли бы на самом деле пойти с: Map.Entry<String, String> en= Maps.immutableEntry(key, value);

Хуан Дэвид Ортега Тапиас
источник
Это полезно github.com/google/guava Guava - это набор основных библиотек Java от Google, который включает в себя новые типы коллекций (например, мультикарты и мультимножества), неизменяемые коллекции, библиотеки графов и утилиты для параллелизма, ввода-вывода, хэширования, кэширования, примитивы, строки и многое другое! Он широко используется в большинстве проектов Java в Google, а также во многих других компаниях.
Лангогуанг
13

Зачем Map.Entry ? Я думаю, что-то вроде пары ключ-значение подходит для этого случая.

Используйте java.util.AbstractMap.SimpleImmutableEntryилиjava.util.AbstractMap.SimpleEntry

tanghao
источник
6

org.apache.commons.lang3.tuple.Pair инвентарь java.util.Map.Entry и может также использоваться автономно.

Также, как другие упоминали, Гуава com.google.common.collect.Maps.immutableEntry(K, V)делает свое дело.

Я предпочитаю Pairза его свободный Pair.of(L, R)синтаксис.

parxier
источник
2
Могу ли я предложить ImmutablePairвместо этого?
белучин
Мне очень нравится класс org.apache.commons.lang3.tuple.Pair, он классный!
Laurens Op 't Zandt
Единственное, что мне не нравится в этом, это то, что он сериализуется влево, вправо, ключ, значение, где left = key и right = value. Всего 2 дополнительных бесполезных (возможно) значения в сериализованной строке.
Викрант Гоэль
4

Я определил общий класс Pair, который я использую все время. Здорово. В качестве бонуса, определяя статический метод фабрики (Pair.create), мне нужно писать аргументы типа только вдвое реже.

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
Извините, я опубликовал это перед прочтением всех остальных комментариев. Похоже, вы хотите что-то, что входит в стандартную библиотеку ...
Нельс Бекман
2
Google Guava хорошо объясняет, почему Pairреализации - это плохо. Источник
Инго Бюрк
3

Если вы используете Clojure, у вас есть другая опция:

(defn map-entry
  [k v]
  (clojure.lang.MapEntry/create k v))
Радон Росборо
источник