Java - Filtrați un flux cu expresii Lambda PlatoBlockchain Data Intelligence. Căutare verticală. Ai.

Java – Filtrați un flux cu expresii Lambda

Fluxurile Java au fost introduse până acum în Java 8 în 2014, într-un efort de a introduce Java detaliat într-o paradigmă de programare funcțională. Fluxurile Java expun multe operațiuni funcționale flexibile și puternice pentru a efectua procesarea colectării într-o singură linie.

Filtrarea colecțiilor bazate pe un predicat rămâne una dintre cele mai frecvent utilizate operații funcționale și poate fi efectuată cu o Predicate sau mai concis – cu a Expresia Lambda.

În acest scurt ghid, vom arunca o privire asupra modului în care puteți filtra un flux Java 8 cu expresii Lambda.

Filtrarea fluxurilor în Java

În general, orice Stream poate fi filtrat prin intermediul filter() metoda și un predicat dat:

Stream filter(Predicate<? super T> predicate)

Fiecare element din flux este rulat pe predicat și este adăugat la fluxul de ieșire dacă predicatul revine true. Puteți furniza a Predicate instanță:

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

Sau, simplificați-l furnizând o expresie Lambda:

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

Sau chiar prăbușiți expresia Lambda într-un referință la metodă:


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

Cu referințe la metode, nu puteți transmite argumente, totuși, puteți defini metode în obiectul pe care îl filtrați și le puteți adapta pentru a fi ușor filtrabile (atâta timp cât metoda nu acceptă argumente și returnează un boolean).

Amintiți-vă că fluxurile nu sunt colecții – sunt pârâuri a colecţiilor, și va trebui să le colectați înapoi în orice colecție, cum ar fi a List, Map, etc pentru a le da permanență. În plus, toate operațiunile efectuate pe elemente de flux fie intermediar or terminal:

  • Operațiunile intermediare returnează un nou flux cu modificări față de operația anterioară
  • Operațiunile terminale returnează un tip de date și sunt menite să încheie o conductă de procesare pe un flux

filter() este o intermediar operațiune și este menit să fie înlănțuit cu alte operațiuni intermediare, înainte ca fluxul să fie terminat. Pentru a persista orice modificări (cum ar fi modificări ale elementelor în sine sau rezultate filtrate), va trebui să atribuiți flux de ieșire la o nouă variabilă de referință, printr-o operație terminală.

Notă: Chiar și atunci când înlănțuiți multe expresii lambda, este posibil să nu întâmpinați probleme de lizibilitate, cu întreruperi de linie adecvate.

În următoarele exemple, vom lucra cu această listă de cărți:

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);

Filtrați colecția cu Stream.filter()

Să filtrăm această colecție de cărți. Orice predicat merge – deci haideți, de exemplu, să filtrăm după ce cărți au peste 400 de pagini:

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

Rezultă o listă care conține:

[
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}
]

Când filtrați, o metodă cu adevărat utilă de înlănțuire este map(), care vă permite să mapați obiecte la o altă valoare. De exemplu, putem mapa fiecare carte după numele ei și astfel returnăm doar nume a cărților care se potrivesc cu predicatul din filter() apel:

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

Rezultă o listă de șiruri de caractere:

[Our Mathematical Universe, Sapiens]

Filtrați colecția pe mai multe predicate cu Stream.filter()

În mod obișnuit, am dori să filtram colecțiile după mai multe criterii. Acest lucru se poate face prin înlănțuirea mai multor filter() Apeluri or folosind un predicat de scurtcircuit, care verifică două condiții într-o singură filter() apel.

 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());

Consultați ghidul nostru practic și practic pentru a învăța Git, cu cele mai bune practici, standarde acceptate de industrie și fisa de cheat incluse. Opriți căutarea pe Google a comenzilor Git și de fapt învăţa aceasta!

Când se utilizează mai multe criterii - apelurile lambda pot deveni oarecum lungi. În acest moment, extragerea lor ca predicate autonome ar putea oferi mai multă claritate. Totuși, care abordare este mai rapidă?

Un singur filtru cu stare complexă sau mai multe filtre?

Depinde de hardware-ul tău, cât de mare este colecția ta și dacă folosești sau nu fluxuri paralele. În general, un filtru cu o condiție complexă va depăși mai multe filtre cu condiții mai simple (colecții mici spre medii) sau va funcționa la același nivel (colecții foarte mari). Dacă condițiile dumneavoastră sunt prea lungi – puteți beneficia de distribuirea lor în mai multe filter() solicită o lizibilitate îmbunătățită, deoarece performanța este foarte asemănătoare.

Cea mai bună alegere este să le încercați pe ambele, notați performanța pe dispozitiv țintăși ajustați-vă strategia în consecință.

utilizator GitHub volkodavs a făcut un benchmark de filtrare în operațiuni de debit/e și a găzduit rezultatele pe „javafilters-benchmarks” repertoriu. Rezultatele sunt rezumate într-un tabel informativ:

Arată o scădere clară a randamentelor la dimensiuni mai mari ale colecțiilor, ambele abordări având performanțe aproximativ la același nivel. Fluxurile paralele beneficiază semnificativ de colecții de dimensiuni mai mari, dar reduc performanța la dimensiuni mai mici (sub ~10k elemente). Este de remarcat faptul că fluxurile paralele și-au menținut debitul mult mai bine decât fluxurile neparalele, făcându-le semnificativ mai robuste la intrare.

Timestamp-ul:

Mai mult de la Stackabuse