JavaのC ++ Pair <L、R>に相当するものは何ですか?


670

Pair<L,R>Javaにない理由はありますか?このC ++構成に相当するものは何でしょうか?自分で実装することは避けたいです。

と思われる1.6は、似たような(提供されるAbstractMap.SimpleEntry<K,V>)が、このルックスはかなり回旋します。


7
なぜAbstractMap.SimpleEntry複雑なのですか?
CurtainDog 2012年

27
namigのため、1つのキーと1つの値に任意の名前を付けます。
Enerccio 2014


2
@sffc JavaFXは、JDK7のデフォルトのクラスパスのいずれにもありません。これを使用するには、JFXランタイムライブラリを手動で追加する必要があります。
Cord Rehn、2016年

3
@Enerccio:では、「最初」と「2番目」は恣意的ではないが、「キー」と「値」は実際にそうであると実際に述べている-ですか?次に、これがSDKにそのようなクラスがないことの1つの理由です。「適切な」ネーミングについては、永続的な論争があるでしょう。
fdreger

回答:


400

上糸comp.lang.java.help、ハンターGratznerはの存在に対するいくつかの引数与えPairJavaで構造物を。主な議論は、クラスPairが2つの値の関係についてのセマンティクスを伝えないということです(「最初」と「2番目」の意味をどのようにして知るのですか?)。

より良い方法は、Mikeが提案したような非常に単純なクラスを、クラスで作成したアプリケーションごとに作成することですPairMap.Entry名前に意味があるペアの例です。

要約すると、私の意見では、クラスPosition(x,y)、クラスRange(begin,end)、およびクラスをEntry(key,value)用意する方が、Pair(first,second)何をすべきかについて何も教えてくれないジェネリックよりも優れています。


143
グラッツナーは髪の毛を分割しています。クラスにカプセル化せずに、単一の値をプリミティブクラスまたは組み込みクラスとして返すことができてとてもうれしいです。ダースの要素のタプルを返すとしたら、誰も反対しないでしょう。それは独自のクラスを持つべきです。真ん中のどこかに(あいまいな)分割線があります。私たちのトカゲの脳はペアを十分簡単に​​処理できると思います。
Ian

25
私はイアンに同意します。Javaでは、intを返すことができます。使用するたびにintのエイリアスを作成する必要はありません。ペアはそれほど違いはありません。
クレマン

5
ペアを直接ローカル変数にアンパックしたり、2つの引数を取るメソッドに転送したりできる場合、ペアは便利なクラスになります。このようにアンパックすることはできないため、意味のあるクラスを作成して値をまとめても、それほど悪くはありません。また、制限にもかかわらず本当にペアが必要な場合は、常にObject [2] +キャスト:-)があります
marcus

重要なのは、グラッツナーに同意しない場合、いくつかの場所にペアの実装があることです。Apache CommonsとGuavaはどちらもIIRCを持っています。それらを使用してください。しかし、メインのJavaライブラリに何かを入れるということは、それが(大文字で)気高い承認済みの方法であることを意味し、人々はそれに同意しないので、そこに置くべきではありません。古いlibには十分な残骸があるので、不必要にそれを追加しないでください。
HaakonLøtveit2017

1
@Dragas私が値のペアを必要とするとき、それはJavaではありません...真剣に?
idclev 463035818

156

これはJavaです。説明的なクラス名とフィールド名を使用して、独自の調整済みPairクラスを作成する必要があります。hashCode()/ equals()を記述するか、Comparableを何度も実装することにより、ホイールを再発明することを気にしないでください。


61
それは「なぜ」という質問には答えません。(「これはJava」の答えだと思わない限り)
Nikita Rybak '23

127
+1は、Javaの冗長性をあざけるためのものです。実際に質問に答えない場合は-1。
Bennett McElwee

19
Pairクラスが含まれているApache Commong Langをポイントしていれば、Javaの模造品は問題ありませんでした。
ヘイレム2012

6
または、次のように使用することもできますSimpleImmutableEntry
CurtainDog 2012年

33
最初の文は、「なぜ」という質問に答えます。これはJavaです。それだけです。
masterziv

103

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

136
おそらく、セッターを削除して、最初と2番目をファイナルにして、ペアを不変にする必要があります。(ハッシュキーとして使用した後にコンポーネントを変更した場合、奇妙なことが起こります)。
ティロ

21
toString()メソッドで "(" + first.toString()+ "、" + second.toString()+ ")"を返すと、NullPointerExceptionsがスローされる場合があります。これはより良い: "(" + first + "、" + second + ")"を返す;
JuhaSyrjälä、2009

6
また、ペアを「最終」としてマークするか、等しいの最初の行を「if(other!= null && this.getClass()== other.getClass())」に変更します
sargas

8
ランダムなnoobyの質問で申し訳ありませんが、なぜコンストラクタでsuper()への呼び出しがあるのですか?
イブラヒム

6
@イブラヒム:この場合、それは不必要です---あなたがsuper()取り出した場合の動作はまったく同じです。それがここにあるように、それがオプションであるなら、私は通常それを捨てます。
Chris Jester-Young

53

私が思いつくことができる最短のペアは、ロンボクを使用した次のものです:

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

これは、のすべての利点がある@arturhから答えを、それが持っている(比較を除く)hashCodeequalstoStringおよび静的な「コンストラクタ」。


気の利いた!好きでした!
アフメットイプキン


31

ペアリングを実装する別の方法。

  • パブリックな不変フィールド、つまり単純なデータ構造。
  • 同程度の。
  • 単純なハッシュと等しい。
  • 単純なファクトリなので、型を指定する必要はありません。例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 + ')';
        }
    }

10
静的なファクトリーメソッドが好きofです。Google Guavaの不変のコレクションを思い出させます
JarekPrzygódzki11年

7
ある時点でにキャストo1Comparableていますが、実際にそのインターフェースを実装することを示すものはありません。それが要件である場合、FIRSTtypeパラメータはにする必要がありますFIRST extends Comparable<?>
G_H

私はJavaの人ではないので、私の無知を許してください。しかし、TODOのコメントでどのようなヘルパークラスを考えていましたか?

3
31はhashCodeの悪い定数です。たとえば、2DマップにPair <Integer、Integer>でキー設定されたHashMapを使用すると、多くの衝突が発生します。たとえば、(a * 65497)^ bの方が適しています。
のMichałZieliński

1
@MarioCarneiro ^ XOR、ない力がある
のMichałZieliński

27

http://www.javatuples.org/index.htmlはどうですか私はそれが非常に有用であることが分かってきました。

javatuplesは、1から10要素までのタプルクラスを提供します。

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)

6
おかしいですが、想像以上に使用できるクラスが少なくとも5つあります。
maaartinus

3
@maaartinus私が使用するよりも少なくとも10多い。
Boann、2014年

7
@Boann:わかりました。修正し続けます。私は以前使用してPairおりTriplet、50年に1回程度使用することを想像できました。次に、Lombokを使用して、ペアが必要になるたびに小さな4行クラスを作成します。したがって、「10が多すぎる」は正確です。
maaartinus 2014年

5
Bottom (0 element)クラスが必要ですか?:)
Earth Engine

2
うわーこれは醜いです。私は彼らがそれを明示的にしようとしていることを知っていますが、C#のようなオーバーロードされたパラメーターを持つタプルはより良いでしょう。
arviman 2016年

12

何に使いたいかによります。これを行う一般的な理由は、マップを反復処理することです。これを行うには、これを行うだけです(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());
}

1
この場合、カスタムクラスが役立つとは思いません:)
Nikita Rybak '23

31
「そうする典型的な理由は、マップを反復することです」。本当に?
Bennett McElwee

12

androidはPairクラスを提供します(http://developer.android.com/reference/android/util/Pair.html)、ここでは実装:

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

1
Objects.equal(..)Guavaライブラリが必要です。
Markus L

3
Objects.equals(...)2011年(1.7)以降にJavaで使用されているものに変更します。
AndrewF 2018年

9

最大の問題はおそらく、AとBの不変性を保証できないことです(「型パラメーターが不変であることを確認する方法」を参照)。たとえば、コレクションに挿入されたhashCode()、同じペアに対して一貫性のない結果が生じる可能性があります(これにより、未定義の動作が発生します) 、可変フィールドの観点から等しいの定義を参照)。特定の(汎用ではない)Pairクラスの場合、プログラマーは、AとBを不変に注意深く選択することにより、不変性を確保できます。

とにかく、@ 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 + ')';
    }
}

追加/修正は大歓迎です:)特に私は私の使用についてはよくわかりません Pair<?, ?>

この構文の詳細については、オブジェクトがComparable実装することを確認するおよび詳細な説明については、Javaでジェネリック関数を実装する方法を参照してくださいmax(Comparable a, Comparable b)


Java整数は32ビットなので、最初のハッシュコードを31倍すると、オーバーフローすることになりますか?排他的ORを実行する方が良いでしょうか?
Dan

@Danは自由に編集してJavaから離れました:)
Mr_and_Mrs_D

5

私の意見では、Javaにペアはありません。ペアに直接追加機能を追加したい場合(たとえば、比較可能)、型をバインドする必要があるためです。C ++では気にしません。ペアを構成する型にがない場合はoperator <pair::operator <もコンパイルされません。

境界のない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));

型引数が比較可能かどうかをコンパイル時にチェックする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));

これは良いことですが、今回は比較できない型をペアの型引数として使用することはできません。いくつかのユーティリティクラスでペア用のコンパレータをたくさん使用するかもしれませんが、C ++の人々はそれを取得しないかもしれません。別の方法は、型引数の境界が異なる型階層に多くのクラスを書き込むことですが、境界とそれらの組み合わせが多すぎます...


5

JavaFX(Java 8にバンドルされている)にはPair <A、B>クラスがあります


1
javafx.util.Pair内のhashCodeの実装は些細な例の衝突につながることができます。HashMap / HashTableでの使用は、Javaがハッシュコードに加えて値の同等性をチェックするため、引き続き機能しますが、注意が必要です。
sffc 2015年

これは非常に標準的で一般的に推奨されるhashCode実装です。衝突がが期待されなければならない任意の呼び出すコードhashCode()。Java自体はこのメソッドを呼び出さないことに注意してください。ライブラリを含むユーザーコード用です。
AndrewF 2018年

5

他の多くの人がすでに述べたように、Pairクラスが役立つかどうかはユースケースに本当に依存しています。

プライベートヘルパー関数の場合、コードを読みやすくし、すべてのボイラープレートコードでさらに別の値クラスを作成する労力に値しない場合、Pairクラスを使用することは完全に正当だと思います。

一方、抽象化レベルで2つのオブジェクトまたは値を含むクラスのセマンティクスを明確に文書化する必要がある場合は、そのためのクラスを作成する必要があります。通常、データがビジネスオブジェクトの場合です。

いつものように、熟練した判断が必要です。

2番目の質問については、Apache CommonsライブラリのPairクラスをお勧めします。これらは、Javaの拡張標準ライブラリと見なされます。

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

また、ビジネスオブジェクトの値クラスの記述を簡略化するApache CommonsのEqualsBuilderHashCodeBuilder、およびToStringBuilderを確認することもできます。


commons-lang3はベータ版ではないため、更新されたURLはcommons.apache.org/lang/api-release/index.html?org/apache/…です。すでにコモンズ・ラング3.使用している場合これは私自身のロンボク島のソリューションよりもさらに短い
マイケルPiefel


5

良いニュース JavaFXにはキーバリューペアがあります。

依存関係としてjavafxを追加してインポートするだけです javafx.util.Pairです。

と単純に使用しc++ます。

Pair <Key, Value> 

例えば

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

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

悪いニュースは、誰もがJavaFXのを使用していることである
のMichałDobiDobrzańskiは

4

Map.Entryインターフェイスは、C ++のペアに非常に近くなります。AbstractMap.SimpleEntryやAbstractMap.SimpleImmutableEntry などの具体的な実装を見てください。最初の項目はgetKey()で、2番目の項目はgetValue()です。


1
OPはすでにこのオプションを認識しており、詳細に議論されました。
キーガン


3

Java言語の性質によると、私は人々が実際にはを必要としないと思いPairますが、インターフェースは通常彼らが必要とするものです。次に例を示します。

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

したがって、2つの値を返したい場合は、次のようにできます。

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

これはかなり軽量なソリューションであり、「aのセマンティクスは何Pair<L,R>ですか?」という質問に答えます。答えは、これは2つの(異なる場合がある)タイプで構築されたインターフェースであり、それぞれを返すメソッドを持っているということです。さらにセマンティックを追加するのはあなた次第です。たとえば、Positionを使用していて、コードでそれを示す必要がある場合は、を定義しPositionXPositionYそれを含むことでInteger、を構成できますPair<PositionX,PositionY>。JSR 308が利用可能な場合は、Pair<@PositionX Integer, @PositionY Ingeger>を簡略化するためにする。

編集:ここで指摘すべきことの1つは、上記の定義が型パラメーター名とメソッド名を明示的に関連付けることです。これはa 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");

何についてequalshashCodeおよびtoString
sdgfsdh 2017年

まあ、これは単なる最小限の実装です。それ以上必要な場合は、ヘルパー関数を簡単に作成できますが、それでもコードを作成する必要があります。
アースエンジン

実装toStringするには、2つのフィールド間の関係についてさらに知識が必要です。
Earth Engine

私のポイントは、aを提供することはこれらのものを実装できるためclass、単なるa よりも優れているかもしれないというinterfaceことです。
sdgfsdh 2017年

3

構文的には似ていますが、JavaとC ++には非常に異なるパラダイムがあります。JavaのようにC ++を書くのは悪いC ++であり、C ++のようにJavaを書くのは悪いJavaです。

EclipseのようなリフレクションベースのIDEを使用すると、「ペア」クラスの機能を作成することが迅速かつ簡単になります。クラスを作成し、2つのフィールドを定義し、さまざまな「XXを生成」メニューオプションを使用して、ほんの数秒でクラスに入力します。Comparableインターフェースが必要な場合は、「compareTo」をすばやく入力する必要があるかもしれません。

言語の個別の宣言/定義オプションを使用すると、C ++コードジェネレーターはあまり良くないので、小さなユーティリティクラスを手書きで書くのは時間のかかる退屈な作業です。ペアはテンプレートであるため、使用しない関数に料金を支払う必要はありません。typedef機能を使用すると、コードに意味のある型名を割り当てることができるため、「セマンティクスがない」という異論は実際には成り立ちません。


2

ペアは良いものであり、複雑なジェネリックの基本的な構築単位になるでしょう。たとえば、これは私のコードからです:

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

Haskellのタプルと同じです


1
今私は、Pair <A、B>を使用するとコードの情報が少なくなり、Pairを使用する代わりに特別なオブジェクトを実装する方がはるかに優れていると言える
Illarion Kovalchuk

1
良くも悪くも。2つの引数を組み合わせる関数(たとえば、グラフを1つにマージする)があり、それをキャッシュする必要があるとします。ここでPairは、特別なセマンティクスがないため、最適です。明確な概念に対して明確な名前を付けることは良いことですが、「1番目」と「2番目」がうまく機能する名前を探すのはよくありません。
maaartinus

2

シンプルな方法Object []-注釈タプルとして使用できます


2
はい、どんな次元でも。しかし:作成が面倒で、タイプセーフではありません。
Michael Piefel

2

Javaのようなプログラミング言語の場合、ほとんどのプログラマーがデータ構造のようなペアを表すために使用する代替データ構造は2つの配列であり、データは同じインデックスを介してアクセスされます

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

データを結合する必要があるため、これは理想的ではありませんが、かなり安価であることがわかります。また、ユースケースで座標の格納が必要な場合は、独自のデータ構造を構築することをお勧めします。

私のライブラリにはこのようなものがあります

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

2

GoogleのAutoValueライブラリ-https : //github.com/google/auto/tree/master/valueを使用できます

非常に小さな抽象クラスを作成し、@ AutoValueで注釈を付けると、注釈プロセッサが値の意味を持つ具象クラスを生成します。


2

以下は、利便性のために複数のタプルを持つライブラリの一部です。

  • JavaTuples。1次から10次のタプルだけです。
  • JavaSlang。0度から8度のタプルと、他の多くの機能的なグッズ。
  • jOOλ。度0-16のタプルといくつかの他の機能的なグッズ。(免責事項、私はメンテナー会社で働いています)
  • 機能的なJava。0度から8度のタプルと、他の多くの機能的なグッズ。

他のライブラリは少なくともPairタプルを含むと述べられています。

特に、公認の型付けではなく(受け入れられた回答で推奨されているように)構造型の多くを利用する関数型プログラミングのコンテキストでは、これらのライブラリーとそのタプルは非常に便利です。



2

別の簡潔なロンボク実装

import lombok.Value;

@Value(staticConstructor = "of")
public class Pair<F, S> {
    private final F first;
    private final S second;
}

1

私はすべてのペアの実装がここに散らばっていることに気づきました。これは、2つの値の順序に意味を与えます。ペアを考えるとき、2つのアイテムの組み合わせを考えます。2つのアイテムの順序は重要ではありません。ここで、順序付けられていないペアの私の実装だhashCodeequalsコレクションに目的の動作を保証するためにオーバーライド。クローンも可能です。

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

    }

}

この実装は適切にユニットテストされており、セットとマップでの使用が試されています。

これをパブリックドメインでリリースすることを主張していないことに注意してください。これは、アプリケーションで使用するために記述したばかりのコードです。そのため、これを使用する場合は、直接コピーを作成しないでください。コメントや名前を少し変更してください。私のドリフトをキャッチ?


3
実際には、各ページの下部を確認してください。「cc-wikiに基づいてライセンスされたユーザーの貢献」
amara '30

ああ、気づかなかった。ヘッドアップをありがとう。その場合は、そのライセンスに適合すると思われるコードを使用してください。
G_H

1
問題は、C ++の同等のペアに関するものです。また、ペアのオブジェクトへの参照があり、それらが可変である限り、コレクションにペアを挿入すると、動作が未定義になる可能性があると思います。
Mr_and_Mrs_D


1

com.sun.tools.javac.util.Pairは、ペアの単純な実装です。jdk1.7.0_51 \ lib \ tools.jarにあります。

org.apache.commons.lang3.tuple.Pair以外は、単なるインターフェースではありません。


2
ただし、JDKの内部APIを使用するべきではありません。
jpangamarca 2016

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

}

使用法 :

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

不変、ペアのみ!


ああすごい。別の?より複雑なGenericsを使用してみてください-ある時点で、適切な型を推測できなくなります。さらに、次のことが可能になるはずです。Pair<Object, Object> pair = Pair.createPair("abc", "def")ただしPair.createPair((Object)"abc", (Object)"def")、コードで記述する必要があると思いますか?
QUITあり-Anony-Mousse

あなたはこれで静的メソッドを置き換えることができます: @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); } しかし、それが良い習慣であるかどうかはわかりません
Bastiflew

いいえ、それはおそらくさらに物事を台無しにするだけです。私の経験では、少なくとも1つのコンパイラー(java6、java7、javadoc、およびEclipse Javaコンパイラーを試してください)が文句を言うでしょう。new Pair<Object, Object>("abc", "def")私の実験では、トラディショナルが最も信頼できました。
QUITあり-Anony-Mousse
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.