Apa yang setara dengan C ++ Pair <L, R> di Java?


671

Apakah ada alasan bagus mengapa tidak ada Pair<L,R>di Jawa? Apa yang akan setara dengan konstruk C ++ ini? Saya lebih suka menghindari mengimplementasikan saya sendiri.

Tampaknya 1.6 menyediakan sesuatu yang serupa ( AbstractMap.SimpleEntry<K,V>), tetapi ini terlihat cukup berbelit-belit.


7
Mengapa AbstractMap.SimpleEntryberbelit - belit?
CurtainDog

27
Karena namig, penamaan sewenang-wenang satu kunci dan satu nilai.
Enerccio


2
@ sffc JavaFX tidak ada di classpath default apa pun di JDK7, menggunakannya mengharuskan perpustakaan runtime JFX ditambahkan secara manual.
Cord Rehn

3
@Enerccio: Jadi, Anda benar-benar menyatakan bahwa "pertama" dan "kedua" tidak sembarangan, sementara "kunci" dan "nilai" - adalah? Maka ini adalah salah satu alasan bagus untuk tidak memiliki kelas seperti itu di SDK. Akan ada perselisihan abadi tentang penamaan yang "tepat".
fdreger

Jawaban:


400

Dalam sebuah utascomp.lang.java.help , Hunter Gratzner memberikan beberapa argumen yang menentang keberadaan Pairkonstruk di Jawa. Argumen utama adalah bahwa suatu kelas Pairtidak menyampaikan semantik tentang hubungan antara dua nilai (bagaimana Anda tahu apa arti "pertama" dan "kedua"?).

Praktik yang lebih baik adalah menulis kelas yang sangat sederhana, seperti yang diusulkan Mike, untuk setiap aplikasi yang Anda buat dari Pairkelas tersebut. Map.Entryadalah contoh dari pasangan yang membawa maknanya dalam namanya.

Singkatnya, menurut saya lebih baik memiliki kelas Position(x,y), kelas Range(begin,end)dan kelas Entry(key,value)daripada generik Pair(first,second)yang tidak memberi tahu saya apa-apa tentang apa yang seharusnya dilakukan.


143
Gratzner membelah rambut. Kami cukup senang mengembalikan nilai tunggal sebagai kelas primitif atau bawaan tanpa merangkumnya dalam kelas. Jika kita mengembalikan selusin elemen, tidak ada yang akan tidak setuju itu harus memiliki kelas sendiri. Di suatu tempat di tengah adalah garis pemisah (fuzzy). Saya pikir otak kadal kami dapat dengan mudah mengatasi Pasangan.
Ian

25
Saya setuju dengan Ian. Java memungkinkan Anda mengembalikan int; itu tidak memaksa Anda untuk membuat alias untuk int setiap kali Anda menggunakannya. Pasangan tidak jauh berbeda.
Clément

5
Jika kami bisa membongkar pasangan secara langsung ke variabel lokal Anda, atau meneruskannya ke metode yang membutuhkan dua argumen, Pair akan menjadi kelas yang berguna. Karena kita tidak bisa membukanya seperti ini, membuat kelas yang bermakna dan menjaga nilai-nilai bersama tidak terlihat terlalu buruk. Dan, jika Anda benar-benar menginginkan pasangan terlepas dari keterbatasan, selalu ada Object [2] + cast :-)
marcus

Masalahnya adalah jika Anda tidak setuju dengan Gratzner, maka ada implementasi Pair di beberapa tempat. Apache Commons dan Guava keduanya memilikinya IIRC. Gunakan itu. Tetapi untuk meletakkan sesuatu di perpustakaan utama Jawa berarti bahwa itu adalah Cara yang Mulia dan Disetujui untuk Melakukan Hal-hal (dengan huruf besar) dan karena orang tidak menyetujuinya, kita tidak seharusnya meletakkannya di sana. Ada cukup cacat di lib lama seperti itu, jangan sia-sia menempatkan lebih banyak di sana.
Haakon Løtveit

1
@ Tag Ketika saya Membutuhkan sepasang nilai maka itu bukan Java ... serius?
idclev 463035818

156

Ini Jawa. Anda harus membuat kelas Pair Anda sendiri yang disesuaikan dengan kelas deskriptif dan nama bidang, dan tidak keberatan bahwa Anda akan menemukan kembali roda dengan menulis kode hash () / equals () atau menerapkan Sebanding lagi dan lagi.


61
Itu tidak menjawab pertanyaan "mengapa". (Kecuali Anda menganggap jawaban 'ini adalah java')
Nikita Rybak

127
+1 untuk mengejek verboseness Java. -1 karena tidak benar-benar menjawab pertanyaan.
Bennett McElwee

19
Java-ejekan akan baik-baik saja jika Anda menunjuk ke Apache Commong Lang, yang berisi kelas Pair.
haylem

6
Atau Anda bisa menggunakanSimpleImmutableEntry
CurtainDog

33
Kalimat pertama TIDAK menjawab pertanyaan "mengapa?". Ini Java, dan hanya itu.
masterziv

103

Kelas Pair yang kompatibel dengan 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
Anda mungkin ingin menghapus setter, dan membuat final pertama dan kedua, sehingga membuat pasangan tidak berubah. (Jika seseorang mengubah komponen setelah menggunakannya sebagai kunci hash, hal-hal aneh akan terjadi).
Thilo

21
kembali "(" + first.toString () + "," + second.toString () + ")" di metode toString () dapat melempar NullPointerExceptions. Ini lebih baik: return "(" + first + "," + second + ")";
Juha Syrjälä

6
Juga, tandai pasangan sebagai "final" atau ubah baris pertama sama dengan 'if (other! = Null && this.getClass () == other.getClass ())'
sargas

8
Maaf untuk pertanyaan nooby acak, tetapi mengapa Anda memiliki panggilan ke super () di konstruktor?
Ibrahim

6
@ Ibrahim: Dalam hal ini, itu berlebihan --- perilakunya persis sama jika Anda super()mengeluarkannya. Biasanya saya hanya memotongnya jika itu opsional, seperti di sini.
Chris Jester-Young

53

Pasangan terpendek yang bisa saya ajukan adalah yang berikut, menggunakan Lombok :

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

Ia memiliki semua manfaat dari jawaban dari @arturh (kecuali komparabilitas), itu memiliki hashCode, equals, toStringdan statis “konstruktor”.


Bagus! Menyukai ini!
Ahmet Ipkin


31

Cara lain untuk mengimplementasikan Pair with.

  • Bidang abadi publik, yaitu struktur data sederhana.
  • Sebanding.
  • Hash dan sederajat sederhana.
  • Pabrik sederhana sehingga Anda tidak perlu menyediakan jenisnya. misalnya Pair.of ("halo", 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
Saya suka metode pabrik statis of. Ini mengingatkan pada koleksi abadi Guava Google .
Jarek Przygódzki

7
Anda berada di beberapa titik pengecoran o1untuk Comparable, meskipun tidak ada menunjukkan hal itu akan benar-benar mengimplementasikan antarmuka yang. Jika itu merupakan persyaratan, FIRSTparameter type seharusnya FIRST extends Comparable<?>.
G_H

Saya bukan orang Jawa, jadi tolong maafkan saya atas ketidaktahuan saya, tetapi kelas pembantu seperti apa yang Anda pikirkan dalam komentar TODO?

3
31 adalah konstanta yang buruk untuk kode hash. Misalnya, jika Anda menggunakan HashMap yang dikunci oleh Pair <Integer, Integer> untuk peta 2D, Anda akan mendapatkan banyak tabrakan. Sebagai contoh (a * 65497) ^ b akan lebih cocok.
Michał Zieliński

1
@MarioCarneiro ^ adalah xor, bukan kekuatan
Michał Zieliński

27

Bagaimana dengan http://www.javatuples.org/index.html Saya merasa sangat berguna.

The javatuples menawarkan kepada Anda kelas tuple dari satu hingga sepuluh elemen:

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
Lucu, tetapi setidaknya ada 5 kelas lebih banyak daripada yang bisa saya bayangkan untuk digunakan.
maaartinus

3
@maaartinus Setidaknya 10 lebih dari yang akan saya gunakan.
Boann

7
@Boann: Oke, saya tetap terkoreksi. Saya biasa menggunakan Pairdan bisa membayangkan untuk menggunakan Tripletmungkin sekali setiap 50 tahun. Sekarang saya menggunakan Lombok dan membuat kelas 4-garis kecil setiap kali saya membutuhkan pasangan. Jadi "10 terlalu banyak" adalah tepat.
maaartinus

5
Apakah kita perlu Bottom (0 element)kelas? :)
Earth Engine

2
Wow ini jelek. Saya tahu mereka mencoba untuk membuatnya eksplisit, tetapi Tuple dengan params yang kelebihan beban seperti di C # akan lebih baik.
arviman

12

Tergantung pada apa Anda ingin menggunakannya. Alasan khas untuk melakukannya adalah untuk beralih ke peta, yang Anda lakukan ini (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
Saya tidak yakin kelas khusus akan membantu dalam kasus ini :)
Nikita Rybak

31
"Alasan khas untuk melakukannya adalah beralih ke peta". Betulkah?
Bennett McElwee

12

Android menyediakan Pairkelas ( http://developer.android.com/reference/android/util/Pair.html ), di sini implementasinya:

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(..)membutuhkan perpustakaan Guava.
Markus L

3
Ubah ke Objects.equals(...)yang sudah ada di Jawa sejak 2011 (1.7).
AndrewF

9

Masalah terbesar mungkin adalah bahwa seseorang tidak dapat memastikan ketidakmampuan pada A dan B (lihat Bagaimana memastikan bahwa parameter tipe tidak dapat diubah ) sehingga hashCode()dapat memberikan hasil yang tidak konsisten untuk Pasangan yang sama setelah dimasukkan dalam koleksi misalnya (ini akan memberikan perilaku yang tidak ditentukan) , lihat Menentukan persamaan dalam hal bidang yang bisa diubah ). Untuk kelas Pair tertentu (non generik), programmer dapat memastikan imutabilitas dengan hati-hati memilih A dan B agar tidak berubah.

Lagi pula, menghapus peringatan generik dari jawaban @ 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 + ')';
    }
}

Tambahan / koreksi banyak diterima :) Secara khusus saya tidak yakin tentang penggunaan saya Pair<?, ?>.

Untuk info lebih lanjut tentang mengapa sintaks ini lihat Memastikan bahwa objek mengimplementasikan Sebanding dan untuk penjelasan rinci Bagaimana menerapkan max(Comparable a, Comparable b)fungsi generik di Jawa?


Karena Java Integers adalah 32 bit, tidak akan mengalikan kode hash pertama dengan 31 berarti bahwa itu meluap? Bukankah lebih baik melakukan OR eksklusif?
Dan

@Dan merasa bebas untuk mengedit saya pindah dari java :)
Mr_and_Mrs_D

5

Menurut pendapat saya, tidak ada pasangan di Jawa karena, jika Anda ingin menambahkan fungsionalitas tambahan langsung pada pasangan (misalnya Sebanding), Anda harus mengikat jenisnya. Dalam C ++, kami hanya tidak peduli, dan jika jenis yang menyusun pasangan tidak memiliki operator <, maka pair::operator <tidak akan mengkompilasi juga.

Contoh Sebanding dengan tanpa batas:

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

Contoh Comparable with compile-time check untuk apakah argumen tipe sebanding:

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

Ini bagus, tapi kali ini Anda mungkin tidak menggunakan tipe yang tidak sebanding sebagai argumen tipe di Pair. Seseorang dapat menggunakan banyak Pembanding untuk Pasangan di beberapa kelas utilitas, tetapi orang-orang C ++ mungkin tidak mendapatkannya. Cara lain adalah dengan menulis banyak kelas dalam hierarki tipe dengan batasan berbeda pada argumen tipe, tetapi ada terlalu banyak batasan yang mungkin dan kombinasinya ...


5

JavaFX (yang dibundel dengan Java 8) memiliki kelas Pair <A, B>


1
The pelaksanaan kode hash di javafx.util.Pair dapat menyebabkan tabrakan pada kasus-kasus sepele. Menggunakannya di HashMap / HashTable masih akan berfungsi karena Java memeriksa kesetaraan nilai di samping kode hash, tapi itu sesuatu yang harus diperhatikan.
sffc

Itu adalah implementasi kode hash yang sangat standar dan umum direkomendasikan. Tabrakan harus diharapkan oleh kode apa pun yang memanggil hashCode(). Perhatikan bahwa Java sendiri tidak memanggil metode ini. Ini untuk kode pengguna, termasuk perpustakaan.
AndrewF

5

Seperti yang telah dinyatakan oleh banyak orang lain, itu benar-benar tergantung pada use case apakah kelas Pair berguna atau tidak.

Saya pikir untuk fungsi pembantu pribadi, adalah benar-benar sah untuk menggunakan kelas Pair jika itu membuat kode Anda lebih mudah dibaca dan tidak sebanding dengan upaya menciptakan kelas nilai lain dengan semua kode pelat ketelnya.

Di sisi lain, jika level abstraksi Anda mengharuskan Anda untuk mendokumentasikan semantik kelas yang berisi dua objek atau nilai, maka Anda harus menulis kelas untuknya. Biasanya itu masalahnya jika data adalah objek bisnis.

Seperti biasa, itu membutuhkan penilaian yang terampil.

Untuk pertanyaan kedua Anda, saya merekomendasikan kelas Pair dari perpustakaan Apache Commons. Itu mungkin dianggap sebagai pustaka standar yang diperluas untuk Java:

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

Anda mungkin juga ingin melihat di Apache Commons ' EqualsBuilder , HashCodeBuilder dan ToStringBuilder yang menyederhanakan penulisan kelas nilai untuk objek bisnis Anda.


URL yang diperbarui adalah commons.apache.org/lang/api-release/index.html?org/apache/… karena commons-lang3 kehabisan beta. Ini bahkan lebih pendek daripada solusi Lombok saya sendiri jika Anda sudah menggunakan commons-lang 3.
Michael Piefel


5

Kabar Baik JavaFXmemiliki nilai kunci Pair.

tambahkan saja javafx sebagai ketergantungan dan impor javafx.util.Pair;

dan gunakan hanya seperti pada c++.

Pair <Key, Value> 

misalnya

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

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

Berita
buruknya

4

Antarmuka Map.Entry datang cukup dekat dengan pasangan c ++. Lihatlah implementasi konkret, seperti AbstractMap.SimpleEntry dan AbstractMap.SimpleImmutableEntry Item pertama adalah getKey () dan yang kedua adalah getValue ().


1
OP sudah mengetahui opsi ini, dan sudah dibahas panjang lebar.
Keegan


3

Menurut sifat bahasa Jawa, saya kira orang tidak benar-benar memerlukan Pair, antarmuka biasanya apa yang mereka butuhkan. Berikut ini sebuah contoh:

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

Jadi, ketika orang ingin mengembalikan dua nilai, mereka dapat melakukan hal berikut:

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

Ini adalah solusi yang cukup ringan, dan menjawab pertanyaan "Apa itu semantik dari Pair<L,R>?". Jawabannya adalah, ini adalah antarmuka yang dibangun dengan dua (mungkin berbeda) jenis, dan memiliki metode untuk mengembalikan masing-masing. Terserah Anda untuk menambahkan semantik lebih lanjut. Misalnya, jika Anda menggunakan Posisi dan BENAR-BENAR ingin menunjukkannya dalam kode Anda, Anda dapat menentukan PositionXdan PositionYyang berisi Integer, untuk membuat a Pair<PositionX,PositionY>. Jika JSR 308 tersedia, Anda juga dapat menggunakannya Pair<@PositionX Integer, @PositionY Ingeger>untuk menyederhanakannya.

EDIT: Satu hal yang saya harus tunjukkan di sini adalah bahwa definisi di atas secara eksplisit berkaitan dengan nama parameter type dan nama metode. Ini adalah jawaban bagi mereka yang berpendapat bahwa Pairkurangnya informasi semantik. Sebenarnya, metode ini getLberarti "beri saya elemen yang sesuai dengan tipe tipe parameter L", yang berarti sesuatu.

EDIT: Ini adalah kelas utilitas sederhana yang dapat membuat hidup lebih mudah:

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

pemakaian:

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

Bagaimana dengan equals, hashCodedan toString?
sdgfsdh

baik, ini hanya implementasi minimal. Jika Anda membutuhkan lebih dari itu, Anda dapat menulis beberapa fungsi pembantu untuk membuatnya lebih mudah, tetapi tetap saja Anda perlu menulis kode.
Earth Engine

Untuk menerapkan toStringAnda perlu lebih banyak pengetahuan tentang hubungan antara kedua bidang.
Mesin Bumi

Maksud saya adalah menyediakan classmungkin lebih baik daripada hanya interfacekarena dapat mengimplementasikan hal-hal ini.
sdgfsdh

3

Meskipun secara sintaksis serupa, Java dan C ++ memiliki paradigma yang sangat berbeda. Menulis C ++ seperti Java adalah C ++ yang buruk, dan menulis Java seperti C ++ adalah Java yang buruk.

Dengan IDE berbasis refleksi seperti Eclipse, menulis fungsionalitas kelas "pasangan" dengan cepat dan sederhana. Buat kelas, tentukan dua bidang, gunakan berbagai opsi menu "Hasilkan XX" untuk mengisi kelas dalam hitungan detik. Mungkin Anda harus mengetikkan "compareTo" dengan sangat cepat jika Anda menginginkan antarmuka yang sebanding.

Dengan opsi deklarasi / definisi terpisah dalam bahasa, kode generator C ++ tidak begitu baik, jadi menulis sedikit kelas utilitas lebih memakan waktu kebosanan. Karena pasangan adalah templat, Anda tidak perlu membayar untuk fungsi-fungsi yang tidak Anda gunakan, dan fasilitas typedef memungkinkan menetapkan nama ketik yang bermakna ke kode, sehingga keberatan tentang "tidak ada semantik" tidak benar-benar bertahan.


2

Pasangan akan menjadi hal yang baik, untuk menjadi unit konstruksi dasar untuk obat generik yang kompleks, misalnya, ini dari kode saya:

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

Sama seperti Haskell's Tuple


1
Sekarang saya dapat mengatakan, bahwa menggunakan Pair <A, B> membuat kode kurang informatif, dan mengimplementasikan objek khusus daripada menggunakan Pair jauh lebih baik
Illarion Kovalchuk

1
Lebih baik atau lebih buruk. Bayangkan Anda memiliki fungsi yang menggabungkan dua argumennya (mis. Menggabungkan grafik menjadi satu) dan perlu menyimpannya. Di sini, Pairoptimal karena tidak ada semantik khusus. Memiliki nama yang jelas untuk konsep yang jelas itu baik, tetapi mencari nama di mana "pertama" dan "kedua" bekerja dengan baik tidak.
maaartinus

2

Simple way Object [] - dapat digunakan sebagai tuple dimensi


2
Dimensi apa saja, ya. Tapi: rumit untuk dibuat, dan tidak aman untuk diketik.
Michael Piefel

2

Untuk bahasa pemrograman seperti Java, struktur data alternatif yang digunakan oleh sebagian besar programmer untuk mewakili pasangan seperti struktur data adalah dua larik, dan data diakses melalui indeks yang sama

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

Ini tidak ideal karena data harus diikat bersama, tetapi juga ternyata cukup murah. Juga, jika use case Anda menuntut penyimpanan koordinat maka lebih baik untuk membangun struktur data Anda sendiri.

Saya memiliki sesuatu seperti ini di perpustakaan saya

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


2

Berikut adalah beberapa perpustakaan yang memiliki beberapa tingkat tupel untuk kenyamanan Anda:

  • JavaTuples . Tuples dari tingkat 1-10 adalah semua yang dimilikinya.
  • JavaSlang . Tuples dari tingkat 0-8 dan banyak barang fungsional lainnya.
  • JOOλ . Tuples dari tingkat 0-16 dan beberapa barang fungsional lainnya. (Penafian, saya bekerja untuk perusahaan pengelola)
  • Java fungsional . Tuples dari tingkat 0-8 dan banyak barang fungsional lainnya.

Perpustakaan lain telah disebutkan mengandung setidaknya Pairtupel.

Khususnya, dalam konteks pemrograman fungsional yang menggunakan banyak pengetikan struktural, daripada pengetikan nominal ( seperti yang disarankan dalam jawaban yang diterima ), perpustakaan dan tupel mereka sangat berguna.



2

implementasi lombok singkat lainnya

import lombok.Value;

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

1

Saya perhatikan semua implementasi Pair berserakan di sini atribut yang berarti urutan dua nilai. Ketika saya memikirkan pasangan, saya memikirkan kombinasi dua item di mana urutan keduanya tidak penting. Inilah implementasi pasangan berpasangan yang tidak tertata, dengan hashCodedan equalsmenimpa untuk memastikan perilaku yang diinginkan dalam koleksi. Juga dapat dikloning.

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

    }

}

Implementasi ini telah diuji unit dengan benar dan penggunaan dalam Set dan Peta telah dicoba.

Perhatikan bahwa saya tidak mengklaim untuk melepaskan ini di domain publik. Ini adalah kode yang baru saja saya tulis untuk digunakan dalam aplikasi, jadi jika Anda akan menggunakannya, jangan membuat salinan langsung dan mengacaukan dengan komentar dan nama sedikit. Tangkap maksudku?


3
sebenarnya, periksa bagian bawah setiap halaman: "kontribusi pengguna berlisensi di bawah cc-wiki"
amara

Ah, aku tidak memperhatikan itu. Terimakasih atas peringatannya. Dalam hal itu, gunakan kode sesuai keinginan Anda di bawah lisensi itu.
G_H

1
Pertanyaannya adalah tentang pasangan setara C ++ - yang dipesan. Saya juga berpikir bahwa selama seseorang memiliki referensi ke objek Pair dan itu adalah pasangan pasang yang bisa berubah dalam koleksi dapat menyebabkan perilaku yang tidak terdefinisi.
Mr_and_Mrs_D


1

com.sun.tools.javac.util.Pair adalah implementasi sederhana dari suatu pasangan. Itu dapat ditemukan di jdk1.7.0_51 \ lib \ tools.jar.

Selain dari org.apache.commons.lang3.tuple.Pair, ini bukan hanya sebuah antarmuka.


2
Tidak ada yang harus menggunakan API internal JDK.
jpangamarca

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

}

penggunaan:

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

Abadi, hanya sepasang!


Oh wow. Yang lainnya? Coba gunakan milik Anda dengan Generik yang lebih kompleks - pada titik tertentu, ia akan gagal menyimpulkan jenis yang sesuai. Plus, berikut ini harus dimungkinkan: Pair<Object, Object> pair = Pair.createPair("abc", "def")tetapi saya pikir seseorang perlu menulis Pair.createPair((Object)"abc", (Object)"def")dengan kode Anda?
Memiliki QUIT - Anony-Mousse

Anda dapat mengganti metode statis dengan ini: @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); } tetapi saya tidak tahu apakah itu praktik yang baik
Bastiflew

Tidak, itu mungkin hanya akan mengacaukan segalanya. Dalam pengalaman saya, setidaknya satu dari kompiler (coba java6, java7, javadoc dan eclipse java compiler) akan mengeluh. Tradisional new Pair<Object, Object>("abc", "def")adalah yang paling dapat diandalkan dalam percobaan saya.
Memiliki QUIT - Anony-Mousse
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.