Java - Filter een stream met Lambda-expressies PlatoBlockchain Data Intelligence. Verticaal zoeken. Ai.

Java – Filter een stream met Lambda-expressies

Java Streams zijn helemaal terug in Java 8 geïntroduceerd in 2014, in een poging om uitgebreide Java te introduceren in een functioneel programmeerparadigma. Java Streams leggen veel flexibele en krachtige functionele bewerkingen bloot om collectieverwerking in oneliners uit te voeren.

Het filteren van verzamelingen op basis van een predikaat blijft een van de meest gebruikte functionele bewerkingen en kan worden uitgevoerd met a Predicate of meer beknopt - met a Lambda-expressie.

In deze korte handleiding bekijken we hoe u een Java 8-stream kunt filteren met Lambda Expressions.

Streams filteren in Java

Over het algemeen is elke Stream kan worden gefilterd via de filter() methode en een bepaald predikaat:

Stream filter(Predicate<? super T> predicate)

Elk element in de stroom wordt uitgevoerd tegen het predikaat en wordt toegevoegd aan de uitvoerstroom als het predikaat terugkeert true. U kunt een Predicate voorbeeld:

Predicate contains = s -> s.contains("_deprecated");
List results = stream.filter(contains).collect(Collectors.toList());

Of vereenvoudig het door een Lambda-expressie op te geven:

List results = stream.filter(s -> s.contains("_deprecated"))
                             .collect(Collectors.toList());

Of zelfs de Lambda Expression samenvouwen tot een methode referentie:


List results = stream.filter(String::isEmpty)
                             .collect(Collectors.toList());

Met methodeverwijzingen kunt u geen argumenten doorgeven, maar u kunt methoden definiëren in het object dat u filtert en deze aanpassen zodat ze gemakkelijk kunnen worden gefilterd (zolang de methode geen argumenten accepteert en een boolean).

Vergeet niet dat streams zijn geen collecties – het zijn streams van collecties, en je moet ze terug verzamelen in een verzameling zoals a List, Map, enz. om ze duurzaamheid te geven. Bovendien worden alle bewerkingen uitgevoerd op stream-elementen ofwel tussen- or terminal:

  • Tussenbewerkingen retourneren een nieuwe stream met wijzigingen ten opzichte van de vorige bewerking
  • Terminalbewerkingen retourneren een gegevenstype en zijn bedoeld om een ​​verwerkingspijplijn op een stream te beëindigen

filter() is een tussen- bewerking, en is bedoeld om te worden gekoppeld aan andere tussenbewerkingen, voordat de stroom wordt beëindigd. Als u wijzigingen wilt behouden (zoals wijzigingen aan elementen zelf of gefilterde resultaten), moet u het resultaat toewijzen uitvoerstroom: naar een nieuwe referentievariabele, via een terminalbewerking.

Opmerking: Zelfs als je veel lambda-expressies aan een ketting koppelt, loop je misschien niet tegen leesbaarheidsproblemen aan, met de juiste regeleinden.

In de volgende voorbeelden werken we met deze lijst met boeken:

Book book1 = new Book("001", "Our Mathematical Universe", "Max Tegmark", 432, 2014);
Book book2 = new Book("002", "Life 3.0", "Max Tegmark", 280, 2017);
Book book3 = new Book("003", "Sapiens", "Yuval Noah Harari", 443, 2011);
        
List books = Arrays.asList(book1, book2, book3);

Filterverzameling met Stream.filter()

Laten we deze verzameling boeken filteren. Elk predikaat gaat - dus laten we bijvoorbeeld filteren op welke boeken meer dan 400 pagina's hebben:

List results = books.stream()
                          .filter(b -> b.getPageNumber() > 400)
                          .collect(Collectors.toList());

Dit resulteert in een lijst met daarin:

[
Book{id='001', name='Our Mathematical Universe', author='Max Tegmark', pageNumber=432, publishedYear=2014}, 
Book{id='003', name='Sapiens', author='Yuval Noah Harari', pageNumber=443, publishedYear=2011}
]

Bij het filteren is een echt nuttige methode om te ketenen: map(), waarmee u objecten aan een andere waarde kunt toewijzen. We kunnen bijvoorbeeld elk boek aan zijn naam toewijzen, en dus alleen de namen van de boeken die passen bij het predikaat uit de filter() bellen:

List results = books.stream()
                            .filter(b -> b.getPageNumber() > 400)
                            .map(Book::getName)
                            .collect(Collectors.toList());

Dit resulteert in een lijst met strings:

[Our Mathematical Universe, Sapiens]

Filterverzameling op meerdere predikaten met Stream.filter()

Gewoonlijk willen we collecties filteren op meer dan één criterium. Dit kan door meerdere filter() gesprekken or met behulp van een kortsluitingspredikaat, dat controleert op twee voorwaarden in één filter() noemen.

 List results = books.stream()
                    .filter(b -> b.getPageNumber() > 400 && b.getName().length() > 10)
                    .collect(Collectors.toList());
                    


 List results2 = books.stream()
                    .filter(b -> b.getPageNumber() > 400)
                    .filter(b -> b.getName().length() > 10)
                    .collect(Collectors.toList());

Bekijk onze praktische, praktische gids voor het leren van Git, met best-practices, door de industrie geaccepteerde normen en bijgevoegd spiekbriefje. Stop met Googlen op Git-commando's en eigenlijk leren het!

Bij gebruik van meerdere criteria kunnen de lambda-oproepen wat lang duren. Op dit moment kan het extraheren ervan als zelfstandige predikaten meer duidelijkheid bieden. Maar welke aanpak is sneller?

Eén filter met complexe conditie of meerdere filters?

Het hangt af van je hardware, hoe groot je verzameling is en of je parallelle streams gebruikt of niet. Over het algemeen zal één filter met een complexe conditie beter presteren dan meerdere filters met eenvoudigere condities (kleine tot middelgrote collecties), of op hetzelfde niveau presteren (zeer grote collecties). Als uw voorwaarden te lang zijn, kunt u er baat bij hebben ze over meerdere te verdelen filter() pleit voor een betere leesbaarheid, aangezien de prestaties erg op elkaar lijken.

De beste keuze is om beide te proberen, let op de prestaties op de doelapparaat, en pas uw strategie dienovereenkomstig aan.

GitHub-gebruiker volkodavs deed een filterbenchmark in doorvoerbewerkingen/s, en hostte de resultaten op de “javafilters-benchmarks” opslagplaats. De resultaten zijn samengevat in een informatieve tabel:

Het laat een duidelijke afname van het rendement zien bij grotere collecties, waarbij beide benaderingen ongeveer op hetzelfde niveau presteren. Parallelle streams profiteren aanzienlijk bij grotere collecties, maar beperken de prestaties bij kleinere formaten (minder dan ~10k elementen). Het is vermeldenswaard dat parallelle streams hun doorvoer veel beter behouden dan niet-parallelle streams, waardoor ze aanzienlijk robuuster zijn voor invoer.

Tijdstempel:

Meer van Stapelmisbruik