Что эквивалентно паре C ++ <L, R> в Java? - PullRequest
638 голосов
/ 01 октября 2008

Есть ли веская причина, почему в Java нет Pair<L,R>? Что будет эквивалентно этой конструкции C ++? Я бы предпочел не реализовывать свою собственную.

Кажется, что 1.6 обеспечивает нечто подобное (AbstractMap.SimpleEntry<K,V>), но это выглядит довольно запутанным.

Ответы [ 33 ]

5 голосов
/ 08 апреля 2016

Вы можете использовать служебный класс javafx, Pair, который служит той же цели, что и pair <> в c ++. https://docs.oracle.com/javafx/2/api/javafx/util/Pair.html

5 голосов
/ 15 декабря 2010

По моему мнению, в Java нет пары, потому что, если вы хотите добавить дополнительные функции непосредственно в пару (например, сопоставимые), вы должны связать типы. В C ++ нам просто все равно, и если типы, составляющие пару, не имеют operator <, pair::operator < также не будет компилироваться.

Пример сопоставимого без ограничений:

public class Pair<F, S> implements Comparable<Pair<? extends F, ? extends S>> {
    public final F first;
    public final S second;
    /* ... */
    public int compareTo(Pair<? extends F, ? extends S> that) {
        int cf = compare(first, that.first);
        return cf == 0 ? compare(second, that.second) : cf;
    }
    //Why null is decided to be less than everything?
    private static int compare(Object l, Object r) {
        if (l == null) {
            return r == null ? 0 : -1;
        } else {
            return r == null ? 1 : ((Comparable) (l)).compareTo(r);
        }
    }
}

/* ... */

Pair<Thread, HashMap<String, Integer>> a = /* ... */;
Pair<Thread, HashMap<String, Integer>> b = /* ... */;
//Runtime error here instead of compile error!
System.out.println(a.compareTo(b));

Пример Comparable с проверкой во время компиляции для сопоставимости аргументов типа:

public class Pair<
        F extends Comparable<? super F>, 
        S extends Comparable<? super S>
> implements Comparable<Pair<? extends F, ? extends S>> {
    public final F first;
    public final S second;
    /* ... */
    public int compareTo(Pair<? extends F, ? extends S> that) {
        int cf = compare(first, that.first);
        return cf == 0 ? compare(second, that.second) : cf;
    }
    //Why null is decided to be less than everything?
    private static <
            T extends Comparable<? super T>
    > int compare(T l, T r) {
        if (l == null) {
            return r == null ? 0 : -1;
        } else {
            return r == null ? 1 : l.compareTo(r);
        }
    }
}

/* ... */

//Will not compile because Thread is not Comparable<? super Thread>
Pair<Thread, HashMap<String, Integer>> a = /* ... */;
Pair<Thread, HashMap<String, Integer>> b = /* ... */;
System.out.println(a.compareTo(b));

Это хорошо, но на этот раз вы не можете использовать несопоставимые типы в качестве аргументов типа в Pair. Можно использовать множество компараторов для пары в каком-то служебном классе, но люди на C ++ могут этого не получить. Другой способ - написать множество классов в иерархии типов с разными границами для аргументов типа, но слишком много возможных границ и их комбинаций ...

5 голосов
/ 21 апреля 2015

JavaFX (который поставляется в комплекте с Java 8) имеет класс Pair

5 голосов
/ 30 марта 2011

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

Я думаю, что для частной вспомогательной функции вполне законно использовать класс Pair, если это делает ваш код более читабельным и не стоит усилий для создания еще одного класса значений со всем его кодом.

С другой стороны, если ваш уровень абстракции требует, чтобы вы четко документировали семантику класса, который содержит два объекта или значения, то вы должны написать класс для него. Обычно это тот случай, если данные являются бизнес-объектом.

Как всегда, это требует умелого суждения.

Для вашего второго вопроса я рекомендую класс Pair из библиотек Apache Commons. Они могут рассматриваться как расширенные стандартные библиотеки для Java:

https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/tuple/Pair.html

Возможно, вы захотите взглянуть на Apache Commons ' EqualsBuilder , HashCodeBuilder и ToStringBuilder , которые упрощают написание классов значений для ваших бизнес-объектов.

5 голосов
/ 24 января 2016

Благая весть Java добавлено ключевое значение Pair.

просто импортировать javafx.util.Pair;

и используйте просто как в c++.

Pair < Key , Value > 

например.

Pair < Integer , Integer > pr = new Pair<Integer , Integer>()

pr.get(key); // will return corresponding value
4 голосов
/ 12 февраля 2016
Collections.singletonMap(left, rigth);
4 голосов
/ 15 мая 2015

Map.Entry интерфейс очень близок к паре c ++. Посмотрите на конкретную реализацию, например AbstractMap.SimpleEntry и AbstractMap.SimpleImmutableEntry Первый элемент - getKey (), а второй - getValue ().

3 голосов
/ 18 февраля 2014

Несмотря на синтаксическое сходство, Java и C ++ имеют очень разные парадигмы. Написание C ++ как Java - это плохо C ++, а написание Java как C ++ - это плохо.

В среде IDE, основанной на отражении, такой как Eclipse, написание обязательной функциональности класса "пара" выполняется быстро и просто. Создайте класс, определите два поля, используйте различные опции меню «Создать XX», чтобы заполнить класс за считанные секунды. Может быть, вам придется набирать «сравнить» очень быстро, если вы хотите интерфейс Comparable.

С отдельными опциями объявления / определения на языке C ++ генераторы кода не так хороши, поэтому написание небольших служебных классов требует больше времени. Поскольку пара является шаблоном, вам не нужно платить за функции, которые вы не используете, а средство typedef позволяет присваивать значимые типы названий кода, поэтому возражения по поводу «без семантики» на самом деле не поддерживаются. 1005 *

3 голосов
/ 09 ноября 2012

В соответствии с природой языка Java, я полагаю, что людям на самом деле не требуется Pair, интерфейс, как правило, то, что им нужно. Вот пример:

interface Pair<L, R> {
    public L getL();
    public R getR();
}

Итак, когда люди хотят вернуть два значения, они могут сделать следующее:

... //Calcuate the return value
final Integer v1 = result1;
final String v2 = result2;
return new Pair<Integer, String>(){
    Integer getL(){ return v1; }
    String getR(){ return v2; }
}

Это довольно легкое решение, и оно отвечает на вопрос «Какова семантика Pair<L,R>?». Ответ таков: это интерфейсная сборка с двумя (может быть разными) типами, и у нее есть методы для возврата каждого из них. Это зависит от вас, чтобы добавить дополнительную семантику к нему. Например, если вы используете Position и действительно хотите указать это в своем коде, вы можете определить PositionX и PositionY, которые содержат Integer, чтобы создать Pair<PositionX,PositionY>. Если JSR 308 доступен, вы также можете использовать Pair<@PositionX Integer, @PositionY Ingeger>, чтобы упростить это.

EDIT: Здесь я должен указать одну вещь: вышеприведенное определение явно связывает имя параметра типа и имя метода. Это ответ на те аргументы, что Pair - это недостаток семантической информации. На самом деле, метод getL означает «дать мне элемент, соответствующий типу параметра типа L», что означает что-то.

EDIT: Вот простой вспомогательный класс, который может облегчить жизнь:

class Pairs {
    static <L,R> Pair<L,R> makePair(final L l, final R r){
        return new Pair<L,R>(){
            public L getL() { return l; }
            public R getR() { return r; }   
        };
    }
}

использование:

return Pairs.makePair(new Integer(100), "123");
2 голосов
/ 03 марта 2016

Брайан Гетц, Пол Сандос и Стюарт Маркс объясняют, почему во время сессии QA в Devoxx'14.

Наличие общего класса пар в стандартной библиотеке превратится в технический долг, как только типы значений введены.

См. Также: Есть ли в Java SE 8 пары или кортежи?

...