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

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

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

Ответы [ 33 ]

381 голосов
/ 01 октября 2008

В потоке на comp.lang.java.help Хантер Гратцнер приводит некоторые аргументы против присутствия конструкции Pair в Java. Основным аргументом является то, что класс Pair не передает никакой семантики о связи между двумя значениями (откуда вы знаете, что означают «первое» и «второе»?).

Лучше всего написать очень простой класс, подобный тому, который предложил Майк, для каждого приложения, которое вы сделали бы из класса Pair. Map.Entry является примером пары, которая несет в себе свое значение.

Подводя итог, на мой взгляд, лучше иметь класс Position(x,y), класс Range(begin,end) и класс Entry(key,value), а не универсальный Pair(first,second), который ничего не говорит мне о том, что предполагается делать.

146 голосов
/ 27 февраля 2010

Это Java. Вы должны создать свой собственный класс Pair с описательными именами классов и полей, не говоря уже о том, что вы заново изобретете колесо, написав hashCode () / equals () или снова и снова реализуя Comparable.

101 голосов
/ 24 марта 2009

HashMap совместимый класс пары:

public class Pair<A, B> {
    private A first;
    private B second;

    public Pair(A first, B second) {
        super();
        this.first = first;
        this.second = second;
    }

    public int hashCode() {
        int hashFirst = first != null ? first.hashCode() : 0;
        int hashSecond = second != null ? second.hashCode() : 0;

        return (hashFirst + hashSecond) * hashSecond + hashFirst;
    }

    public boolean equals(Object other) {
        if (other instanceof Pair) {
            Pair otherPair = (Pair) other;
            return 
            ((  this.first == otherPair.first ||
                ( this.first != null && otherPair.first != null &&
                  this.first.equals(otherPair.first))) &&
             (  this.second == otherPair.second ||
                ( this.second != null && otherPair.second != null &&
                  this.second.equals(otherPair.second))) );
        }

        return false;
    }

    public String toString()
    { 
           return "(" + first + ", " + second + ")"; 
    }

    public A getFirst() {
        return first;
    }

    public void setFirst(A first) {
        this.first = first;
    }

    public B getSecond() {
        return second;
    }

    public void setSecond(B second) {
        this.second = second;
    }
}
52 голосов
/ 17 декабря 2010

Самая короткая пара, которую я мог придумать, это следующая, используя Lombok :

@Data
@AllArgsConstructor(staticName = "of")
public class Pair<F, S> {
    private F first;
    private S second;
}

Он обладает всеми преимуществами ответа @ arturh (кроме сопоставимости), имеет hashCode, equals, toString и статический «конструктор».

35 голосов
/ 13 марта 2012

Apache Commons Lang 3.0+ имеет несколько классов пары: http://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/tuple/package-summary.html

31 голосов
/ 05 сентября 2010

Еще один способ реализации Pair with.

  • Открытые неизменяемые поля, т.е. простая структура данных.
  • Сопоставимые.
  • Простой хеш и равно.
  • Простая фабрика, поэтому вам не нужно указывать типы. например Pair.of ("привет", 1);

    public class Pair<FIRST, SECOND> implements Comparable<Pair<FIRST, SECOND>> {
    
        public final FIRST first;
        public final SECOND second;
    
        private Pair(FIRST first, SECOND second) {
            this.first = first;
            this.second = second;
        }
    
        public static <FIRST, SECOND> Pair<FIRST, SECOND> of(FIRST first,
                SECOND second) {
            return new Pair<FIRST, SECOND>(first, second);
        }
    
        @Override
        public int compareTo(Pair<FIRST, SECOND> o) {
            int cmp = compare(first, o.first);
            return cmp == 0 ? compare(second, o.second) : cmp;
        }
    
        // todo move this to a helper class.
        private static int compare(Object o1, Object o2) {
            return o1 == null ? o2 == null ? 0 : -1 : o2 == null ? +1
                    : ((Comparable) o1).compareTo(o2);
        }
    
        @Override
        public int hashCode() {
            return 31 * hashcode(first) + hashcode(second);
        }
    
        // todo move this to a helper class.
        private static int hashcode(Object o) {
            return o == null ? 0 : o.hashCode();
        }
    
        @Override
        public boolean equals(Object obj) {
            if (!(obj instanceof Pair))
                return false;
            if (this == obj)
                return true;
            return equal(first, ((Pair) obj).first)
                    && equal(second, ((Pair) obj).second);
        }
    
        // todo move this to a helper class.
        private boolean equal(Object o1, Object o2) {
            return o1 == null ? o2 == null : (o1 == o2 || o1.equals(o2));
        }
    
        @Override
        public String toString() {
            return "(" + first + ", " + second + ')';
        }
    }
    
26 голосов
/ 01 марта 2012

Как насчет http://www.javatuples.org/index.html Я нашел это очень полезным.

Javatuples предлагает вам классы кортежей от одного до десяти элементов:

Unit<A> (1 element)
Pair<A,B> (2 elements)
Triplet<A,B,C> (3 elements)
Quartet<A,B,C,D> (4 elements)
Quintet<A,B,C,D,E> (5 elements)
Sextet<A,B,C,D,E,F> (6 elements)
Septet<A,B,C,D,E,F,G> (7 elements)
Octet<A,B,C,D,E,F,G,H> (8 elements)
Ennead<A,B,C,D,E,F,G,H,I> (9 elements)
Decade<A,B,C,D,E,F,G,H,I,J> (10 elements)
12 голосов
/ 05 мая 2014

Android предоставляет Pair класс (http://developer.android.com/reference/android/util/Pair.html), здесь реализация:

public class Pair<F, S> {
    public final F first;
    public final S second;

    public Pair(F first, S second) {
        this.first = first;
        this.second = second;
    }

    @Override
    public boolean equals(Object o) {
        if (!(o instanceof Pair)) {
            return false;
        }
        Pair<?, ?> p = (Pair<?, ?>) o;
        return Objects.equal(p.first, first) && Objects.equal(p.second, second);
    }

    @Override
    public int hashCode() {
        return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode());
    }

    public static <A, B> Pair <A, B> create(A a, B b) {
        return new Pair<A, B>(a, b);
    }
}
12 голосов
/ 01 октября 2008

Это зависит от того, для чего вы хотите его использовать. Типичная причина для этого - перебирать карты, для чего вы просто делаете это (Java 5+):

Map<String, Object> map = ... ; // just an example
for (Map.Entry<String, Object> entry : map.entrySet()) {
  System.out.printf("%s -> %s\n", entry.getKey(), entry.getValue());
}
8 голосов
/ 01 декабря 2012

Самая большая проблема, вероятно, заключается в том, что невозможно обеспечить неизменность на A и B (см. Как обеспечить неизменность параметров типа ), поэтому hashCode() может дать противоречивые результаты для одной и той же пары после того, как вставлено, например, в коллекцию (это даст неопределенное поведение, см. Определение равных в терминах изменяемых полей ). Для определенного (не универсального) класса Pair программист может обеспечить неизменность, тщательно выбирая A и B как неизменяемые.

В любом случае, очистка предупреждений генерика от ответа @ PeterLawrey (java 1.7):

public class Pair<A extends Comparable<? super A>,
                    B extends Comparable<? super B>>
        implements Comparable<Pair<A, B>> {

    public final A first;
    public final B second;

    private Pair(A first, B second) {
        this.first = first;
        this.second = second;
    }

    public static <A extends Comparable<? super A>,
                    B extends Comparable<? super B>>
            Pair<A, B> of(A first, B second) {
        return new Pair<A, B>(first, second);
    }

    @Override
    public int compareTo(Pair<A, B> o) {
        int cmp = o == null ? 1 : (this.first).compareTo(o.first);
        return cmp == 0 ? (this.second).compareTo(o.second) : cmp;
    }

    @Override
    public int hashCode() {
        return 31 * hashcode(first) + hashcode(second);
    }

    // TODO : move this to a helper class.
    private static int hashcode(Object o) {
        return o == null ? 0 : o.hashCode();
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof Pair))
            return false;
        if (this == obj)
            return true;
        return equal(first, ((Pair<?, ?>) obj).first)
                && equal(second, ((Pair<?, ?>) obj).second);
    }

    // TODO : move this to a helper class.
    private boolean equal(Object o1, Object o2) {
        return o1 == o2 || (o1 != null && o1.equals(o2));
    }

    @Override
    public String toString() {
        return "(" + first + ", " + second + ')';
    }
}

Дополнения / исправления приветствуются :) В частности, я не совсем уверен в своем использовании Pair<?, ?>.

Для получения дополнительной информации о том, почему этот синтаксис см. . Убедитесь, что объекты реализуют Comparable , а также для подробного объяснения Как реализовать обобщенную функцию max(Comparable a, Comparable b) в Java?

...