Pregunta

¿Hay una buena razón por la cual no hay Pair < L, R > en Java? ¿Cuál sería el equivalente de esta construcción C ++? Prefiero evitar volver a implementar el mío.

Parece que 1.6 está proporcionando algo similar ( AbstractMap.SimpleEntry < K, V > ), pero parece bastante complicado.

¿Fue útil?

Solución

En un tema en comp .lang.java.help , Hunter Gratzner da algunos argumentos en contra de la presencia de una construcción Pair en Java. El argumento principal es que una clase Pair no transmite ninguna semántica sobre la relación entre los dos valores (¿cómo sabe qué significan "primero" y "segundo"?).

Una mejor práctica es escribir una clase muy simple, como la que Mike propuso, para cada aplicación que hubieras hecho de la clase Pair . Map.Entry es un ejemplo de un par que lleva su significado en su nombre.

Para resumir, en mi opinión, es mejor tener una clase Position (x, y) , una clase Range (begin, end) y una class < código> Entrada (clave, valor) en lugar de un Par (primero, segundo) genérico que no me dice nada sobre lo que se supone que debe hacer.

Otros consejos

Esto es Java. Tienes que crear tu propia clase de par a medida con nombres de clase y campo descriptivos, y no te preocupes si reinventas la rueda escribiendo hashCode () / equals () o implementando Comparable una y otra vez.

Clase de par compatible con 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;
    }
}

El par más corto que se me ocurrió es el siguiente, usando Lombok :

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

Tiene todos los beneficios de la respuesta de @arturh (excepto la comparabilidad), tiene hashCode , es igual a , toString y un "constructor" estático.

Otra forma de implementar Pair with.

  • Campos públicos inmutables, es decir, estructura de datos simple.
  • Comparable.
  • Hash simple e igual.
  • Fábrica simple para que no tenga que proporcionar los tipos. p.ej. Pair.of (" hola " ;, 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 + ')';
        }
    }
    

¿Qué hay de http://www.javatuples.org/index.html que he encontrado? Es muy útil.

Los javatuples le ofrecen clases de tuplas de uno a diez elementos:

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)

Depende de para qué lo quieras usar. La razón típica para hacerlo es iterar sobre los mapas, para los que simplemente hace esto (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());
}

android proporciona la clase Pair ( http://developer.android.com /reference/android/util/Pair.html ), aquí la implementación:

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

El mayor problema es probablemente que uno no puede garantizar la inmutabilidad en A y B (consulte Cómo asegurarse de que los parámetros de tipo sean inmutables ) para que hashCode () pueda dar resultados inconsistentes para el mismo Par después de insertarse en una colección, por ejemplo (esto daría un comportamiento indefinido, consulte Definir iguales en términos de campos mutables ). Para una clase de par particular (no genérica), el programador puede garantizar la inmutabilidad eligiendo cuidadosamente A y B para que sean inmutables.

De todos modos, borrando las advertencias de los genéricos de la respuesta 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 + ')';
    }
}

Adiciones / correcciones muy bienvenidas :) En particular, no estoy muy seguro acerca de mi uso de Pair <?,? > .

Para obtener más información sobre por qué esta sintaxis, consulte Asegúrese de que los objetos implementen Comparable y para obtener una explicación detallada ¿Cómo implementar una función genérica max (Comparable a, Comparable b) en Java?

En mi opinión, no hay un par en Java porque, si desea agregar funcionalidad adicional directamente en el par (por ejemplo, comparable), debe vincular los tipos. En C ++, simplemente no nos importa, y si los tipos que componen un par no tienen operator < , el pair :: operator < tampoco se compilará.

Un ejemplo de Comparable sin límite:

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 ejemplo de Comparable con la verificación en tiempo de compilación para ver si los argumentos de tipo son 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));

Esto es bueno, pero esta vez es posible que no uses tipos no comparables como argumentos de tipo en Pair. Uno puede usar muchos Comparadores para emparejar en alguna clase de utilidad, pero las personas de C ++ pueden no obtenerlo. Otra forma es escribir muchas clases en una jerarquía de tipos con diferentes límites en los argumentos de tipo, pero hay demasiados límites posibles y sus combinaciones ...

JavaFX (que viene incluido con Java 8) tiene el par < A, B > clase

Como muchos otros ya han dicho, realmente depende del caso de uso si una clase Pair es útil o no.

Creo que para una función auxiliar privada es totalmente legítimo usar una clase Pair si eso hace que su código sea más legible y no vale la pena el esfuerzo de crear otra clase de valor con todo su código de placa de caldera.

Por otra parte, si su nivel de abstracción requiere que documente claramente la semántica de la clase que contiene dos objetos o valores, entonces debe escribir una clase para ello. Por lo general, ese es el caso si los datos son un objeto comercial.

Como siempre, requiere un juicio experto.

Para su segunda pregunta, recomiendo la clase Pair de las bibliotecas de Apache Commons. Esos podrían considerarse como bibliotecas estándar extendidas para Java:

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

También puede querer echar un vistazo a Apache Commons ' EqualsBuilder , HashCodeBuilder y ToStringBuilder que simplifica la escritura de clases de valor para sus objetos comerciales.

Buenas noticias Java agregó el valor de clave Pair.

solo importa javafx.util.Pair ;

y usar simplemente como en c ++ .

Pair < Key , Value > 

por ejemplo

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

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

Puede usar la clase de utilidad javafx, Pair que sirve para el mismo propósito que pair < > en c ++. https://docs.oracle.com/javafx/2/api /javafx/util/Pair.html

Map.Entry acercarse bastante al par de c ++. Mire la implementación concreta, como AbstractMap.SimpleEntry y AbstractMap.SimpleImmutableEntry El primer elemento es getKey () y el segundo es getValue ().

Collections.singletonMap(left, rigth);

De acuerdo con la naturaleza del lenguaje Java, supongo que las personas no requieren realmente un Pair , una interfaz suele ser lo que necesitan. Aquí hay un ejemplo:

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

Entonces, cuando las personas desean devolver dos valores, pueden hacer lo siguiente:

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

Esta es una solución bastante liviana y responde a la pregunta " ¿Cuál es la semántica de un Pair < L, R > ? " ;. La respuesta es que se trata de una compilación de interfaz con dos tipos (puede ser diferente) y tiene métodos para devolver cada uno de ellos. Depende de usted agregarle más semántica. Por ejemplo, si está utilizando Posición y REALMENTE desea indicarlo en su código, puede definir PositionX y PositionY que contiene Integer , para cree un Pair < PositionX, PositionY > . Si JSR 308 está disponible, también puede usar Pair < @PositionX Integer, @PositionY Ingeger > para simplificar eso.

EDITAR: Una cosa que debo indicar aquí es que la definición anterior se relaciona explícitamente con el nombre del parámetro de tipo y el nombre del método. Esta es una respuesta a aquellos argumentos en los que un Pair es la falta de información semántica. En realidad, el método getL significa "dame el elemento que corresponde al tipo de parámetro tipo L", que significa algo.

EDITAR: Aquí hay una clase de utilidad simple que puede hacer la vida más fácil:

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

uso:

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

A pesar de ser sintácticamente similares, Java y C ++ tienen paradigmas muy diferentes. Escribir C ++ como Java es malo C ++, y escribir Java como C ++ es malo Java.

Con un IDE basado en la reflexión como Eclipse, escribir la funcionalidad necesaria de un " par " La clase es rápida y sencilla. Cree una clase, defina dos campos, use los distintos "Generar XX" Opciones de menú para completar la clase en cuestión de segundos. Quizás deberías escribir un " compareTo " muy rápido si quisieras la interfaz comparable.

Con las opciones de declaración / definición separadas en el lenguaje, los generadores de códigos C ++ no son tan buenos, por lo que escribir a mano pocas clases de utilidad es más tedioso. Debido a que el par es una plantilla, no tiene que pagar por las funciones que no usa, y la función typedef permite asignar nombres de tipo significativos al código, por lo que las objeciones sobre "no semántica" realmente no aguantar.

El par sería una buena cosa, por ser una unidad básica de construcción para genéricos complejos, por ejemplo, esto es de mi código:

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

Es lo mismo que la Tupla de Haskell

Para lenguajes de programación como Java, la estructura de datos alternativa utilizada por la mayoría de los programadores para representar pares como estructuras de datos son dos matrices, y se accede a los datos a través del mismo índice

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

Esto no es ideal ya que los datos deberían estar unidos, pero también resultan ser bastante baratos. Además, si su caso de uso exige el almacenamiento de coordenadas, es mejor construir su propia estructura de datos.

Tengo algo como esto en mi biblioteca

public class Pair<First,Second>{.. }

Puede usar la biblioteca AutoValue de Google: https://github.com/google/auto / tree / master / value .

Usted crea una clase abstracta muy pequeña y la anota con @AutoValue y el procesador de anotaciones genera una clase concreta para usted que tiene un valor semántico.

Aquí hay algunas bibliotecas que tienen varios grados de tuplas para su conveniencia:

  • JavaTuples . Tuples del grado 1-10 es todo lo que tiene.
  • JavaSlang . Tuplas de grado 0-8 y muchas otras golosinas funcionales.
  • jOO & # 955; . Tuplas de grado 0-16 y algunas otras golosinas funcionales. (Descargo de responsabilidad, trabajo para la empresa mantenedora)
  • Java funcional . Tuplas de grado 0-8 y muchas otras golosinas funcionales.

Se ha mencionado que otras bibliotecas contienen al menos la tupla Pair .

Específicamente, en el contexto de la programación funcional que utiliza una gran cantidad de tipeo estructural, en lugar de tipeo nominal ( como se recomienda en el respuesta aceptada ), esas bibliotecas y sus tuplas son muy útiles.

Brian Goetz, Paul Sandoz y Stuart Marks explican por qué durante la sesión de control de calidad en Devoxx'14 .

Tener una clase de pares genéricos en la biblioteca estándar se convertirá en una deuda técnica una vez que se introduzcan tipos de valor .

Consulte también: ¿Java SE 8 tiene pares o tuplas?

Objeto de manera simple []: se puede utilizar como cualquier tupla de dimensión

Noté que todas las implementaciones de Par esparcidas por aquí atribuyen significado al orden de los dos valores. Cuando pienso en un par, pienso en una combinación de dos elementos en los que el orden de los dos no tiene importancia. Aquí está mi implementación de un par desordenado, con las anulaciones de hashCode y equals para garantizar el comportamiento deseado en las colecciones. También se puede clonar.

/**
 * 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;

    }

}

Esta implementación se ha probado adecuadamente en la unidad y se ha probado su uso en un conjunto y un mapa.

Tenga en cuenta que no pretendo publicar esto en el dominio público. Este es el código que acabo de escribir para su uso en una aplicación, así que si lo va a utilizar, evite hacer una copia directa y meterse un poco con los comentarios y nombres. ¿Atrapas mi deriva?

Si alguien quiere una versión simple y fácil de usar, la puse a disposición en https: / /github.com/lfac-pt/Java-Pair . Además, ¡las mejoras son bienvenidas!

com.sun.tools.javac.util.Pair es una implementación simple de un par. Se puede encontrar en jdk1.7.0_51 \ lib \ tools.jar.

Aparte de org.apache.commons.lang3.tuple.Pair, no es solo una interfaz.

otra implementación concisa de lombok

import lombok.Value;

@Value(staticConstructor = "of")
public class Pair<F, S> {
    private final F first;
    private final S second;
}
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;
    }

}

uso:

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

¡Inmutable, solo un par!

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top