web-dev-qa-db-fra.com

Quel est l'équivalent de la paire C ++ <L, R> en Java?

Existe-t-il une bonne raison pour laquelle il n'y a pas Pair<L,R> en Java? Quel serait l'équivalent de cette construction C++? Je préférerais éviter de réimplémenter le mien.

Il semble que 1.6 fournit quelque chose de similaire (AbstractMap.SimpleEntry<K,V>), mais cela semble assez compliqué.

638
user13673

Dans n fil sur comp.lang.Java.help , Hunter Gratzner donne des arguments contre la présence d'une construction Pairen Java. L'argument principal est qu'une classe Pairne transmet aucune sémantique à propos de la relation entre les deux valeurs (comment savoir ce que signifie "premier" et "deuxième"?).

Une meilleure pratique consiste à écrire une classe très simple, telle que celle proposée par Mike, pour chaque application que vous auriez créée avec la classe Pairname__. Map.Entry est un exemple de paire qui porte sa signification dans son nom.

En résumé, à mon avis, il est préférable d’avoir une classe Position(x,y), une classe Range(begin,end) et une classe Entry(key,value) plutôt qu’un générique Pair(first,second) qui ne m’indique rien de ce qu’elle est supposée faire.

380
Luc Touraille

C'est Java. Vous devez créer votre propre classe Pair sur mesure avec des noms de classe et de champ descriptifs, sans oublier de réinventer la roue en écrivant hashCode ()/equals () ou en implémentant encore et encore Comparable.

146
Andreas Krey

HashMap compatible Classe de paires:

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

La paire la plus courte que je pourrais trouver est la suivante, en utilisant Lombok :

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

Il présente tous les avantages de la réponse de @arturh (à l'exception de la comparabilité), il possède hashCode, equals, toString et un "constructeur" statique.

52
Michael Piefel
35
Matunos

Une autre façon d'implémenter Pair with.

  • Champs immuables publics, c.-à-d. Structure de données simple.
  • Comparable.
  • Hash simple et égal.
  • Une usine simple pour ne pas avoir à fournir les types. par exemple. Pair.of ("bonjour", 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 + ')';
        }
    }
    
31
Peter Lawrey

Que diriez-vous de http://www.javatuples.org/index.html Je l’ai trouvé très utile.

Le javatuples vous propose des classes de tuples de un à dix éléments:

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)
26
cyberoblivion

Android fournit Pairclass ( http://developer.Android.com/reference/Android/util/Pair.html ), voici la mise en œuvre:

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
sherpya

Cela dépend de ce que vous voulez utiliser. La raison typique est de parcourir les cartes pour lesquelles vous faites simplement ceci (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());
}
12
cletus

Le plus gros problème est probablement que l'on ne peut pas garantir l'immuabilité sur A et B (voir Comment s'assurer que les paramètres de type sont immuables ), de sorte que hashCode() peut donner des résultats incohérents pour la même paire après est inséré dans une collection, par exemple (cela donnerait un comportement indéfini, voir Définition d'égaux en termes de champs mutables ). Pour une classe Pair particulière (non générique), le programmeur peut assurer l’immuabilité en choisissant soigneusement A et B comme immuables.

Quoi qu'il en soit, effacer les avertissements génériques de la réponse de @ 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 + ')';
    }
}

Les ajouts/corrections sont les bienvenus :) En particulier, je ne suis pas tout à fait sûr de mon utilisation de Pair<?, ?>.

Pour plus d'informations sur les raisons de cette syntaxe, voir Assurez-vous que les objets implémentent Comparable et une explication détaillée Comment implémenter une fonction générique max(Comparable a, Comparable b) en Java?

8
Mr_and_Mrs_D

Bonne nouvelle Java a ajouté une valeur clé Pair.

il suffit d'importer javafx.util.Pair;

et utilisez simplement comme dans c++.

Pair < Key , Value > 

par exemple.

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

pr.get(key); // will return corresponding value
5
RAJAN_PARMAR

Comme beaucoup d'autres l'ont déjà dit, cela dépend vraiment du cas d'utilisation d'une classe Pair, qu'elle soit utile ou non.

Je pense que pour une fonction d'assistance privée, il est tout à fait légitime d'utiliser une classe Pair si cela rend votre code plus lisible et ne vaut pas la peine de créer une autre classe de valeur avec tout son code de plaque de chaudière.

D'autre part, si votre niveau d'abstraction exige que vous documentiez clairement la sémantique de la classe qui contient deux objets ou valeurs, vous devez alors écrire une classe pour celle-ci. C'est généralement le cas si les données sont un objet métier.

Comme toujours, cela nécessite un jugement compétent.

Pour votre deuxième question, je recommande la classe Pair des bibliothèques Apache Commons. Celles-ci peuvent être considérées comme des bibliothèques standard étendues pour Java:

https://commons.Apache.org/proper/commons-lang/apidocs/org/Apache/commons/lang3/Tuple/Pair.html

Vous voudrez peut-être également consulter Apache Commons ' EqualsBuilder , HashCodeBuilder et ToStringBuilder , qui simplifient l'écriture de classes de valeur pour vos objets métier.

5
Peter Goetz

Vous pouvez utiliser la classe d’utilitaires javafx, Pair, qui remplit le même objectif que la paire <> dans c ++. https://docs.Oracle.com/javafx/2/api/javafx/util/Pair.html

JavaFX (fourni avec Java 8) a la classe Pair <A, B>

5
CarrKnight

À mon avis, il n'y a pas de paire en Java car, si vous souhaitez ajouter des fonctionnalités supplémentaires directement sur la paire (par exemple, Comparable), vous devez relier les types. En C++, on s'en fiche, et si les types composant une paire n'ont pas operator <, le pair::operator < ne se compilera pas aussi bien.

Un exemple de Comparable sans limite:

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

Un exemple de Comparable avec vérification à la compilation pour savoir si les arguments de type sont comparables:

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

C'est bien, mais cette fois, vous ne pouvez pas utiliser de types non comparables comme arguments de type dans Pair. On peut utiliser beaucoup de comparateurs pour Pair dans certaines classes d’utilitaires, mais les utilisateurs de C++ peuvent ne pas l’obtenir. Une autre méthode consiste à écrire un grand nombre de classes dans une hiérarchie de types avec des limites différentes pour les arguments de types, mais il existe trop de limites possibles et leurs combinaisons ...

5
MaxBuzz
Collections.singletonMap(left, rigth);
4
Denis Arkharov

Map.Entry interface est très proche de la paire c ++. Examinez l'implémentation concrète, telle que AbstractMap.SimpleEntry et AbstractMap.SimpleImmutableEntry. Le premier élément est getKey () et le second est getValue ().

4
Nikunj Bhagat

Bien qu'ils soient syntaxiquement similaires, Java et C++ ont des paradigmes très différents. Écrire en C++, comme Java, est mauvais, et écrire en Java, comme C++, est mauvais.

Avec une réflexion basée sur IDE comme Eclipse, l'écriture des fonctionnalités nécessaires d'une classe "paire" est simple et rapide. Créez une classe, définissez deux champs, utilisez les différentes options du menu "Générer XX" pour compléter la classe en quelques secondes. Peut-être devriez-vous taper un "compareTo" très rapidement si vous vouliez utiliser l'interface Comparable.

Avec des options de déclaration/définition séparées dans le langage, les générateurs de code C++ ne sont pas si bons, donc écrire à la main de petites classes d’utilitaires est plus fastidieux. Comme la paire est un modèle, vous n’avez pas à payer pour les fonctions que vous n’utilisez pas, et la fonction typedef permet d’attribuer des noms de types significatifs au code, de sorte que les objections concernant "aucune sémantique" ne tiennent vraiment pas.

3
gerardw

En fonction de la nature du langage Java, je suppose que les utilisateurs ne requièrent pas réellement un Pairname__, une interface est généralement ce dont ils ont besoin. Voici un exemple:

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

Ainsi, lorsque les utilisateurs veulent renvoyer deux valeurs, ils peuvent procéder comme suit:

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

C'est une solution assez légère, et elle répond à la question "Quelle est la sémantique d'un Pair<L,R>?". La réponse est qu'il s'agit d'une interface construite avec deux types (qui peuvent être différents) et des méthodes pour renvoyer chacun d'eux. C'est à vous d'ajouter une sémantique supplémentaire. Par exemple, si vous utilisez Position et souhaitez VRAIMENT l'indiquer dans votre code, vous pouvez définir PositionXet PositionYcontenant Integername__, pour créer un Pair<PositionX,PositionY>. Si JSR 308 est disponible, vous pouvez également utiliser Pair<@PositionX Integer, @PositionY Ingeger> pour le simplifier.

EDIT: Une chose que je devrais indiquer ici est que la définition ci-dessus associe explicitement le nom du paramètre de type et le nom de la méthode. Ceci est une réponse à ceux qui font valoir qu'un Pairest le manque d'informations sémantiques. En fait, la méthode getLsignifie "donnez-moi l'élément qui correspond au type de paramètre de type L", ce qui signifie quelque chose.

EDIT: Voici une classe d’utilitaires simple qui peut vous rendre la vie plus facile:

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

usage:

return Pairs.makePair(new Integer(100), "123");
3
Earth Engine

Vous pouvez utiliser la bibliothèque AutoValue de Google - https://github.com/google/auto/tree/master/value .

Vous créez une très petite classe abstraite et l'annotez avec @AutoValue et le processeur d'annotation génère pour vous une classe concrète ayant une valeur sémantique.

2
Shahar

Voici quelques bibliothèques qui ont plusieurs degrés de nuplets pour votre commodité:

  • JavaTuples . Tuples de degré 1-10 est tout ce qu'il a.
  • JavaSlang . Tuples de degré 0-8 et beaucoup d'autres goodies fonctionnels.
  • jOOλ . Tuples de degré 0-16 et quelques autres goodies fonctionnels. (Avertissement, je travaille pour la société de maintenance)
  • Java fonctionnel . Tuples de degré 0-8 et beaucoup d'autres goodies fonctionnels.

Il a été mentionné que d'autres bibliothèques contiennent au moins le nuplet Pair.

Plus précisément, dans le contexte de la programmation fonctionnelle qui utilise beaucoup de typage structurel, plutôt que de typage nominal ( comme préconisé dans la réponse acceptée ), ces bibliothèques et leurs n-uplets sont très utiles.

2
Lukas Eder

La paire serait une bonne chose, pour être une unité de construction de base pour un générique complexe, par exemple, cela provient de mon code:

WeakHashMap<Pair<String, String>, String> map = ...

C'est exactement la même chose que le tuple de Haskell

2
Illarion Kovalchuk

Pour les langages de programmation tels que Java, la structure de données alternative utilisée par la plupart des programmeurs pour représenter une paire, comme des structures de données, consiste en deux tableaux, et l'accès aux données via le même index

exemple: http://www-igm.univ-mlv.fr/~lecroq/string/node8.html#SECTION008

Ce n'est pas idéal car les données doivent être liées ensemble, mais s'avèrent également être relativement bon marché. De plus, si votre cas d'utilisation requiert le stockage de coordonnées, il est préférable de créer votre propre structure de données.

J'ai quelque chose comme ça dans ma bibliothèque

public class Pair<First,Second>{.. }
2
Swapneel Patil

Brian Goetz, Paul Sandoz et Stuart Marks expliquer pourquoi au cours de la session de contrôle de la qualité à Devoxx'14.

Avoir une classe de paire générique dans la bibliothèque standard se transformera en dette technique une fois types de valeur introduits.

Voir aussi: Java SE 8 a-t-il des paires ou des tuples?

2
user2418306

une autre mise en œuvre laconique de lombok

import lombok.Value;

@Value(staticConstructor = "of")
public class Pair<F, S> {
    private final F first;
    private final S second;
}
1
Matt Broekhuis

Manière simple Object [] - peut être utilisé comme toute autre dimension

1
Testus

com.Sun.tools.javac.util.Pair est une implémentation simple d'une paire. On peut le trouver dans jdk1.7.0_51\lib\tools.jar.

Autre que org.Apache.commons.lang3.Tuple.Pair, ce n'est pas simplement une interface.

1
masterxilo

J'ai remarqué que toutes les implémentations de paires dispersées ici attribuent une signification à l'ordre des deux valeurs. Quand je pense à une paire, je pense à une combinaison de deux éléments dans lesquels l'ordre des deux n'a aucune importance. Voici mon implémentation d'une paire non ordonnée, avec hashCode et equals pour remplacer le comportement souhaité dans les collections. Aussi clonable.

/**
 * The class <code>Pair</code> models a container for two objects wherein the
 * object order is of no consequence for equality and hashing. An example of
 * using Pair would be as the return type for a method that needs to return two
 * related objects. Another good use is as entries in a Set or keys in a Map
 * when only the unordered combination of two objects is of interest.<p>
 * The term "object" as being a one of a Pair can be loosely interpreted. A
 * Pair may have one or two <code>null</code> entries as values. Both values
 * may also be the same object.<p>
 * Mind that the order of the type parameters T and U is of no importance. A
 * Pair&lt;T, U> can still return <code>true</code> for method <code>equals</code>
 * called with a Pair&lt;U, T> argument.<p>
 * Instances of this class are immutable, but the provided values might not be.
 * This means the consistency of equality checks and the hash code is only as
 * strong as that of the value types.<p>
 */
public class Pair<T, U> implements Cloneable {

    /**
     * One of the two values, for the declared type T.
     */
    private final T object1;
    /**
     * One of the two values, for the declared type U.
     */
    private final U object2;
    private final boolean object1Null;
    private final boolean object2Null;
    private final boolean dualNull;

    /**
     * Constructs a new <code>Pair&lt;T, U&gt;</code> with T object1 and U object2 as
     * its values. The order of the arguments is of no consequence. One or both of
     * the values may be <code>null</code> and both values may be the same object.
     *
     * @param object1 T to serve as one value.
     * @param object2 U to serve as the other value.
     */
    public Pair(T object1, U object2) {

        this.object1 = object1;
        this.object2 = object2;
        object1Null = object1 == null;
        object2Null = object2 == null;
        dualNull = object1Null && object2Null;

    }

    /**
     * Gets the value of this Pair provided as the first argument in the constructor.
     *
     * @return a value of this Pair.
     */
    public T getObject1() {

        return object1;

    }

    /**
     * Gets the value of this Pair provided as the second argument in the constructor.
     *
     * @return a value of this Pair.
     */
    public U getObject2() {

        return object2;

    }

    /**
     * Returns a shallow copy of this Pair. The returned Pair is a new instance
     * created with the same values as this Pair. The values themselves are not
     * cloned.
     *
     * @return a clone of this Pair.
     */
    @Override
    public Pair<T, U> clone() {

        return new Pair<T, U>(object1, object2);

    }

    /**
     * Indicates whether some other object is "equal" to this one.
     * This Pair is considered equal to the object if and only if
     * <ul>
     * <li>the Object argument is not null,
     * <li>the Object argument has a runtime type Pair or a subclass,
     * </ul>
     * AND
     * <ul>
     * <li>the Object argument refers to this pair
     * <li>OR this pair's values are both null and the other pair's values are both null
     * <li>OR this pair has one null value and the other pair has one null value and
     * the remaining non-null values of both pairs are equal
     * <li>OR both pairs have no null values and have value tuples &lt;v1, v2> of
     * this pair and &lt;o1, o2> of the other pair so that at least one of the
     * following statements is true:
     * <ul>
     * <li>v1 equals o1 and v2 equals o2
     * <li>v1 equals o2 and v2 equals o1
     * </ul>
     * </ul>
     * In any other case (such as when this pair has two null parts but the other
     * only one) this method returns false.<p>
     * The type parameters that were used for the other pair are of no importance.
     * A Pair&lt;T, U> can return <code>true</code> for equality testing with
     * a Pair&lt;T, V> even if V is neither a super- nor subtype of U, should
     * the the value equality checks be positive or the U and V type values
     * are both <code>null</code>. Type erasure for parameter types at compile
     * time means that type checks are delegated to calls of the <code>equals</code>
     * methods on the values themselves.
     *
     * @param obj the reference object with which to compare.
     * @return true if the object is a Pair equal to this one.
     */
    @Override
    public boolean equals(Object obj) {

        if(obj == null)
            return false;

        if(this == obj)
            return true;

        if(!(obj instanceof Pair<?, ?>))
            return false;

        final Pair<?, ?> otherPair = (Pair<?, ?>)obj;

        if(dualNull)
            return otherPair.dualNull;

        //After this we're sure at least one part in this is not null

        if(otherPair.dualNull)
            return false;

        //After this we're sure at least one part in obj is not null

        if(object1Null) {
            if(otherPair.object1Null) //Yes: this and other both have non-null part2
                return object2.equals(otherPair.object2);
            else if(otherPair.object2Null) //Yes: this has non-null part2, other has non-null part1
                return object2.equals(otherPair.object1);
            else //Remaining case: other has no non-null parts
                return false;
        } else if(object2Null) {
            if(otherPair.object2Null) //Yes: this and other both have non-null part1
                return object1.equals(otherPair.object1);
            else if(otherPair.object1Null) //Yes: this has non-null part1, other has non-null part2
                return object1.equals(otherPair.object2);
            else //Remaining case: other has no non-null parts
                return false;
        } else {
            //Transitive and symmetric requirements of equals will make sure
            //checking the following cases are sufficient
            if(object1.equals(otherPair.object1))
                return object2.equals(otherPair.object2);
            else if(object1.equals(otherPair.object2))
                return object2.equals(otherPair.object1);
            else
                return false;
        }

    }

    /**
     * Returns a hash code value for the pair. This is calculated as the sum
     * of the hash codes for the two values, wherein a value that is <code>null</code>
     * contributes 0 to the sum. This implementation adheres to the contract for
     * <code>hashCode()</code> as specified for <code>Object()</code>. The returned
     * value hash code consistently remain the same for multiple invocations
     * during an execution of a Java application, unless at least one of the pair
     * values has its hash code changed. That would imply information used for 
     * equals in the changed value(s) has also changed, which would carry that
     * change onto this class' <code>equals</code> implementation.
     *
     * @return a hash code for this Pair.
     */
    @Override
    public int hashCode() {

        int hashCode = object1Null ? 0 : object1.hashCode();
        hashCode += (object2Null ? 0 : object2.hashCode());
        return hashCode;

    }

}

Cette mise en œuvre a été correctement testée par unité et son utilisation dans un ensemble et une carte a été testée.

Remarquez que je ne prétends pas publier ceci dans le domaine public. Il s'agit du code que je viens d'écrire pour une utilisation dans une application. Par conséquent, si vous comptez vous en servir, évitez de copier directement les commentaires et les noms. Attraper ma dérive?

1
G_H

Si quelqu'un veut une version extrêmement simple et facile à utiliser, je le mets à disposition sur https://github.com/lfac-pt/Java-Pair . De plus, les améliorations sont les bienvenues!

1
Luís Cardoso

De nombreuses personnes publient un code Pair qui peut être utilisé comme clé dans une carte ... Si vous essayez d'utiliser une paire comme clé de hachage (un idiome courant), veillez à consulter le Table<R,C,V> de Guava: http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Table . Ils donnent l'exemple d'utilisation suivante pour les bords de graphique:

Table<Vertex, Vertex, Double> weightedGraph = HashBasedTable.create();
weightedGraph.put(v1, v2, 4);
weightedGraph.put(v1, v3, 20);
weightedGraph.put(v2, v3, 5);

weightedGraph.row(v1); // returns a Map mapping v2 to 4, v3 to 20
weightedGraph.column(v3); // returns a Map mapping v1 to 20, v2 to 5

Table mappe deux clés sur une seule valeur et fournit également des recherches efficaces pour les deux types de clés. J'ai commencé à utiliser cette structure de données au lieu d'un Map<Pair<K1,K2>, V> dans de nombreuses parties de mon code. Il existe des implémentations de tableaux, d'arbres et autres pour les utilisations denses et éparses, avec la possibilité de spécifier vos propres classes de carte intermédiaires.

0
Andrew Mao

La réponse de @Andreas Krey est bonne. Tout ce que Java rend difficile, vous ne devriez probablement pas le faire.

D'après mon expérience, les utilisations les plus courantes de Pair sont les multiples valeurs renvoyées par une méthode et les valeurs VALUES d'un hashmap (souvent indexées par des chaînes).

Dans ce dernier cas, j'ai récemment utilisé une structure de données, comme ceci:

class SumHolder{MyObject trackedObject, double sum};

Il y a toute votre classe "Pair", à peu près la même quantité de code qu'un "Pair" générique mais avec l'avantage des noms descriptifs. Il peut être défini directement dans la méthode utilisée, ce qui éliminera les problèmes typiques liés aux variables publiques et autres. En d'autres termes, c'est absolument mieux qu'une paire pour cet usage (en raison des membres nommés) et pas pire.

Si vous voulez réellement une "paire" pour la clé d'un hashmap, vous créez essentiellement un index à double clé. Je pense que cela peut être le cas où une "paire" est beaucoup moins de code. Ce n'est pas vraiment facile car Eclipse pourrait générer des égaux/hachages sur votre petite classe de données, mais ce serait beaucoup plus de code. Ici, une paire serait une solution rapide, mais si vous avez besoin d'un hachage à double index, qui peut dire que vous n'avez pas besoin d'un hachage à index n? La solution de classe de données sera mise à l'échelle, la paire ne sera pas à moins que vous les imbriquiez!

Donc, le second cas, revenant d'une méthode, est un peu plus difficile. Votre classe a besoin de plus de visibilité (l'appelant doit aussi la voir). Vous pouvez le définir en dehors de la méthode mais à l'intérieur de la classe exactement comme ci-dessus. À ce stade, votre méthode devrait pouvoir renvoyer un objet MyClass.SumHolder. L'appelant obtient le nom des objets renvoyés, pas seulement une "paire". Notez à nouveau que la sécurité "par défaut" du niveau de paquet est assez bonne - elle est suffisamment restrictive pour ne pas vous causer trop de problèmes. Mieux qu'un objet "Pair" de toute façon.

L'autre cas d'utilisation possible de Pairs est une api publique avec des valeurs de retour pour les appelants extérieurs à votre forfait actuel. Pour cela, je créerais simplement un véritable objet, de préférence immuable. Éventuellement, un appelant partagera cette valeur de retour et le fait de la rendre mutable pourrait être problématique. Ceci est un autre cas où l'objet Pair est pire - la plupart des paires ne peuvent pas être rendues immuables.

Un autre avantage de tous ces cas - la classe Java s'agrandit, ma classe sum avait besoin d'une seconde somme et d'un drapeau "Créé" au moment où j'avais terminé, j'aurais dû jeter la paire et partir avec autre chose, mais si la paire avait du sens, ma classe avec 4 valeurs a toujours au moins autant de sens.

0
Bill K
public class Pair<K, V> {

    private final K element0;
    private final V element1;

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

    public Pair(K element0, V element1) {
        this.element0 = element0;
        this.element1 = element1;
    }

    public K getElement0() {
        return element0;
    }

    public V getElement1() {
        return element1;
    }

}

utilisation:

Pair<Integer, String> pair = Pair.createPair(1, "test");
pair.getElement0();
pair.getElement1();

Immuable, seulement une paire!

0
Baptiste

Avec la nouvelle version de Lombok vous pouvez compiler cette classe mignonne:

@Value(staticConstructor = "of") public class Pair <E> {
  E first, second;
}

et l'utiliser comme: Pair<Value> pairOfValues = Pair.of(value1, value2);

0
Dominik