Java - סינון זרם עם Lambda Expressions PlatoBlockchain Data Intelligence. חיפוש אנכי. איי.

Java - סנן זרם עם ביטויי למבדה

זרמי Java הוצגו כל הדרך ב-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 ולמעשה ללמוד זה!

כאשר משתמשים במספר קריטריונים - שיחות הלמבדה יכולות להתארך מעט. בשלב זה, חילוץ שלהם כפרדיקטים עצמאיים עשוי להציע יותר בהירות. עם זאת, איזו גישה מהירה יותר?

פילטר בודד במצב מורכב או מסננים מרובים?

זה תלוי בחומרה שלך, כמה גדול האוסף שלך, והאם אתה משתמש בזרמים מקבילים או לא. באופן כללי – פילטר אחד עם מצב מורכב יעפיל על מספר מסננים עם תנאים פשוטים יותר (אוספים קטנים עד בינוניים), או יבצע באותה רמה (אוספים גדולים מאוד). אם התנאים שלך ארוכים מדי - אתה עשוי להפיק תועלת מחלוקתם על מספר רב filter() קורא לשיפור הקריאות, שכן הביצועים דומים מאוד.

הבחירה הטובה ביותר היא לנסות את שניהם, שימו לב לביצועים ב- מכשיר מטרה, והתאם את האסטרטגיה שלך בהתאם.

משתמש GitHub volkodavs עשה מדד סינון בפעולות/ות תפוקה, ואירח את התוצאות ב- "אמות מידה של javafilters" מאגר. התוצאות מסוכמות בטבלה אינפורמטיבית:

זה מראה ירידה ברורה בהחזרות בגדלים גדולים יותר של אוסף, כאשר שתי הגישות מתפקדות בערך באותה רמה. זרמים מקבילים מרוויחים באופן משמעותי בגדלים גדולים יותר של אוסף, אך מרסנים את הביצועים בגדלים קטנים יותר (מתחת ל-10 אלמנטים). ראוי לציין שזרמים מקבילים שמרו על התפוקה שלהם הרבה יותר טוב מאשר זרמים לא מקבילים, מה שהופך אותם לחזקים משמעותית לקלט.

בול זמן:

עוד מ Stackabuse