Java Stream: durch boolesches Prädikat in zwei Listen teilen

Lesezeit: 5 Minuten

Ich habe eine Liste von employees. Sie haben isActive Boolesches Feld. Ich möchte teilen employees in zwei Listen: activeEmployees und formerEmployees. Ist es möglich, die Stream-API zu verwenden? Was ist der raffinierteste Weg?

  • Mögliches Duplikat von How to partition a list by predicate using java8?

    – Malte Hartwig

    26. Oktober 2017 um 15:47 Uhr

  • @MalteHartwig beachte dieses Duplikat sagt “Prädikat”, aber OP fragt tatsächlich nach der Gruppierung nach einer Funktion. Ich würde jedoch nicht wieder öffnen, wenn es so geschlossen wäre.

    – Andy Turner

    26. Oktober 2017 um 15:54 Uhr

Java Stream durch boolesches Pradikat in zwei Listen teilen
Andy Turner

Collectors.partitioningBy:

Map<Boolean, List<Employee>> partitioned = 
    listOfEmployees.stream().collect(
        Collectors.partitioningBy(Employee::isActive));

Die resultierende Karte enthält zwei Listen, die dem entsprechen, ob das Prädikat gefunden wurde oder nicht:

List<Employee> activeEmployees = partitioned.get(true);
List<Employee> formerEmployees = partitioned.get(false);

Es gibt ein paar Gründe für die Verwendung partitioningBy über groupingBy (wie von Juan Carlos Mendoza vorgeschlagen):

Erstens der Parameter von groupingBy ist ein Function<Employee, Boolean> (in diesem Fall), und so besteht die Möglichkeit, ihm eine Funktion zu übergeben, die null zurückgeben kann, was bedeutet, dass es eine dritte Partition geben würde, wenn diese Funktion für einen der Mitarbeiter null zurückgibt. partitioningBy verwendet a Predicate<Employee>sodass immer nur 2 Partitionen zurückgegeben werden können. was zu einem führen würde NullPointerException wird vom Kollektor ausgelöst: Obwohl nicht explizit dokumentiert, wird explizit eine Ausnahme für Nullschlüssel ausgelöst, vermutlich aufgrund des Verhaltens von Map.computeIfAbsent dass “wenn die Funktion null zurückgibt, keine Zuordnung aufgezeichnet wird”, was bedeutet, dass Elemente sonst stillschweigend aus der Ausgabe gelöscht würden. (Danke an lczapski für den Hinweis).

Zweitens erhalten Sie zwei Listen partitioningByin der resultierenden Karte mit groupingBy; mit

System.out.println(
    Stream.empty().collect(Collectors.partitioningBy(a -> false)));
// Output: {false=[], true=[]}

System.out.println(
    Stream.empty().collect(Collectors.groupingBy(a -> false)));
// Output: {}

erhalten Sie nur Schlüssel/Wert-Paare, bei denen Elemente dem angegebenen Schlüssel zugeordnet sind: Dieses Verhalten ist in der nicht dokumentiert Java 8 Javadocaber es wurde für hinzugefügt

  • Java 9

    .

    und drittens ist die Karte, die Sie erhalten, intern optimiert, um nur zwei Tasten zu halten.

  • – Eugen Stream.of(1,2,3,4).collect(groupingBy(x -> x == 3 ? null : x >= 3)) 19. September 2018 um 7:00 Uhr java.lang.NullPointerException: element cannot be mapped to a null keyIch war neugierig darauf: “Übergeben einer Funktion, die null zurückgeben kann, was bedeutet, dass es eine dritte Partition geben würde, wenn diese Funktion null zurückgibt”. Ich habe einen Code erstellt, der null zurückgibt

    und nach der Ausführung wurde eine Ausnahme zurückgegeben:

    . Es kann also nicht wahr sein.


  • – lczapski 9. September 2019 um 7:25 Uhr@lczapski interessant, ich werde die Antwort aktualisieren. Das ist eigentlich nicht

    dokumentiert

    obwohl.


  • – Andy Turner Map.computeIfAbsent9. September 2019 um 8:52 Uhr

    @lczapski Ich denke, diese Einschränkung kommt implizit von

    die besagt, dass “Wenn die Funktion null zurückgibt, keine Zuordnung aufgezeichnet wird”.

– Andy Turner 9. September 2019 um 8:58 Uhr Sie können auch verwenden

Map<Boolean, List<Employee>> grouped = employees.stream()
                .collect(Collectors.groupingBy(Employee::isActive));

List<Employee> activeEmployees = grouped.get(true);
List<Employee> formerEmployees = grouped.get(false);

  • GruppierungNach in diesem Fall gibt es 2 Gruppenmöglichkeiten (aktive und inaktive Mitarbeiter): +1, aber beachten Sie, dass Sie es sein sollten groupingBy leicht Function<Employee, Boolean>vorsichtig mit diesem Ansatz: der Parameter von nullist ein partitioningBy und so besteht die Möglichkeit, ihm eine Funktion zu übergeben, die zurückkehren kann Predicate, was bedeutet, dass es eine dritte Partition geben würde, wenn diese Funktion für einen der Mitarbeiter null zurückgibt. Die

    verwendet a

    sodass immer nur 2 Partitionen zurückgegeben werden können.


  • – Andy Turner groupingBy 26. Oktober 2017 um 15:34 Uhr

    Ich habe nur ein wenig experimentiert und festgestellt, dass es andere Gründe gibt, es nicht zu verwenden

    – Schauen Sie sich die Bearbeitung meiner Antwort an. (Entschuldigung, ich versuche definitiv nicht nur, Ihre Antwort zu zerreißen, ich habe tatsächlich etwas gelernt, indem ich die beiden ausprobiert habe!)

  • – Andy Turner isActive 26. Oktober 2017 um 15:41 Uhr

    @AndyTurner danke. Für diesen Fall gehe ich davon aus

    wird nicht null zurückgeben (wie es einen primitiven booleschen Wert verwendet).

  • – Juan Carlos Mendoza 26. Oktober 2017 um 15:48 Uhr Ich würde auch davon ausgehen, dass es so ist. Ich weise nur darauf hin, dass es das gibt groupingByWahrscheinlichkeit

    über

    .

1647157627 533 Java Stream durch boolesches Pradikat in zwei Listen teilen
– Andy Turner

26. Oktober 2017 um 15:53 ​​Uhr

Adrian Collectors::teeing

List<List<Employee>> divided = employees.stream().collect(
      Collectors.teeing(
              Collectors.filtering(Employee::isActive, Collectors.toList()),
              Collectors.filtering(Predicate.not(Employee::isActive), Collectors.toList()),
              List::of
      ));

System.out.println(divided.get(0));  //active
System.out.println(divided.get(1));  //inactive

Java Stream durch boolesches Pradikat in zwei Listen teilen
Was ist der raffinierteste Weg?

Java 12 natürlich mit neu Collectors2.partition Donald Rab Wenn Sie bereit sind, eine Bibliothek eines Drittanbieters zu verwenden, funktioniert dies mitvon

PartitionMutableList<Employee> partition =
        employees.stream().collect(
                Collectors2.partition(Employee::isActive, PartitionFastList::new));

List<Employee> activeEmployees = partition.getSelected();
List<Employee> formerEmployees = partition.getRejected();

Eclipse-Sammlungen ListIterate.

PartitionMutableList<Employee> partition =
        ListIterate.partition(employees, Employee::isActive);

List<Employee> activeEmployees = partition.getSelected();
List<Employee> formerEmployees = partition.getRejected();

PartitionMutableList Sie können die Dinge auch vereinfachen, indem Sie verwenden PartitionIterable. PartitionIterable ist ein Typ, der sich erstreckt von getSelected() . Jede Unterart von getRejected()hat eine Sammlung für positive Ergebnisse

und negative Ergebnisse

996460cookie-checkJava Stream: durch boolesches Prädikat in zwei Listen teilen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy