Вопрос-ответ

A Java collection of value pairs? (tuples?)

Коллекция пар значений Java? (кортежи?)

Мне нравится, что в Java есть карта, где вы можете определять типы каждой записи на карте, например, <String, Integer>.

То, что я ищу, - это тип коллекции, где каждый элемент в коллекции представляет собой пару значений. Каждое значение в паре может иметь свой собственный тип (как в примере String и Integer выше), который определяется во время объявления.

Коллекция сохранит заданный порядок и не будет обрабатывать одно из значений как уникальный ключ (как в map).

По сути, я хочу иметь возможность определять МАССИВ типа <String,Integer> или любые другие 2 типа.

Я понимаю, что могу создать класс, в котором нет ничего, кроме двух переменных, но это кажется чрезмерно подробным.

Я также понимаю, что мог бы использовать 2D-массив, но из-за разных типов, которые мне нужно использовать, мне пришлось бы создавать из них массивы объектов, а затем мне пришлось бы все время выполнять приведение.

Мне нужно хранить только пары в коллекции, поэтому мне нужно только два значения для каждой записи. Существует ли что-то подобное без прохождения маршрута класса? Спасибо!

Переведено автоматически
Ответ 1

AbstractMap.SimpleEntry

Легко, вы ищете это:

java.util.List<java.util.Map.Entry<String,Integer>> pairList= new java.util.ArrayList<>();

Как вы можете ее заполнить?

java.util.Map.Entry<String,Integer> pair1=new java.util.AbstractMap.SimpleEntry<>("Not Unique key1",1);
java.util.Map.Entry<String,Integer> pair2=new java.util.AbstractMap.SimpleEntry<>("Not Unique key2",2);
pairList.add(pair1);
pairList.add(pair2);

Это упрощает:

Entry<String,Integer> pair1=new SimpleEntry<>("Not Unique key1",1);
Entry<String,Integer> pair2=new SimpleEntry<>("Not Unique key2",2);
pairList.add(pair1);
pairList.add(pair2);

И, с помощью createEntry метода, может еще больше уменьшить детализацию до:

pairList.add(createEntry("Not Unique key1", 1));
pairList.add(createEntry("Not Unique key2", 2));

Поскольку ArrayList не является окончательным, его можно разделить на подклассы, чтобы предоставить of метод (и вышеупомянутый createEntry метод), что приводит к синтаксически лаконичному:

TupleList<java.util.Map.Entry<String,Integer>> pair = new TupleList<>();
pair.of("Not Unique key1", 1);
pair.of("Not Unique key2", 2);
Ответ 2

Класс Pair - это один из тех примеров обобщения "дай мне", который достаточно легко написать самостоятельно. Например, у меня в голове не укладывается.:

public class Pair<L,R> {

private final L left;
private final R right;

public Pair(L left, R right) {
assert left != null;
assert right != null;

this.left = left;
this.right = right;
}

public L getLeft() { return left; }
public R getRight() { return right; }

@Override
public int hashCode() { return left.hashCode() ^ right.hashCode(); }

@Override
public boolean equals(Object o) {
if (!(o instanceof Pair)) return false;
Pair pairo = (Pair) o;
return this.left.equals(pairo.getLeft()) &&
this.right.equals(pairo.getRight());
}

}

И да, это существует в нескольких местах Сети с разной степенью полноты и функциональности. (Мой пример выше предназначен для неизменности.)

Ответ 3

Java 9+

В Java 9 вы можете просто написать: Map.entry(key, value) чтобы создать неизменяемую пару.

Примечание: этот метод не допускает, чтобы ключи или значения были нулевыми. Например, если вы хотите разрешить значения null, вам нужно изменить это на: Map.entry(key, Optional.ofNullable(value)).


Java 8+

В Java 8 вы можете использовать более универсальный класс javafx.util.Pair для создания неизменяемой сериализуемой пары. Этот класс действительно допускает нулевые ключи и нулевые значения. (В Java 9 этот класс включен в javafx.base модуль). РЕДАКТИРОВАТЬ: начиная с Java 11, JavaFX был отделен от JDK, поэтому вам понадобится дополнительный артефакт maven org.openjfx:javafx-base.


Java 6+

В Java 6 и выше вы можете использовать более подробный вариант AbstractMap.SimpleImmutableEntry для неизменяемой пары или AbstractMap.SimpleEntry для пары, значение которой может быть изменено. Эти классы также допускают нулевые ключи и нулевые значения и сериализуемы.


Android

Если вы пишете для Android, просто используйте Pair.create(key, value) для создания неизменяемой пары.


Apache Commons

Apache Commons Lang provides the helpful Pair.of(key, value) to create an immutable, comparable, serializable pair.


Eclipse Collections

If you're using pairs that contain primitives, Eclipse Collections provides some very efficient primitive pair classes that will avoid all the inefficient auto-boxing and auto-unboxing.

For instance, you could use PrimitiveTuples.pair(int, int) to create an IntIntPair, or PrimitiveTuples.pair(float, long) to create a FloatLongPair.


Hand-rolled implementations

As of Java 16, records have come out of preview status, so you can now do:

public record Pair<K, V>(K key, V value) {
public static <K, V> Pair<K, V> of(K key, V value) {
return new Pair<>(key, value);
}
}

The above implementation will have a big advantage in the future, as it'll allow you to do record deconstruction.

Prior to Java 16, you can achieve the same semantics with Project Lombok:

@Value(staticConstructor = "of")
public class Pair<K, V> {
K key;
V value;
}

или со следующей детализацией (которая, в отличие от класса, указанного в принятом ответе, защищает от исключений NullPointerExceptions и имеет надежную hashCode() реализацию, идентичную реализации Records1):

import java.util.Objects;

public class Pair<K, V> {

public final K key;
public final V value;

private Pair(K key, V value) {
this.key = key;
this.value = value;
}

public static <K, V> Pair<K, V> of(K key, V value) {
return new Pair<>(key, value);
}

public boolean equals(Object o) {
return o instanceof Pair && Objects.equals(key, ((Pair<?,?>)o).key) && Objects.equals(value, ((Pair<?,?>)o).value);
}

public int hashCode() {
return 31 * Objects.hashCode(key) + Objects.hashCode(value);
}

public String toString() {
return key + "=" + value;
}
}

1 Протестировано на OpenJDK 17

Ответ 4

Map.Entry

Эти встроенные классы тоже являются опцией. Оба реализуют Map.Entry интерфейс.

UML-схема интерфейса Map.Entry с парой реализующих классов

java