Pergunta

Há uma boa razão pela qual não há Pair<L,R> em Java? Qual seria o equivalente a esta construção C ++? Eu preferiria evitar reimplementar o meu próprio.

Parece que 1,6 está fornecendo algo semelhante (AbstractMap.SimpleEntry<K,V>), mas isso parece muito complicado.

Foi útil?

Solução

Na uma discussão sobre comp.lang.java.help , Hunter Gratzner dá alguns argumentos contra a presença de uma construção Pair em Java. O principal argumento é que uma Pair classe não transmitir qualquer semântica sobre a relação entre os dois valores (como você sabe o que "primeiro" e "segundo" significa?).

A melhor prática é escrever uma classe muito simples, como o Mike proposta, para cada aplicativo que você teria feito da classe Pair. Map.Entry é um exemplo de um par que carregam o seu significado em seu nome.

Para resumir, em minha opinião, é melhor ter um Position(x,y) classe, um Range(begin,end) classe e um Entry(key,value) classe em vez de um Pair(first,second) genérico que não me diz nada sobre o que é suposto fazer.

Outras dicas

Esta é Java. Você tem que fazer sua própria classe Par costurado com nomes de classe e de campo descritivos, e não a mente que você vai reinventar a roda escrevendo hashCode () / é igual a () ou implementar Comparável novamente e novamente.

HashMap compatível classe Par:

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

O par mais curto que eu poderia vir acima com é o seguinte, usando Lombok :

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

Ele tem todos os benefícios de a resposta de @arturh (exceto a comparabilidade), tem hashCode, equals, toString e um “construtor” estático.

Outra forma de implementar par com.

  • campos imutáveis ??públicos, ou seja, estrutura de dados simples.
  • Comparável.
  • haxixe Simples e iguais.
  • Simples fábrica, assim você não tem que fornecer os tipos. por exemplo. Pair.of ( "Olá", 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 + ')';
        }
    }
    

Como sobre http://www.javatuples.org/index.html eu encontrei que é muito útil.

Os javatuples ofertas que você tupla de aulas de um para elementos dez:

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 do que você quer usá-lo. O motivo comum de fazer isso é fazer uma iteração através de mapas, para que você simplesmente fazer isso (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 fornece Pairclass ( http://developer.android.com/reference/android/util/Pair .html ), aqui a implementação:

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

O maior problema é provavelmente que não se pode garantir a imutabilidade em A e B (ver Como garantir que os parâmetros de tipo são imutáveis ??) para hashCode() podem dar resultados inconsistentes para o mesmo par após é inserido em uma coleção, por exemplo, (isso daria indefinido comportamento, consulte Defining iguais em termos de campos mutáveis ??). Para um particular (não genérico) class Par o programador pode garantir imutabilidade escolhendo cuidadosamente A e B para ser imutável.

De qualquer forma, limpando as advertências de genéricos de resposta da @ 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 + ')';
    }
}

As adições / correções muito bem-vindos :) Em particular, eu não estou muito certo sobre o meu uso de Pair<?, ?>.

Para mais informações sobre por que esta sintaxe ver Garantir que os objetos implementar Comparable e para uma explicação detalhada How para implementar uma função max(Comparable a, Comparable b) genérica em Java?

Na minha opinião, não há Par em Java, porque, se você quiser adicionar funcionalidades extras diretamente no par (por exemplo comparável), você deve obrigado os tipos. Em C ++, nós simplesmente não se importam, e se os tipos que compõem um par não tem operator <, o pair::operator < não irá compilar também.

Um exemplo de Comparável sem delimitadora:

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

Um exemplo de Comparável com verificação em tempo de compilação para se argumentos de tipo são comparáveis:

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

Isso é bom, mas desta vez você não pode usar tipos não-comparáveis ??como argumentos de tipo no par. Pode-se usar muita comparadores para o par de alguma classe de utilitário, mas as pessoas C ++ não pode obtê-lo. Outra maneira é lotes de gravação de aulas em uma hierarquia de tipos com diferentes limites sobre argumentos de tipo, mas existem muitos limites possíveis e suas combinações ...

JavaFX (que vem com Java 8) tem o Par class

Como muitos outros já disse, ele realmente depende do caso de uso se uma classe Pair é útil ou não.

Eu acho que para uma função auxiliar privado é totalmente legítimo usar uma classe Par se isso faz seu código mais legível e não vale a pena o esforço de criar ainda uma outra classe de valor com todos os códigos sua placa de caldeira.

Por outro lado, se o seu nível de abstração requer que você documentar claramente a semântica da classe que contém dois objetos ou valores, então você deve escrever uma classe para ele. Normalmente, esse é o caso, se os dados é um objeto de negócios.

Como sempre, ele exige o julgamento qualificado.

Para sua segunda pergunta, eu recomendo a classe Pair as bibliotecas Apache Commons. Aqueles pode ser considerado como bibliotecas extendida para Java:

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

Você também pode querer dar uma olhada no Apache Commons' EqualsBuilder , HashCodeBuilder e ToStringBuilder que simplifica a escrita classes de valor para os seus objetos de negócios.

Good News Java valor acrescentado chave Pair.

Basta importar javafx.util.Pair;

e uso simplesmente como em c++.

Pair < Key , Value > 

por exemplo.

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

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

Você pode usar classe de utilitário javafx, Pair que tem a mesma finalidade como par <> em C ++. https://docs.oracle.com/javafx/2/api /javafx/util/Pair.html

Map.Entry Interface vêm muito perto de c ++ par. Olhe para a implementação concreta, como AbstractMap.SimpleEntry e AbstractMap.SimpleImmutableEntry Primeiro item é getKey () ea segunda é getValue ().

Collections.singletonMap(left, rigth);

De acordo com a natureza da linguagem Java, acho que as pessoas realmente não exigem um Pair, uma interface é geralmente o que eles precisam. Aqui está um exemplo:

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

Assim, quando as pessoas querem retornar dois valores que podem fazer o seguinte:

... //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 é uma solução muito leve, e ele responde à pergunta "Qual é a semântica de um Pair<L,R>?". A resposta é, esta é uma compilação de interface com duas (pode ser diferente) tipos, e que tem métodos para retornar cada um deles. Cabe a você adicionar mais semântica para ele. Por exemplo, se você estiver usando posição e realmente quer para indicar isso em você código, você pode definir PositionX e PositionY que contém Integer, para fazer um Pair<PositionX,PositionY>. Se JSR 308 está disponível, você também pode usar Pair<@PositionX Integer, @PositionY Ingeger> para simplificar isso.

EDIT: Uma coisa que eu deve indicar aqui é que a definição acima se refere explicitamente o nome do parâmetro tipo e o nome do método. Esta é uma resposta àqueles argumenta que uma Pair é a falta de informação semântica. Na verdade, o método meios getL "me dar o elemento que correspondem ao tipo de tipo de parâmetro L", o que fazer significa alguma coisa.

EDIT: Aqui é uma classe utilitário simples que pode tornar a vida mais 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");

Apesar de ser sintaticamente semelhante, Java e C ++ têm muito diferentes paradigmas. Escrita C ++ como Java é ruim C ++, e escrevendo Java como C ++ é ruim Java.

Com um IDE baseado reflexão como Eclipse, escrevendo o necessariamente a funcionalidade de uma classe "par" é rápido e simples. Criar classe, definir dois campos, use os vários "Gerar XX" opções de menu para preencher a classe em questão de segundos. Talvez você tem que digitar um "compareTo" quick real, se você queria a interface Comparable.

Com opções de declaração / definição separada na linguagem C ++ geradores de código não são tão bom, tão mão escrevendo pequenas classes de utilitários é mais tempo tédio consumindo. Porque o par é um modelo, você não tem que pagar por funções que você não usa, e a facilidade typedef permite atribuir typenames significativas para o código, de modo que as objeções sobre "sem semântica" realmente não realizar-se.

Par seria uma coisa boa, para ser uma unidade de construção básico para um genéricos complexos, por exemplo, isso é do meu código:

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

É o mesmo que Tuple de Haskell

para linguagens de programação como Java, a estrutura de dados alternativo utilizado pela maioria dos programadores para representar dados como par-estruturas são dois matriz, e de dados é acedida através do mesmo índice

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

Este não é o ideal, como os dados devem ser unidos, mas também acabam por ser muito barato. Além disso, se seu caso de uso exige o armazenamento de coordenadas, em seguida, o seu melhor para construir a sua própria estrutura de dados.

Eu tenho algo parecido com isso em minha biblioteca

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

Você pode usar a biblioteca autovalor do Google - https://github.com/google/auto / árvore / master / valor .

Você cria uma pequena classe abstrata e anotá-lo com @AutoValue e o processador de anotação gera uma classe concreta para você que tem um valor semântico.

Aqui estão algumas bibliotecas que têm vários graus de tuplas para sua conveniência:

  • JavaTuples . Tuples de grau 1-10 é tudo o que tem.
  • JavaSlang . Tuples de grau 0-8 e lotes de outros presentes funcionais.
  • jOO? . Tuples de grau 0-16 e algumas outras guloseimas funcionais. (Disclaimer, eu trabalho para a empresa mantenedor)
  • Funcional Java. Tuples de grau 0-8 e lotes de outros presentes funcionais.

Outras bibliotecas foram mencionados para conter pelo menos a tupla Pair.

Especificamente, no contexto de programação funcional que faz uso de uma grande quantidade de tipagem estrutural, em vez de tipagem nominal ( tal como preconizado na aceita resposta ), as bibliotecas e seus tuples vir em muito acessível.

Brian Goetz, Paul Sandoz e Stuart marcas explicar por que durante a sessão de QA na Devoxx'14 .

Tendo classe par genérico na biblioteca padrão vai se transformar em dívida técnica uma vez tipos de valor introduzido .

Veja também: O Java SE 8 tem Pairs ou Tuples?

Simples maneira Object [] - pode ser usado como an? dimensão tupla

notei todas as implementações Par sendo espalhados por aqui atributo significado para a ordem dos dois valores. Quando eu penso de um par, eu acho que de uma combinação de dois itens em que a ordem dos dois é de nenhuma importância. Aqui está minha implementação de um par não ordenada, com hashCode e equals substituições para assegurar o comportamento desejado em coleções. Também cloneable.

/**
 * 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 implementação foi devidamente unidade testada eo uso em um conjunto e Mapa foi experimentado.

Observe que eu não estou reivindicando para liberar isso no domínio público. Este é o código que eu acabei de escrever para uso em um aplicativo, por isso, se você estiver indo para usá-lo, por favor, abster-se de fazer uma cópia direta e mexer sobre com os comentários e nomes de um bit. Me entende?

Se alguém quer um morto-simples e fácil para a versão uso eu fiz o meu disponível em https: / /github.com/lfac-pt/Java-Pair . Além disso, as melhorias são muito bem-vindos!

com.sun.tools.javac.util.Pair é uma implementação simples de um par. Ela pode ser encontrada em jdk1.7.0_51 \ lib \ tools.jar.

Além do org.apache.commons.lang3.tuple.Pair, não é apenas uma interface.

outra implementação concisa 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();

Imutável, a apenas um par!

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top