710 Stimmen

Finde das erste Element anhand eines Prädikats

Ich habe gerade angefangen, mit Java 8 Lambdas zu spielen und versuche, einige der Dinge zu implementieren, die ich von funktionalen Sprachen gewohnt bin.

Zum Beispiel haben die meisten funktionalen Sprachen eine Art find-Funktion, die auf Sequenzen oder Listen operiert und das erste Element zurückgibt, für das der Prädikat true ist. Der einzige Weg, den ich in Java 8 sehe, um das zu erreichen, ist:

lst.stream()
    .filter(x -> x > 5)
    .findFirst()

Dies scheint mir jedoch ineffizient zu sein, da der Filter die ganze Liste durchsucht, zumindest nach meinem Verständnis (das falsch sein könnte). Gibt es einen besseren Weg?

934voto

Alexis C. Punkte 87062

Nein, der Filter durchsucht nicht den gesamten Stream. Es handelt sich um eine Zwischenoperation, die einen Lazy Stream zurückgibt (tatsächlich geben alle Zwischenoperationen einen Lazy Stream zurück). Um Sie zu überzeugen, können Sie einfach den folgenden Test durchführen:

List list = Arrays.asList(1, 10, 3, 7, 5);
int a = list.stream()
            .peek(num -> System.out.println("wird gefiltert " + num))
            .filter(x -> x > 5)
            .findFirst()
            .get();
System.out.println(a);

Was folgendes ausgibt:

wird gefiltert 1
wird gefiltert 10
10

Sie sehen, dass nur die ersten beiden Elemente des Streams tatsächlich verarbeitet werden.

Sie können also mit Ihrem Ansatz weitermachen, der völlig in Ordnung ist.

131voto

wha'eve' Punkte 3580

Allerdings erscheint mir das ineffizient, da der Filter die gesamte Liste durchsucht.

Nein, das wird es nicht - es wird "abgebrochen", sobald das erste Element gefunden wird, das dem Prädikat entspricht. Weitere Informationen zur Trägheit finden Sie im Javadoc des Stream-Pakets, insbesondere (Hervorhebung von mir):

Viele Stream-Operationen, wie Filtern, Zuordnen oder Duplikate entfernen, können träge implementiert werden und bieten Möglichkeiten für Optimierungen. Zum Beispiel müssen nicht alle Eingabestrings überprüft werden, um "den ersten String mit drei aufeinanderfolgenden Vokalen zu finden". Stream-Operationen sind in Zwischen- (Stream-erzeugende) und endgültige (Wert- oder Seiteneffekt-erzeugende) Operationen unterteilt. Zwischen-Operationen sind immer träge.

65voto

CodeShadow Punkte 3383
return dataSource.getParkingLots()
                 .stream()
                 .filter(parkingLot -> Objects.equals(parkingLot.getId(), id))
                 .findFirst()
                 .orElse(null);

Ich musste nur ein Objekt aus einer Liste von Objekten filtern. Also habe ich das verwendet, hoffe es hilft.

23voto

Ifesinachi Bryan Punkte 2014

Zusätzlich zu Alexis C's Antwort, Wenn Sie mit einer Array-Liste arbeiten, in der Sie nicht sicher sind, ob das von Ihnen gesuchte Element vorhanden ist, verwenden Sie dies.

Integer a = list.stream()
                .peek(num -> System.out.println("wird filtern " + num))
                .filter(x -> x > 5)
                .findFirst()
                .orElse(null);

Dann könnten Sie einfach überprüfen, ob a null ist.

17voto

Grigory Kislin Punkte 14348

Bereits von @AjaxLeung beantwortet, aber in Kommentaren und schwer zu finden.
Zum Überprüfen

lst.stream()
    .filter(x -> x > 5)
    .findFirst()
    .isPresent()

wird vereinfacht zu

lst.stream()
    .anyMatch(x -> x > 5)

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