716 Stimmen

Was ist das Äquivalent von C++ Pair<L,R> in Java?

Gibt es einen guten Grund, warum es in Java kein Pair gibt? Was wäre das Äquivalent zu diesem C++-Konstrukt? Ich würde es lieber vermeiden, mein eigenes neu zu implementieren.

Es scheint, dass 1.6 etwas Ähnliches bereitstellt (AbstractMap.SimpleEntry), aber das sieht ziemlich verworren aus.

10 Stimmen

Warum ist AbstractMap.SimpleEntry umständlich?

0 Stimmen

Sehen Sie meine Antwort stackoverflow.com/a/16089164/173149, wo ich AbstractMap.SimpleImmutableEntry ohne Probleme verwende (kompliziertes Beispiel).

0 Stimmen

SimpleEntry hat drei Methoden, die nicht von Object vererbt wurden. Warum sollte es "verschachtelt" sein?

32voto

Peter Lawrey Punkte 511323

Ein weiterer Weg, Pair mit zu implementieren.

  • Öffentliche unveränderbare Felder, d.h. einfache Datenstruktur.
  • Vergleichbar.
  • Einfache Hashfunktion und Gleichheitsprüfung.
  • Einfache Factory, so dass Sie die Typen nicht angeben müssen. z.B. Pair.of("Hallo", 1);

    public class Pair implements Comparable> {
    
        public final FIRST first;
        public final SECOND second;
    
        private Pair(FIRST first, SECOND second) {
            this.first = first;
            this.second = second;
        }
    
        public static  Pair of(FIRST first,
                SECOND second) {
            return new Pair(first, second);
        }
    
        @Override
        public int compareTo(Pair 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 Stimmen

Ich mag die statische Factory-Methode of. Es erinnert an die unveränderlichen Sammlungen von Google Guava.

7 Stimmen

Sie gießen zu einem bestimmten Zeitpunkt o1 zu Comparable, obwohl nichts darauf hinweist, dass es tatsächlich dieses Interface implementiert. Wenn das eine Voraussetzung ist, sollte der erste Typenparameter FIRST extends Comparable sein.

0 Stimmen

Ich bin kein Java-Experte, also verzeihen Sie mir bitte meine Unkenntnis, aber an welche Art von Hilfsklassen haben Sie in den TODO-Kommentaren gedacht?

28voto

cyberoblivion Punkte 659

Wie wäre es mit http://www.javatuples.org/index.html ich habe es sehr nützlich gefunden.

Die Javatuples bietet Tuple-Klassen von einem bis zehn Elementen:

Unit (1 Element)
Pair (2 Elemente)
Triplet (3 Elemente)
Quartet (4 Elemente)
Quintet (5 Elemente)
Sextet (6 Elemente)
Septet (7 Elemente)
Octet (8 Elemente)
Ennead (9 Elemente)
Decade (10 Elemente)

7 Stimmen

Lustig, aber es gibt mindestens 5 Klassen mehr, als ich mir jemals vorstellen könnte zu verwenden.

0 Stimmen

Kommen sie nicht mit der Java-Standardbibliothek, oder?

3 Stimmen

@maaartinus Mindestens 10 mehr als ich verwenden würde.

12voto

cletus Punkte 596503

Es hängt davon ab, wofür du es verwenden möchtest. Der typische Grund ist, um über Maps zu iterieren, wofür du einfach das machst (Java 5+):

Map map = ... ; // nur ein Beispiel
for (Map.Entry entry : map.entrySet()) {
  System.out.printf("%s -> %s\n", entry.getKey(), entry.getValue());
}

1 Stimmen

Ich bin mir nicht sicher, ob eine benutzerdefinierte Klasse in diesem Fall helfen würde :)

40 Stimmen

"Der typische Grund dafür ist das Durchlaufen von Maps". Wirklich?

6voto

MaxBuzz Punkte 69

Nach meiner Meinung gibt es in Java kein Pair, weil, wenn Sie zusätzliche Funktionalitäten direkt auf das Pair hinzufügen möchten (z. B. Comparable), müssen Sie die Typen einschränken. In C++ ist es egal, und wenn die Typen, die ein Pair bilden, keinen operator < ```haben, wird auch der ``pair::operator < `nicht kompilieren.` `` ```

` `

Ein Beispiel für Comparable ohne Einschränkung:

public class Pair implements Comparable> {
    public final F first;
    public final S second;
    /* ... */
    public int compareTo(Pair that) {
        int cf = compare(first, that.first);
        return cf == 0 ? compare(second, that.second) : cf;
    }
    //Warum wird entschieden, dass null kleiner als alles ist?
    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> a = /* ... */;
Pair> b = /* ... */;
//Laufzeitfehler hier anstatt Kompilierfehler!
System.out.println(a.compareTo(b));

Ein Beispiel für Comparable mit Kompilierzeitprüfung, ob Typargumente vergleichbar sind:

public class Pair<
        F extends Comparable, 
        S extends Comparable
> implements Comparable> {
    public final F first;
    public final S second;
    /* ... */
    public int compareTo(Pair that) {
        int cf = compare(first, that.first);
        return cf == 0 ? compare(second, that.second) : cf;
    }
    //Warum wird entschieden, dass null kleiner als alles ist?
    private static <
            T extends Comparable
    > int compare(T l, T r) {
        if (l == null) {
            return r == null ? 0 : -1;
        } else {
            return r == null ? 1 : l.compareTo(r);
        }
    }
}

/* ... */

//Wird nicht kompilieren, weil Thread nicht Comparable ist
Pair> a = /* ... */;
Pair> b = /* ... */;
System.out.println(a.compareTo(b));

Dies ist gut, aber dieses Mal dürfen Sie keine nicht vergleichbaren Typen als Typargumente in Pair verwenden. Man kann viele Comparators für Pair in einer Hilfsklasse verwenden, aber C++-Leute verstehen das vielleicht nicht. Ein anderer Weg ist, viele Klassen in einer Typenhierarchie mit unterschiedlichen Einschränkungen für Typargumente zu schreiben, aber es gibt zu viele mögliche Einschränkungen und ihre Kombinationen...

` `` ```

5voto

Peter Goetz Punkte 114

Wie bereits von vielen anderen erwähnt wurde, hängt es wirklich vom Anwendungsfall ab, ob eine Pair-Klasse nützlich ist oder nicht.

Ich denke, für eine private Hilfsfunktion ist es völlig legitim, eine Pair-Klasse zu verwenden, wenn dies Ihren Code lesbarer macht und es nicht wert ist, noch eine Wertklasse mit all ihrem Boilerplate-Code zu erstellen.

Andererseits, wenn Ihr Abstraktionsniveau erfordert, dass Sie die Semantik der Klasse deutlich dokumentieren, die zwei Objekte oder Werte enthält, sollten Sie eine Klasse dafür schreiben. In der Regel ist das der Fall, wenn die Daten ein Geschäftsobjekt sind.

Wie immer erfordert es fachkundiges Urteilsvermögen.

Für Ihre zweite Frage empfehle ich die Pair-Klasse aus den Apache Commons-Bibliotheken. Diese könnten als erweiterte Standardbibliotheken für Java betrachtet werden:

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

Sie möchten vielleicht auch einen Blick auf EqualsBuilder, HashCodeBuilder und ToStringBuilder von Apache Commons werfen, die das Schreiben von Wertklassen für Ihre Geschäftsobjekte vereinfachen.

0 Stimmen

Die aktualisierte URL ist commons.apache.org/lang/api-release/index.html?org/apache/… da commons-lang3 nicht mehr in der Beta-Version ist. Diese ist sogar kürzer als meine eigene Lösung mit Lombok, wenn Sie bereits commons-lang 3 verwenden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X