Existe uma boa razão para não existir Pair<L,R>
em Java? Qual seria o equivalente dessa construção C ++? Prefiro evitar reimplementar o meu.
Parece que o 1.6 está fornecendo algo semelhante ( AbstractMap.SimpleEntry<K,V>
), mas isso parece bastante complicado.
AbstractMap.SimpleEntry
complicado?Respostas:
Em um tópico
comp.lang.java.help
, Hunter Gratzner apresenta alguns argumentos contra a presença de umaPair
construção em Java. O argumento principal é que uma classePair
não transmite nenhuma semântica sobre o relacionamento entre os dois valores (como você sabe o que "primeiro" e "segundo" significam?).Uma prática melhor é escrever uma classe muito simples, como a proposta por Mike, para cada aplicativo que você faria da
Pair
classe.Map.Entry
é um exemplo de um par que carrega seu significado em seu nome.Para resumir, na minha opinião, é melhor ter uma classe
Position(x,y)
, uma classeRange(begin,end)
e uma classeEntry(key,value)
do que um genéricoPair(first,second)
que não me diga nada sobre o que deve fazer.fonte
Isto é Java. Você precisa criar sua própria classe Pair personalizada, com nomes descritivos de classe e campo, e não se esqueça de reinventar a roda escrevendo hashCode () / equals () ou implementando Comparable repetidamente.
fonte
SimpleImmutableEntry
Classe de par compatível com HashMap:
fonte
super()
bola. Normalmente, eu apenas cortaria se fosse opcional, como se estivesse aqui.O par mais curto que eu pude criar é o seguinte, usando Lombok :
Possui todos os benefícios da resposta de @arturh (exceto a comparabilidade), possui
hashCode
,equals
,toString
e um “construtor” estática.fonte
O Apache Commons Lang 3.0+ possui algumas classes de pares: http://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/tuple/package-summary.html
fonte
Outra maneira de implementar o Pair with.
Fábrica simples, para que você não precise fornecer os tipos. por exemplo Pair.of ("olá", 1);
fonte
of
. Ele lembra coleções imutáveis do Google Guava .o1
paraComparable
, mesmo que nada indica que ele vai realmente implementar essa interface. Se isso é um requisito, oFIRST
parâmetro type deve serFIRST extends Comparable<?>
.Que tal http://www.javatuples.org/index.html eu achei muito útil.
Os javatuples oferecem classes de tupla de um a dez elementos:
fonte
Pair
e poderia imaginar usarTriplet
talvez uma vez a cada 50 anos. Agora eu uso Lombok e crio uma pequena classe de 4 linhas toda vez que preciso de um par. Então "10 em excesso" é exato.Bottom (0 element)
aula? :)Depende do que você deseja usá-lo. O motivo típico para fazer isso é iterar nos mapas, para os quais você simplesmente faz isso (Java 5+):
fonte
android fornece
Pair
classe ( http://developer.android.com/reference/android/util/Pair.html ), aqui a implementação:fonte
Objects.equal(..)
requer a biblioteca Guava.Objects.equals(...)
que está em Java desde 2011 (1.7).O maior problema é provavelmente que não se pode garantir a imutabilidade em A e B (consulte Como garantir que os parâmetros de tipo sejam imutáveis ), portanto,
hashCode()
pode fornecer resultados inconsistentes para o mesmo par após a inserção em uma coleção, por exemplo (isso daria um comportamento indefinido , consulte Definindo iguais em termos de campos mutáveis ). Para uma classe de par específica (não genérica), o programador pode garantir a imutabilidade escolhendo cuidadosamente A e B para serem imutáveis.Enfim, limpando os avisos de genéricos da resposta de @ PeterLawrey (java 1.7):
Adições / correções muito bem-vindas :) Em particular, não tenho muita certeza sobre meu uso de
Pair<?, ?>
.Para obter mais informações sobre por que essa sintaxe, consulte Garantir que os objetos implementem Comparável e para obter uma explicação detalhada Como implementar uma
max(Comparable a, Comparable b)
função genérica em Java?fonte
Na minha opinião, não há Par em Java porque, se você deseja adicionar funcionalidade extra diretamente ao par (por exemplo, Comparável), deve vincular os tipos. Em C ++, simplesmente não nos importamos e, se os tipos que compõem um par não tiverem
operator <
, opair::operator <
eles também não serão compilados.Um exemplo de Comparável sem limite:
Um exemplo de Comparável com verificação em tempo de compilação para saber se os argumentos de tipo são comparáveis:
Isso é bom, mas desta vez você não pode usar tipos não comparáveis como argumentos de tipo no par. Pode-se usar muitos Comparadores para Par em alguma classe de utilitário, mas as pessoas em C ++ podem não entender. Outra maneira é escrever muitas classes em uma hierarquia de tipos com limites diferentes nos argumentos de tipo, mas existem muitos limites possíveis e suas combinações ...
fonte
O JavaFX (que acompanha o Java 8) possui a classe Pair <A, B>
fonte
hashCode()
. Observe que o próprio Java não chama esse método. É para código de usuário, incluindo bibliotecas.Como muitos outros já declararam, realmente depende do caso de uso se uma classe Pair é útil ou não.
Eu acho que, para uma função auxiliar privada, é totalmente legítimo usar uma classe Pair se isso torna seu código mais legível e não vale a pena o esforço de criar mais uma classe de valor com todo o código da placa da caldeira.
Por outro lado, se o seu nível de abstração exigir que você documente claramente a semântica da classe que contém dois objetos ou valores, você deve escrever uma classe para ele. Normalmente, esse é o caso se os dados forem um objeto de negócios.
Como sempre, requer julgamento qualificado.
Para sua segunda pergunta, recomendo a classe Pair das bibliotecas Apache Commons. Essas podem ser consideradas bibliotecas padrão estendidas para Java:
https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/tuple/Pair.html
Você também pode dar uma olhada no EqualsBuilder , no HashCodeBuilder e no ToStringBuilder do Apache Commons , que simplificam a gravação de classes de valor para seus objetos de negócios.
fonte
Você pode usar a classe de utilitário javafx,
Pair
que serve ao mesmo propósito que o par <> no c ++. https://docs.oracle.com/javafx/2/api/javafx/util/Pair.htmlfonte
Boas notícias
JavaFX
tem um valor-chave Par.basta adicionar javafx como uma dependência e importar
javafx.util.Pair
;e use simplesmente como em
c++
.por exemplo
fonte
A interface Map.Entry chega bem perto do par de c ++. Observe a implementação concreta, como AbstractMap.SimpleEntry e AbstractMap.SimpleImmutableEntry O primeiro item é getKey () e o segundo é getValue ().
fonte
fonte
De acordo com a natureza da linguagem Java, suponho que as pessoas não precisem realmente de
Pair
uma interface, geralmente é o que precisam. Aqui está um exemplo:Portanto, quando as pessoas desejam retornar dois valores, podem fazer o seguinte:
Essa é uma solução bastante leve e responde à pergunta "Qual é a semântica de a
Pair<L,R>
?". A resposta é: esta é uma interface criada com dois tipos (podem ser diferentes) e possui métodos para retornar cada um deles. Cabe a você adicionar mais semântica a ele. Por exemplo, se você estiver usando Position e REALMENTE quiser indicá-lo em seu código, poderá definirPositionX
ePositionY
que contémInteger
, para compor aPair<PositionX,PositionY>
. Se o JSR 308 estiver disponível, você também poderá usá-loPair<@PositionX Integer, @PositionY Ingeger>
para simplificar isso.EDIT: Uma coisa que devo indicar aqui é que a definição acima relaciona explicitamente o nome do parâmetro type e o nome do método. Esta é uma resposta para aqueles que argumentam que a
Pair
é falta de informação semântica. Na verdade, o métodogetL
significa "me dê o elemento que corresponde ao tipo de parâmetro do tipo L", o que significa alguma coisa.EDIT: Aqui está uma classe de utilitário simples que pode facilitar a vida:
uso:
fonte
equals
,hashCode
etoString
?toString
você precisa de mais conhecimento sobre o relacionamento entre os dois campos.class
pode ser melhor do que apenas um,interface
porque ele pode implementar essas coisas.Apesar de sintaticamente semelhantes, Java e C ++ têm paradigmas muito diferentes. Escrever C ++ como Java é ruim em C ++ e escrever Java como C ++ é ruim em Java.
Com um IDE baseado em reflexão como o Eclipse, escrever a necessariamente funcionalidade de uma classe "pair" é rápido e simples. Crie uma classe, defina dois campos, use as várias opções de menu "Gerar XX" para preencher a classe em questão de segundos. Talvez você precise digitar um "compareTo" rapidamente, se quiser a interface comparável.
Com opções separadas de declaração / definição na linguagem, os geradores de código C ++ não são tão bons, então escrever manualmente pequenas classes de utilitário consome mais tempo de tédio. Como o par é um modelo, você não precisa pagar pelas funções que não usa, e o recurso typedef permite atribuir nomes de tipos significativos ao código, de modo que as objeções sobre "semântica" não se sustentam.
fonte
Par seria uma coisa boa, para ser uma unidade básica de construção para genéricos complexos, por exemplo, isto é do meu código:
É exatamente o mesmo que Tuple de Haskell
fonte
Pair
é ideal, pois não há semântica especial. Ter um nome claro para um conceito claro é bom, mas procurar um nome onde "primeiro" e "segundo" funcionem bem não é.Objeto de maneira simples [] - pode ser usado como qualquer tupla de dimensão
fonte
Para linguagens de programação como Java, a estrutura de dados alternativa usada pela maioria dos programadores para representar estruturas de dados pareadas é de duas matrizes e os dados são acessados através do mesmo índice
exemplo: http://www-igm.univ-mlv.fr/~lecroq/string/node8.html#SECTION0080
Isso não é ideal, pois os dados devem ser unidos, mas também se mostram bastante baratos. Além disso, se o seu caso de uso exigir armazenamento de coordenadas, é melhor criar sua própria estrutura de dados.
Eu tenho algo assim na minha biblioteca
fonte
Você pode usar a biblioteca AutoValue do Google - https://github.com/google/auto/tree/tree/master/value .
Você cria uma classe abstrata muito pequena e a anota com @AutoValue, e o processador de anotações gera uma classe concreta para você que possui um valor semântico.
fonte
Aqui estão algumas bibliotecas que possuem vários graus de tuplas para sua conveniência:
Outras bibliotecas foram mencionadas para conter pelo menos a
Pair
tupla.Especificamente, no contexto da programação funcional que faz uso de muitas tipologias estruturais, em vez de tipologias nominais ( como preconizado na resposta aceita ), essas bibliotecas e suas tuplas são muito úteis.
fonte
Brian Goetz, Paul Sandoz e Stuart Marks explicam por que durante a sessão de controle de qualidade na Devoxx'14.
Ter classe genérica de pares na biblioteca padrão se transformará em dívida técnica assim que os tipos de valor forem introduzidos.
Consulte também: O Java SE 8 possui pares ou tuplas?
fonte
outra implementação concisa do lombok
fonte
Notei que todas as implementações de Pair espalhadas por aqui atribuem significado à ordem dos dois valores. Quando penso em um par, penso em uma combinação de dois itens em que a ordem dos dois não tem importância. Aqui está minha implementação de um par não ordenado, com
hashCode
eequals
substituições para garantir o comportamento desejado nas coleções. Também clonável.Essa implementação foi testada adequadamente e o uso em um conjunto e mapa foi testado.
Observe que não estou afirmando liberar isso em domínio público. Este é o código que acabei de escrever para uso em um aplicativo. Portanto, se você for usá-lo, evite fazer uma cópia direta e mexa um pouco nos comentários e nomes. Pegar a minha deriva?
fonte
Se alguém quiser uma versão simples, fácil de usar, disponibilizei-a em https://github.com/lfac-pt/Java-Pair . Além disso, melhorias são muito bem-vindas!
fonte
com.sun.tools.javac.util.Pair é uma implementação simples de um par. Pode ser encontrado em jdk1.7.0_51 \ lib \ tools.jar.
Além do org.apache.commons.lang3.tuple.Pair, não é apenas uma interface.
fonte
uso:
Imutável, apenas um par!
fonte
Pair<Object, Object> pair = Pair.createPair("abc", "def")
mas acho que é preciso escreverPair.createPair((Object)"abc", (Object)"def")
com seu código?@SuppressWarnings("unchecked") public static <K, V, X, Y> Pair<X, Y> createPair(K key, V value) { return new Pair<X, Y>((X) key, (Y) value); }
mas eu não sei se é uma boa práticanew Pair<Object, Object>("abc", "def")
foi o mais confiável em meus experimentos.