זרם ב-Java

זרם ב-Java

זרם הוצג ב Java 8 ה- Stream API משמש לעיבוד אוספים של אובייקטים. זרם ב-Java הוא רצף של אובייקטים התומך בשיטות שונות שניתן לבצע בצינור כדי להפיק את התוצאה הרצויה. 

שימוש ב-Stream ב-Java

השימושים של Stream ב-Java מוזכרים להלן:

  • Stream API היא דרך לבטא ולעבד אוספים של אובייקטים.
  • אפשרו לנו לבצע פעולות כמו סינון מיפוי צמצום ומיון.

כיצד ליצור זרם Java

יצירת זרם Java היא אחד השלבים הבסיסיים ביותר לפני ששוקלים את הפונקציונליות של זרם Java. להלן התחביר שניתן להכרזה על זרם Java.

תַחבִּיר

זֶרֶם זֶרֶם;

כאן T הוא אובייקט מחלקה או סוג נתונים בהתאם להצהרה.

תכונות זרם Java

התכונות של זרמי Java מוזכרות להלן:

  • זרם אינו מבנה נתונים; זה רק לוקח קלט מערכי קולקציות או ערוצי קלט/פלט.
  • זרמים אינם משנים את הנתונים המקוריים; הם מייצרים תוצאות רק באמצעות השיטות שלהם.
  • פעולות ביניים (כמו מפת סינון וכו') עצלניות ומחזירות עוד זרם כדי שתוכלו לשרשר אותן יחד.
  • פעולת טרמינל (כמו collect forEach count) מסיימת את הזרם ונותנת את התוצאה הסופית.

פעולות שונות בזרמים

ישנם שני סוגים של פעולות בזרמים:

  1. פעולות ביניים
  2. תפעול מסוף

פעולות ביניים

פעולות זרם Java

פעולות ביניים הן סוגי הפעולות שבהן משורשרות שיטות מרובות ברצף.

מאפיינים של פעולות ביניים

  • שיטות משורשרות יחד.
  • פעולות ביניים הופכות זרם לזרם אחר.
  • זה מאפשר את הרעיון של סינון שבו שיטה אחת מסננת נתונים ומעבירה אותם לשיטה אחרת לאחר עיבוד.

פעולות ביניים חשובות

להלן מספר פעולות ביניים:

1. map() : שיטת המפה משמשת להחזרת זרם המורכב מתוצאות החלת הפונקציה הנתונה על האלמנטים של זרם זה.

תַחבִּיר:

זֶרֶם מפה (פונקציה ממפה)

2. מסנן() : שיטת הסינון משמשת לבחירת אלמנטים לפי הפרדיקט המועבר כארגומנט.

תַחבִּיר:

זֶרֶם מסנן (פרדיקט לְבַסֵס)

3. sorted() : השיטה הממוינת משמשת למיון הזרם.

תַחבִּיר:

זֶרֶם מְמוּיָן()
זֶרֶם sorted(Comparator משווה)

4. flatMap(): פעולת flatMap ב-Java Streams משמשת כדי לשטח זרם של אוספים לזרם יחיד של אלמנטים.

תַחבִּיר:

זֶרֶם flatMap(פונקציה > ממפה)

5. distinct() : מסיר רכיבים כפולים. הוא מחזיר זרם המורכב מהאלמנטים הנבדלים (לפי Object.equals(Object)).

תַחבִּיר:

זֶרֶם מוּבהָק()

6. הצצה() : מבצע פעולה בכל רכיב מבלי לשנות את הזרם. הוא מחזיר זרם המורכב מהאלמנטים של הזרם הזה ובנוסף מבצע את הפעולה שסופקה על כל אלמנט כאשר אלמנטים נצרכים מהזרם שנוצר.

תַחבִּיר:

זֶרֶם הצצה (צרכן פְּעוּלָה)

תוכנת Java המדגימה את השימוש בכל פעולות הביניים:

Java
   import     java.util.Arrays  ;   import     java.util.HashSet  ;   import     java.util.List  ;   import     java.util.Set  ;   import     java.util.stream.Collectors  ;   public     class   StreamIntermediateOperationsExample     {      public     static     void     main  (  String  []     args  )     {      // List of lists of names      List   <  List   <  String  >>     listOfLists     =     Arrays  .  asList  (      Arrays  .  asList  (  'Reflection'       'Collection'       'Stream'  )      Arrays  .  asList  (  'Structure'       'State'       'Flow'  )      Arrays  .  asList  (  'Sorting'       'Mapping'       'Reduction'       'Stream'  )      );      // Create a set to hold intermediate results      Set   <  String  >     intermediateResults     =     new     HashSet   <>  ();      // Stream pipeline demonstrating various intermediate operations      List   <  String  >     result     =     listOfLists  .  stream  ()      .  flatMap  (  List  ::  stream  )         .  filter  (  s     ->     s  .  startsWith  (  'S'  ))         .  map  (  String  ::  toUpperCase  )         .  distinct  ()         .  sorted  ()         .  peek  (  s     ->     intermediateResults  .  add  (  s  ))      .  collect  (  Collectors  .  toList  ());         // Print the intermediate results      System  .  out  .  println  (  'Intermediate Results:'  );      intermediateResults  .  forEach  (  System  .  out  ::  println  );      // Print the final result      System  .  out  .  println  (  'Final Result:'  );      result  .  forEach  (  System  .  out  ::  println  );      }   }   

תְפוּקָה
Intermediate Results: STRUCTURE STREAM STATE SORTING Final Result: SORTING STATE STREAM STRUCTURE  

הֶסבֵּר:

  • ה-listOfLists נוצר כרשימה המכילה רשימות אחרות של מחרוזות.
  • flatMap(List::stream): משטח את הרשימות המקוננות לזרם יחיד של מחרוזות.
  • מסנן(ים -> s.startsWith('S')) : מסנן את המחרוזות כך שיכלול רק את אלה שמתחילות ב-'S'.
  • map(String::toUpperCase) : ממירה כל מחרוזת בזרם לאותיות רישיות.
  • מוּבהָק() : מסיר מחרוזות כפולות.
  • מְמוּיָן() : ממיין את המחרוזות המתקבלות בסדר אלפביתי.
  • לְהָצִיץ(...): מוסיף כל רכיב מעובד לקבוצת הבינייםResults לבדיקת ביניים.
  • collect(Collectors.toList()): אוסף את המחרוזות המעובדות הסופיות לרשימה שנקראת תוצאה.

התוכנית מדפיסה את תוצאות הביניים המאוחסנות בערכת תוצאות הביניים. לבסוף הוא מדפיס את רשימת התוצאות המכילה את המחרוזות המעובדות במלואן לאחר כל פעולות הזרם.

תפעול מסוף

פעולות מסוף הן סוג הפעולות שמחזירות את התוצאה. פעולות אלו אינן מעובדות יותר רק מחזירות ערך תוצאה סופי.

פעולות טרמינל חשובות

1. collect() : שיטת האיסוף משמשת להחזרת התוצאה של פעולות הביניים שבוצעו בזרם.

תַחבִּיר:

R collect(אספן אַסְפָן)

2. forEach() : שיטת forEach משמשת לחזרה על כל רכיב בזרם.

תַחבִּיר:

void forEach(Consumer פְּעוּלָה)

3. להפחית(): שיטת ההפחתה משמשת לצמצום הרכיבים של זרם לערך בודד. שיטת ההפחתה לוקחת את BinaryOperator כפרמטר.

תַחבִּיר:

T reduce(T identity BinaryOperator מַצבֵּר)
אופציונלי reduce(BinaryOperator מַצבֵּר)

4. count() : מחזירה את ספירת הרכיבים בזרם.

תַחבִּיר:

ספירה ארוכה()

5. findFirst() : מחזירה את הרכיב הראשון של הזרם אם קיים.

תַחבִּיר:

אופציונלי findFirst()

6. allMatch() : בודק אם כל הרכיבים של הזרם תואמים לפרדיקט נתון.

תַחבִּיר:

boolean allMatch(Predicate לְבַסֵס)

7. Anymatch () : בודק אם רכיב כלשהו בזרם תואם לפרדיקט נתון.

תַחבִּיר:

בוליאנית Anymatch (פרדיקט לְבַסֵס)

כאן ans משתנה מוקצה 0 כערך ההתחלתי ו-i מתווסף אליו.

פֶּתֶק: פעולות ביניים פועלות על בסיס הרעיון של Lazy Evaluation אשר מבטיח שכל שיטה מחזירה ערך קבוע (פעולת טרמינל) לפני המעבר לשיטה הבאה.

תוכנית Java המשתמשת בכל פעולות המסוף:

Java
   import     java.util.*  ;   import     java.util.stream.Collectors  ;   public     class   StreamTerminalOperationsExample     {      public     static     void     main  (  String  []     args  )     {      // Sample data      List   <  String  >     names     =     Arrays  .  asList  (      'Reflection'       'Collection'       'Stream'        'Structure'       'Sorting'       'State'      );      // forEach: Print each name      System  .  out  .  println  (  'forEach:'  );      names  .  stream  ().  forEach  (  System  .  out  ::  println  );      // collect: Collect names starting with 'S' into a list      List   <  String  >     sNames     =     names  .  stream  ()      .  filter  (  name     ->     name  .  startsWith  (  'S'  ))      .  collect  (  Collectors  .  toList  ());      System  .  out  .  println  (  'ncollect (names starting with 'S'):'  );      sNames  .  forEach  (  System  .  out  ::  println  );      // reduce: Concatenate all names into a single string      String     concatenatedNames     =     names  .  stream  ().  reduce  (      ''        (  partialString       element  )     ->     partialString     +     ' '     +     element      );      System  .  out  .  println  (  'nreduce (concatenated names):'  );      System  .  out  .  println  (  concatenatedNames  .  trim  ());      // count: Count the number of names      long     count     =     names  .  stream  ().  count  ();      System  .  out  .  println  (  'ncount:'  );      System  .  out  .  println  (  count  );      // findFirst: Find the first name      Optional   <  String  >     firstName     =     names  .  stream  ().  findFirst  ();      System  .  out  .  println  (  'nfindFirst:'  );      firstName  .  ifPresent  (  System  .  out  ::  println  );      // allMatch: Check if all names start with 'S'      boolean     allStartWithS     =     names  .  stream  ().  allMatch  (      name     ->     name  .  startsWith  (  'S'  )      );      System  .  out  .  println  (  'nallMatch (all start with 'S'):'  );      System  .  out  .  println  (  allStartWithS  );      // anyMatch: Check if any name starts with 'S'      boolean     anyStartWithS     =     names  .  stream  ().  anyMatch  (      name     ->     name  .  startsWith  (  'S'  )      );      System  .  out  .  println  (  'nanyMatch (any start with 'S'):'  );      System  .  out  .  println  (  anyStartWithS  );      }   }   

תְפוּקָה:

StreamsOutputתְפוּקָה

הֶסבֵּר:

  • רשימת השמות נוצרת עם מחרוזות לדוגמה.
  • לכל אחד: מדפיס כל שם ברשימה.
  • לֶאֱסוֹף : מסנן שמות שמתחילים ב-'S' ואוסף אותם לרשימה חדשה.
  • לְהַפחִית : משרשרת את כל השמות למחרוזת אחת.
  • לִסְפּוֹר : סופר את המספר הכולל של שמות.
  • מצא ראשון : מוצא ומדפיס את השם הפרטי ברשימה.
  • allMatch : בודק אם כל השמות מתחילים ב-'S'.
  • בִּישׁ מַזָל : בודק אם שם כלשהו מתחיל ב-'S'.

התוכנית מדפיסה כל שם שמות מתחילים ב-'S' שמות משורשרים את ספירת השמות את השם הפרטי בין אם כל השמות מתחילים ב-'S' והאם שם כלשהו מתחיל ב-'S'.

היתרון של Java Stream

ישנם כמה יתרונות שבגללם אנו משתמשים ב-Stream ב-Java כפי שהוזכר להלן:

  • אין אחסון
  • צינור של פונקציות
  • עַצלוּת
  • יכול להיות אינסופי
  • ניתן להקביל
  • ניתן ליצור ממערכי אוספים שיטות קווים ב-Stream IntStream וכו'.

מקרי שימוש בעולם האמיתי של זרמי Java

זרמים נמצאים בשימוש נרחב ביישומי Java מודרניים עבור:

  • עיבוד נתונים
  • לעיבוד תגובות JSON/XML
  • עבור פעולות מסד נתונים
  • עיבוד במקביל