Java 中 C++ Pair<L,R> 的等价物是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/156275/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 09:03:19  来源:igfitidea点击:

What is the equivalent of the C++ Pair<L,R> in Java?

javatuplesstd-pair

提问by David Segonds

Is there a good reason why there is no Pair<L,R>in Java? What would be the equivalent of this C++ construct? I would rather avoid reimplementing my own.

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

It seems that 1.6is providing something similar (AbstractMap.SimpleEntry<K,V>), but this looks quite convoluted.

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

采纳答案by Luc Touraille

In a thread on comp.lang.java.help, Hunter Gratzner gives some arguments against the presence of a Pairconstruct in Java. The main argument is that a class Pairdoesn't convey any semantics about the relationship between the two values (how do you know what "first" and "second" mean ?).

在 上的一个线程中comp.lang.java.help,Hunter Gratzner 给出了一些反对PairJava 中存在构造的论据。主要论点是一个类Pair没有传达任何关于两个值之间关系的语义(你怎么知道“第一”和“第二”是什么意思?)。

A better practice is to write a very simple class, like the one Mike proposed, for each application you would have made of the Pairclass. Map.Entryis an example of a pair that carry its meaning in its name.

更好的做法是为每个应用程序编写一个非常简单的类,就像 Mike 建议的那样PairMap.Entry是一个在其名称中带有其含义的对的示例。

To sum up, in my opinion it is better to have a class Position(x,y), a class Range(begin,end)and a class Entry(key,value)rather than a generic Pair(first,second)that doesn't tell me anything about what it's supposed to do.

总而言之,在我看来,最好有一个 class Position(x,y),一个 classRange(begin,end)和一个 classEntry(key,value)而不是一个Pair(first,second)没有告诉我它应该做什么的泛型。

回答by cletus

It depends on what you want to use it for. The typical reason to do so is to iterate over maps, for which you simply do this (Java 5+):

这取决于你想用它做什么。这样做的典型原因是迭代映射,为此您只需执行以下操作(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());
}

回答by arturh

HashMap compatible Pair class:

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

回答by Illarion Kovalchuk

Pair would be a good stuff, to be a basic construction unit for a complex generics, for instance, this is from my code:

对将是一个好东西,作为复杂泛型的基本构造单元,例如,这是来自我的代码:

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

It is just the same as Haskell's Tuple

和 Haskell 的元组一样

回答by Andreas Krey

This is Java. You have to make your own tailored Pair class with descriptive class and field names, and not to mind that you will reinvent the wheel by writing hashCode()/equals() or implementing Comparable again and again.

这是爪哇。您必须使用描述性的类和字段名称制作自己的定制 Pair 类,并且不要介意您将通过编写 hashCode()/equals() 或一次又一次地实现 Comparable 来重新发明轮子。

回答by Peter Lawrey

Another way to implement Pair with.

实现 Pair with 的另一种方式。

  • Public immutable fields, i.e. simple data structure.
  • Comparable.
  • Simple hash and equals.
  • Simple factory so you don't have to provide the types. e.g. Pair.of("hello", 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 + ')';
        }
    }
    
  • 公共不可变字段,即简单的数据结构。
  • 可比。
  • 简单的哈希和等号。
  • 简单的工厂,因此您不必提供类型。例如 Pair.of("你好", 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 + ')';
        }
    }
    

回答by Testus

Simple way Object [] - can be use as anу dimention tuple

简单的方法 Object [] - 可以用作任何维度元组

回答by MaxBuzz

In my opinion, there is no Pair in Java because, if you want to add extra functionality directly on the pair (e.g. Comparable), you must bound the types. In C++, we just don't care, and if types composing a pair do not have operator <, the pair::operator <will not compile as well.

在我看来,Java 中没有 Pair,因为如果您想直接在 Pair 上添加额外的功能(例如 Comparable),您必须绑定类型。在 C++ 中,我们只是不在乎,如果组成对的类型没有operator <,则pair::operator <也不会编译。

An example of Comparable with no bounding:

一个没有边界的 Comparable 示例:

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

An example of Comparable with compile-time check for whether type arguments are comparable:

Comparable 与编译时检查类型参数是否可比较的示例:

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

This is good, but this time you may not use non-comparable types as type arguments in Pair. One may use lots of Comparators for Pair in some utility class, but C++ people may not get it. Another way is to write lots of classes in a type hierarchy with different bounds on type arguments, but there are too many possible bounds and their combinations...

这很好,但这次你不能在 Pair 中使用不可比较的类型作为类型参数。人们可能会在某些实用程序类中使用大量 Comparator for Pair,但 C++ 人可能不会得到它。另一种方法是在类型层次结构中编写大量具有不同类型参数边界的类,但是可能的边界及其组合太多了......

回答by Michael Piefel

The shortest pair that I could come up with is the following, using Lombok:

我能想出的最短对是以下,使用Lombok

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

It has all the benefits of the answer from @arturh(except the comparability), it has hashCode, equals, toStringand a static “constructor”.

它具有的所有优点的答案从@arturh(可比性除外),它有hashCodeequalstoString和静态的“构造”。

回答by Peter Goetz

As many others have already stated, it really depends on the use case if a Pair class is useful or not.

正如许多其他人已经说过的那样,如果 Pair 类有用与否,这实际上取决于用例。

I think for a private helper function it is totally legitimate to use a Pair class if that makes your code more readable and is not worth the effort of creating yet another value class with all its boiler plate code.

我认为对于私有帮助函数,如果使用 Pair 类使您的代码更具可读性并且不值得用所有样板代码创建另一个值类,那么使用 Pair 类是完全合法的。

On the other hand, if your abstraction level requires you to clearly document the semantics of the class that contains two objects or values, then you should write a class for it. Usually that's the case if the data is a business object.

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

As always, it requires skilled judgement.

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

For your second question I recommend the Pair class from the Apache Commons libraries. Those might be considered as extended standard libraries for Java:

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

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

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

You might also want to have a look at Apache Commons' EqualsBuilder, HashCodeBuilderand ToStringBuilderwhich simplify writing value classes for your business objects.

您可能还想看看 Apache Commons 的EqualsBuilderHashCodeBuilderToStringBuilder,它们简化了为您的业务对象编写值类。