Collectors.toMap () keyMapper - prägnanter Ausdruck?


77

Ich versuche, im folgenden Collectors.toMap()Aufruf einen prägnanteren Ausdruck für den Funktionsparameter "keyMapper" zu finden :

List<Person> roster = ...;

Map<String, Person> map = 
    roster
        .stream()
        .collect(
            Collectors.toMap(
                new Function<Person, String>() { 
                    public String apply(Person p) { return p.getLast(); } 
                },
                Function.<Person>identity()));

Es scheint, dass ich in der Lage sein sollte, es mit einem Lambda-Ausdruck zu inline, aber ich kann mir keinen ausdenken, der kompiliert. (Ich bin ziemlich neu in Lambdas, das ist also keine große Überraschung.)

Vielen Dank.

-> Update:

Wie in der akzeptierten Antwort angegeben

Person::getLast

ist das, wonach ich gesucht habe und was ich versucht habe. Der nächtliche BETA_8-Build von Eclipse 4.3 war jedoch das Problem - er hat dies als falsch gekennzeichnet. Beim Kompilieren über die Befehlszeile (was ich vor dem Posten hätte tun sollen) hat es funktioniert. Also, Zeit, einen Fehler bei eclipse.org zu melden.

Vielen Dank.


1
Beachten Sie auch, dass ein statischer Import für Collectors.toMap den Ausdruck noch kürzer macht. NetBeans scheint diese jedoch nicht für mich zu importieren.
Brett Ryan

Bin gerade über diese Frage gestolpert. Ihr Problem war nicht nur Eclipse 4.3, sondern auch JDK 8 vor u112, das ähnliche Probleme hatte. HTH.
Ben

Antworten:


189

Sie können ein Lambda verwenden:

Collectors.toMap(p -> p.getLast(), Function.identity())

oder genauer gesagt, Sie können eine Methodenreferenz verwenden, indem Sie Folgendes verwenden :::

Collectors.toMap(Person::getLast, Function.identity())

und stattdessen Function.identitykönnen Sie einfach das entsprechende Lambda verwenden:

Collectors.toMap(Person::getLast, p -> p)

Wenn Sie Netbeans verwenden, sollten Sie Hinweise erhalten, wann immer eine anonyme Klasse durch ein Lambda ersetzt werden kann.


2
Sie können Ihre Ausdrücke noch kürzer machen, indem Sie Klammern entfernen, da sie für einzelne Argumente nicht benötigt werden, d Collectors.toMap(Person::getLast, p -> p). H.
Brett Ryan

1
Ich bin mir auch ziemlich sicher, dass das Typargument für die Identitätsfunktion nicht erforderlich ist, da es abgeleitet werden kann. Collectors.toMap(Person::getLast, Function.identity())
GuiSim

@GuiSim Ich denke, es ist jetzt tatsächlich der Fall - es war ein Fehler in den früheren Versionen von Java 8.
Assylias

2
Hehe, es scheint, dass p -> p irgendwie optimiert ist, es wird keine neue kompilierte anonyme Klasse erstellt. Ich denke, es verwendet Function.identity () intern, anstatt eine nutzlose Klasse zu erstellen.
Vlasec

1
Wichtiger Vorbehalt! Wenn Ihre Liste Nullwerte enthält, erhalten Sie hier eine Ausnahme, da Collectors.toMap implementiert ist, obwohl eine Karte mit Nullwerten normalerweise vollkommen akzeptabel ist. Sicherlich würden Sie in diesem Fall ohnehin eine NPE erhalten, wenn Sie auf Person :: getLast zugreifen, aber es gibt viele andere Fälle, in denen Ihr Schlüssel möglicherweise anders zusammengesetzt ist, Sie aber dennoch die Ausnahme erhalten. Siehe stackoverflow.com/questions/24630963/…
Sebastiaan van den Broek

29
List<Person> roster = ...;

Map<String, Person> map = 
    roster
        .stream()
        .collect(
            Collectors.toMap(p -> p.getLast(), p -> p)
        );

Das wäre die Übersetzung, aber ich habe dies nicht ausgeführt oder die API verwendet. höchstwahrscheinlich können Sie Function.identity () durch p -> p ersetzen. und statisch in Map importieren (...)


Gibt es eine Möglichkeit, ähnliche Werte in einer Liste <Person> bei Duplikaten zusammenzuführen, anstatt sie zu verketten?
Lovegiver

5

Wir können eine optionale Zusammenführungsfunktion auch bei derselben Schlüsselkollision verwenden. Wenn beispielsweise zwei oder mehr Personen denselben Wert für getLast () haben, können Sie angeben, wie die Werte zusammengeführt werden sollen. Wenn wir dies nicht tun, könnten wir IllegalStateException bekommen. Hier ist das Beispiel, um dies zu erreichen ...

Map<String, Person> map = 
roster
    .stream()
    .collect(
        Collectors.toMap(p -> p.getLast(),
                         p -> p,
                         (person1, person2) -> person1+";"+person2)
    );

1
Es tut mir leid, aber was bedeutet das? (person1, person2) -> person1+";"+person2)
Thach Huynh

1
Wenn die zugeordneten Schlüssel Duplikate enthalten (gemäß Object.equals (Object)), wird die Wertzuordnungsfunktion auf jedes gleiche Element angewendet und die Ergebnisse werden mit der bereitgestellten Zusammenführungsfunktion zusammengeführt. Bitte beziehen Sie sich auf den Link docs.oracle.com/javase/8/docs/api/java/util/stream/…
KayV
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.