Java - Φιλτράρετε μια ροή με Εκφράσεις Lambda PlatoBlockchain Data Intelligence. Κάθετη αναζήτηση. Ολα συμπεριλαμβάνονται.

Java – Φιλτράρετε μια ροή με εκφράσεις λάμδα

Τα Java Streams εισήχθησαν στην Java 8 το 2014, σε μια προσπάθεια να εισαγάγουν τη λεπτομερή Java σε ένα παράδειγμα λειτουργικού προγραμματισμού. Τα Java Streams εκθέτουν πολλές ευέλικτες και ισχυρές λειτουργικές λειτουργίες για την εκτέλεση επεξεργασίας συλλογής σε one-liners.

Το φιλτράρισμα συλλογών που βασίζονται σε κάποιο κατηγορούμενο παραμένει μια από τις πιο συχνά χρησιμοποιούμενες λειτουργικές λειτουργίες και μπορεί να εκτελεστεί με Predicate ή πιο συνοπτικά – με α Έκφραση λάμδα.

Σε αυτόν τον σύντομο οδηγό, θα ρίξουμε μια ματιά στο πώς μπορείτε να φιλτράρετε μια ροή Java 8 με Εκφράσεις Lambda.

Φιλτράρισμα ροών σε Java

Σε γενικές γραμμές, οποιαδήποτε Stream μπορεί να φιλτραριστεί μέσω του filter() μέθοδος και ένα δεδομένο κατηγόρημα:

Stream filter(Predicate<? super T> predicate)

Κάθε στοιχείο στη ροή εκτελείται ενάντια στο κατηγόρημα και προστίθεται στη ροή εξόδου εάν το κατηγόρημα επιστρέψει true. Μπορείτε να παρέχετε ένα Predicate παράδειγμα:

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

Ή, απλοποιήστε το παρέχοντας μια έκφραση λάμδα:

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

Ή ακόμα να συμπτύξετε την Έκφραση Λάμδα σε α αναφορά μεθόδου:


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

Με τις αναφορές μεθόδων, δεν μπορείτε να μεταβιβάσετε ορίσματα, ωστόσο, μπορείτε να ορίσετε μεθόδους στο αντικείμενο που φιλτράρετε και να τις προσαρμόσετε ώστε να είναι εύκολα φιλτραρίσιμα (εφόσον η μέθοδος δεν δέχεται ορίσματα και επιστρέφει boolean).

Να θυμάστε ότι τα ρεύματα δεν είναι συλλογές – είναι ρέματα των συλλογών, και θα πρέπει να τα συλλέξετε ξανά σε οποιαδήποτε συλλογή, όπως π.χ List, Mapκτλ για να τους δώσει μονιμότητα. Επιπλέον, όλες οι λειτουργίες γίνονται σε στοιχεία ροής είτε ενδιάμεσος or τερματικό:

  • Οι ενδιάμεσες λειτουργίες επιστρέφουν μια νέα ροή με αλλαγές από την προηγούμενη λειτουργία
  • Οι λειτουργίες τερματικού επιστρέφουν έναν τύπο δεδομένων και προορίζονται να τερματίσουν έναν αγωγό επεξεργασίας σε μια ροή

filter() είναι ένα ενδιάμεσος λειτουργία και προορίζεται να συνδεθεί με άλλες ενδιάμεσες λειτουργίες, πριν τερματιστεί η ροή. Για να διατηρηθούν οι αλλαγές (όπως αλλαγές στα ίδια τα στοιχεία ή φιλτραρισμένα αποτελέσματα), θα πρέπει να αντιστοιχίσετε τα προκύπτοντα ροή εξόδου σε μια νέα μεταβλητή αναφοράς, μέσω μιας λειτουργίας τερματικού.

Σημείωση: Ακόμη και όταν συνδέετε πολλές εκφράσεις λάμδα, ενδέχεται να μην αντιμετωπίσετε προβλήματα αναγνωσιμότητας, με τις κατάλληλες αλλαγές γραμμής.

Στα ακόλουθα παραδείγματα, θα εργαστούμε με αυτήν τη λίστα βιβλίων:

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

Συλλογή φίλτρων με Stream.filter()

Ας φιλτράρουμε αυτή τη συλλογή βιβλίων. Οποιοδήποτε κατηγόρημα ισχύει – οπότε ας φιλτράρουμε, για παράδειγμα, το ποια βιβλία έχουν περισσότερες από 400 σελίδες:

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

Αυτό οδηγεί σε μια λίστα που περιέχει:

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

Κατά το φιλτράρισμα, μια πραγματικά χρήσιμη μέθοδος για την αλυσίδα είναι map(), που σας επιτρέπει να αντιστοιχίσετε αντικείμενα σε άλλη τιμή. Για παράδειγμα, μπορούμε να αντιστοιχίσουμε κάθε βιβλίο στο όνομά του και έτσι να επιστρέψουμε μόνο το ονόματα των βιβλίων που ταιριάζουν στο κατηγόρημα από το filter() κλήση:

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

Αυτό οδηγεί σε μια λίστα με συμβολοσειρές:

[Our Mathematical Universe, Sapiens]

Συλλογή φίλτρων σε πολλαπλά κατηγορήματα με Stream.filter()

Συνήθως, θα θέλαμε να φιλτράρουμε τις συλλογές με περισσότερα από ένα κριτήρια. Αυτό μπορεί να γίνει με την αλυσίδα πολλαπλών filter() κλήσεις or χρησιμοποιώντας ένα κατηγόρημα βραχυκυκλώματος, το οποίο ελέγχει δύο συνθήκες σε ένα μόνο filter() κλήση.

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

Ρίξτε μια ματιά στον πρακτικό μας οδηγό για την εκμάθηση του Git, με βέλτιστες πρακτικές, πρότυπα αποδεκτά από τον κλάδο και συμπεριλαμβανόμενο φύλλο εξαπάτησης. Σταματήστε τις εντολές του Git στο Google και πραγματικά μαθαίνουν το!

Κατά τη χρήση πολλαπλών κριτηρίων – οι κλήσεις λάμδα μπορεί να είναι κάπως μεγάλες. Σε αυτό το σημείο, η εξαγωγή τους ως μεμονωμένα κατηγορήματα μπορεί να προσφέρει περισσότερη σαφήνεια. Ωστόσο, ποια προσέγγιση είναι πιο γρήγορη;

Μονό φίλτρο με σύνθετη κατάσταση ή πολλαπλά φίλτρα;

Εξαρτάται από το υλικό σας, πόσο μεγάλη είναι η συλλογή σας και αν χρησιμοποιείτε παράλληλες ροές ή όχι. Γενικά – ένα φίλτρο με σύνθετη συνθήκη θα έχει καλύτερη απόδοση πολλών φίλτρων με απλούστερες συνθήκες (συλλογές από μικρές έως μεσαίες) ή θα έχει απόδοση στο ίδιο επίπεδο (πολύ μεγάλες συλλογές). Εάν οι συνθήκες σας είναι πολύ μεγάλες – μπορεί να επωφεληθείτε από τη διανομή τους σε πολλαπλούς filter() απαιτεί βελτιωμένη αναγνωσιμότητα, καθώς η απόδοση είναι πολύ παρόμοια.

Η καλύτερη επιλογή είναι να δοκιμάσετε και τα δύο, σημειώστε την απόδοση στο συσκευή προορισμούκαι προσαρμόστε τη στρατηγική σας ανάλογα.

Χρήστης GitHub volkodavs έκανε ένα κριτήριο φιλτραρίσματος στις λειτουργίες/εις διεκπεραιωτικότητας και φιλοξένησε τα αποτελέσματα στο "javafilters-benchmarks" αποθήκη. Τα αποτελέσματα συνοψίζονται σε έναν ενημερωτικό πίνακα:

Δείχνει μια σαφή μείωση των αποδόσεων σε μεγαλύτερα μεγέθη συλλογής, με τις δύο προσεγγίσεις να αποδίδουν περίπου στο ίδιο επίπεδο. Οι παράλληλες ροές ωφελούνται σημαντικά σε μεγαλύτερα μεγέθη συλλογής, αλλά περιορίζουν την απόδοση σε μικρότερα μεγέθη (κάτω από ~10k στοιχεία). Αξίζει να σημειωθεί ότι οι παράλληλες ροές διατήρησαν την απόδοση τους πολύ καλύτερα από τις μη παράλληλες ροές, καθιστώντας τις σημαντικά πιο ισχυρές στην είσοδο.

Σφραγίδα ώρας:

Περισσότερα από Stackabuse