Java中没有Pair<L,R>,有什么好理由吗?与这个c++构造等价的是什么?我宁愿避免重新实现我自己的。

似乎1.6提供了类似的东西(AbstractMap.SimpleEntry<K,V>),但这看起来相当复杂。


当前回答

正如许多人已经指出的那样,Pair类是否有用实际上取决于用例。

我认为,对于私有帮助函数,如果使用Pair类可以使代码更具可读性,并且不值得花费精力创建另一个包含所有锅炉代码的值类,那么使用Pair类是完全合法的。

另一方面,如果您的抽象级别要求您清楚地记录包含两个对象或值的类的语义,那么您应该为它编写一个类。如果数据是业务对象,通常就是这种情况。

一如既往,这需要熟练的判断。

对于你的第二个问题,我推荐Apache Commons库中的Pair类。这些可能被认为是Java的扩展标准库:

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

你可能还想看看Apache Commons的EqualsBuilder、HashCodeBuilder和ToStringBuilder,它们简化了为业务对象编写值类的过程。

其他回答

HashMap兼容Pair类:

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

尽管语法相似,但Java和c++有非常不同的范例。像Java一样写c++是糟糕的c++,像c++一样写Java是糟糕的Java。

使用像Eclipse这样基于反射的IDE,编写“pair”类的必要功能是快速而简单的。创建类,定义两个字段,使用各种“Generate XX”菜单选项在几秒钟内填写类。如果你想要Comparable界面,也许你必须很快地输入一个“compareTo”。

由于c++语言中有单独的声明/定义选项,代码生成器并不是很好,所以手工编写小的实用程序类更加费时乏味。由于pair是一个模板,您不必为不使用的函数付费,并且typedef功能允许为代码分配有意义的类型名,因此关于“无语义”的反对意见并不成立。

根据Java语言的性质,我认为人们实际上并不需要Pair,通常他们需要的是一个接口。这里有一个例子:

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

所以,当人们想要返回两个值时,他们可以这样做:

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

This is a pretty lightweight solution, and it answers the question "What is the semantic of a Pair<L,R>?". The answer is, this is an interface build with two (may be different) types, and it has methods to return each of them. It is up to you to add further semantic to it. For example, if you are using Position and REALLY want to indicate it in you code, you can define PositionX and PositionY that contains Integer, to make up a Pair<PositionX,PositionY>. If JSR 308 is available, you may also use Pair<@PositionX Integer, @PositionY Ingeger> to simplify that.

编辑: 这里我应该指出的一点是,上面的定义显式地将类型参数名和方法名联系起来。这是对那些认为Pair缺乏语义信息的人的回答。实际上,getL方法的意思是“给我对应于类型参数L的类型的元素”,这确实意味着什么。

编辑: 下面是一个简单的实用程序类,可以让生活变得更简单:

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

用法:

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

http://www.javatuples.org/index.html怎么样?我发现它非常有用。

javatuples提供了从一到十个元素的元组类:

Unit<A> (1 element)
Pair<A,B> (2 elements)
Triplet<A,B,C> (3 elements)
Quartet<A,B,C,D> (4 elements)
Quintet<A,B,C,D,E> (5 elements)
Sextet<A,B,C,D,E,F> (6 elements)
Septet<A,B,C,D,E,F,G> (7 elements)
Octet<A,B,C,D,E,F,G,H> (8 elements)
Ennead<A,B,C,D,E,F,G,H,I> (9 elements)
Decade<A,B,C,D,E,F,G,H,I,J> (10 elements)

@Andreas Krey的回答其实很好。任何Java给你带来困难的事情,你都不应该去做。

在我的经验中,Pair最常见的用途是一个方法的多个返回值和hashmap中的values(通常由字符串索引)。

在后一种情况下,我最近使用了一个数据结构,类似这样:

class SumHolder{MyObject trackedObject, double sum};

这是您的整个“Pair”类,与通用的“Pair”类的代码数量几乎相同,但具有描述性名称的优势。它可以在它使用的方法中定义,这将消除公共变量等典型问题。换句话说,对于这种用法,它绝对比一对更好(由于命名的成员),不会更差。

If you actually want a "Pair" for the key of a hashmap you are essentially creating a double-key index. I think this may be the one case where a "Pair" is significantly less code. It's not really easier because you could have eclipse generate equals/hash on your little data class, but it would be a good deal more code. Here a Pair would be a quick fix, but if you need a double-indexed hash who's to say you don't need an n-indexed hash? The data class solution will scale up, the Pair will not unless you nest them!

So the second case, returning from a method, is a bit harder. Your class needs more visibility (the caller needs to see it too). You can define it outside the method but inside the class exactly as above. At that point your method should be able to return a MyClass.SumHolder object. The caller gets to see the names of the returned objects, not just a "Pair". Note again that the "Default" security of package level is pretty good--it's restrictive enough that you shouldn't get yourself into too much trouble. Better than a "Pair" object anyway.

我能看到的另一种情况是使用一个公共api,为当前包之外的调用者提供返回值。为此,我只创建一个真正的对象——最好是不可变的。最终,调用者将共享此返回值,并且使其可变可能会出现问题。这是Pair对象更糟糕的另一种情况——大多数Pair不能被设置为不可变的。

所有这些情况的另一个优点是——java类扩展,我的sum类需要第二个sum和“Created”标记,当我完成时,我将不得不扔掉Pair并使用其他东西,但如果Pair有意义,我的4个值的类至少仍然有意义。