Stream API

פורסם בקבוצה
Stream API - 1

מהו Stream API?

ה-stream API הוא דרך חדשה לעבוד עם מבני נתונים בסגנון פונקציונלי. זרם API (תיאור של הדרכים שבהן תוכנת מחשב אחת יכולה לתקשר עם תוכנה אחרת) הוא, בבסיסו, זרם של נתונים. המונח "פתיל" עצמו די מעורפל בתכנות בכלל וב-Java בפרט.
Stream API - 1
עם הופעת Java 8, ה-API של Stream אפשר למתכנתים לכתוב הרבה יותר בקצרה מה שלקח בעבר שורות קוד רבות, כלומר לפשט את העבודה עם ערכות נתונים, בפרט, לפשט את פעולות הסינון, המיון ופעולות אחרות של מניפולציה של נתונים. אם אין לך פעולות ביניים, אתה יכול וצריך לעשות לעתים קרובות בלי זרם, אחרת הקוד יהיה מסובך יותר מאשר בלי זרם.
Stream API - 2
איפה בדיוק כדאי לי להתחיל? מיצירת מופע Stream, המבוסס על האיסוף, המערך או השיטה שאנו צריכים וממנו יילקחו הנתונים בהתאם:
List<String> list = new ArrayList<String>();
       list.add("One");
       list.add("Two");
       list.add("Three");
       list.add("Four");
       list.add("Five");
       list.add("Six");
       list.add("Seven");
       list.add("Eight");
       list.add("Nine");
       list.add("Ten");
       Stream stream = list.stream();
כפי שהוזכר לעיל, ה-Stream API מאפשר לך לצמצם את מספר שורות הקוד. דוגמה עם זרם:
IntStream.of(50, 60, 70, 80, 90, 100, 110, 120).filter(x -> x < 90).map(x -> x + 10)
.limit(3).forEach(System.out::print);
דוגמה ללא חוט:
int[] arr = {50, 60, 70, 80, 90, 100, 110, 120
	int count = 0;
	for (int x : arr) {
	    if (x >= 90) continue;
	    x += 10;
	    count++;
	    if (count > 3) break;
	    System.out.print(x);
	}
דרכים אפשריות ליצור זרם:
Stream API - 3
  • זרם ריק:Stream.empty()
  • שידור מהרשימה:list.stream()
  • זרם ממפה:map.entrySet().stream()
  • זרם מהמערך:Arrays.stream(array)
  • זרם מהאלמנטים שצוינו:Stream.of("1", "2", "3")
יתר על כן, יש דבר כזה אופרטורים (בעצם שיטות של מחלקה Stream). ניתן לחלק את המפעילים לשתי קבוצות:
  • ביניים (נקרא גם "עצלן") - עיבוד אלמנטים נכנסים והחזרת הזרם. יכולים להיות מפעילי ביניים רבים בשרשרת עיבוד האלמנטים.
  • טרמינל ("טרמינל", נקרא גם "להוט") - מעבד אלמנטים ומסיים את הזרם, כך שיכול להיות רק מפעיל טרמינל אחד בשרשרת.
דוגמא:
1.List<String> list = new ArrayList<String>();
2.list.add("One");11.list.add("Ten");
12.Stream stream = list.stream();
13.stream.filter(x-> x.toString().length() == 3).forEach(System.out::println);
מה קורה פה:
  • 1 - צור רשימה list;
  • 2-11 - מלא אותו בנתוני בדיקה;
  • 12 - ליצור אובייקט Stream;
  • 13 - שיטה filter(מסנן) - אופרטור ביניים, xמשווה לרכיב אחד של האוסף לספירה (כמו עם for each) ואחרי -> אנו מציינים כיצד האוסף שלנו מסונן ומכיוון שמדובר באופרטור ביניים, האוסף המסונן הולך יותר לתוך השיטה , forEachשבתורו הוא אנלוגי סופי (סופי) של ספירה for each(ביטוי System.out::printlnקיצור של:, x-> System.out.println(x))אשר בתורו עובר על כל מרכיבי האוסף המועברים אליו ומציג אותו)
Stream API - 5
נקודות חשובות:
  • העיבוד לא יתחיל עד שיתקשרו למפעיל המסוף. list.stream().filter(s -> s > 5)(לא ייקח אלמנט אחד מהרשימה);
  • לא ניתן להשתמש במופע של זרם יותר מפעם אחת =( ;
  • Stream API - 6

    לכן, בכל פעם שזה חדש:

    list.stream().filter(x-> x.toString().length() == 3).forEach(System.out::println);
    list.stream().forEach(x -> System.out.println(x));
  • יכולים להיות מפעילי ביניים רבים שנקראים בזרם אחד, בעוד שיש רק מפעיל מסוף אחד:

    stream.filter(x-> x.toString().length() == 3).map(x -> x + " - the length of the letters is three").forEach(x -> System.out.println(x));
לאחר מכן, בואו נסתכל על כמה אופרטורים ביניים:
Stream API - 7
  • filter(Predicate predicate)מסנן את הזרם, מעביר רק את האלמנטים שעוברים את התנאי (Predicate הוא ממשק פונקציונלי מובנה שנוסף לחבילה ב-Java SE 8. java.util.functionבודק את הערך של " true " ו- " false ");
  • map(Function mapper)מאפשר ליצור פונקציה איתה נשנה כל אלמנט ולדלג עליו הלאה (הממשק הפונקציונלי Function<T,R>מייצג את פונקציית המעבר מאובייקט מסוג T לאובייקט מסוג R)
  • flatMap(Function<T, Stream<R>> mapper)- כמו במקרה של map, הם משמשים להמרה לזרם פרימיטיבי.
כאשר עובדים, למשל, עם מערך של זרמים (מערכים, רשימות וכן הלאה), הוא ממיר אותם לזרם אחד (מערך, רשימה וכן הלאה [stream1,stream2,stream3,stream4] => stream:
String[] array = {"Java", "Ruuuuussshhh"};
Stream<String> streamOfArray = Arrays.stream(array);
streamOfArray.map(s->s.split("")) //Convert the word to an array of letters
        .flatMap(Arrays::stream).distinct() //aligns each generated thread into a single thread
        .collect(Collectors.toList()).forEach(System.out::println);
בזמן mapשהוא ממיר לרשימת שרשורים (ליתר דיוק <Stream>שרשורים) [stream1,stream2,stream3,stream4] =>Stream.of(stream1,stream2,stream3,stream4):
String[] array = {"Java", "Ruuuuussshhh"};
Stream<String> streamOfArray = Arrays.stream(array);
streamOfArray.map(s->s.split("")) //Convert the word to an array of letters
        .map(Arrays::stream).distinct() //Make the array into a separate thread
        .collect(Collectors.toList()).forEach(System.out::println);
הבדל נוסף לעומת map, אתה יכול להמיר אלמנט אחד לאפס, אחד או רבים אחרים. כדי להמיר אלמנט אחד לאפס אלמנטים, עליך להחזיר null, או זרם ריק. כדי להמיר לאלמנט אחד, עליך להחזיר זרם מאלמנט אחד, למשל, דרך Stream.of(x). כדי להחזיר מספר אלמנטים, ניתן ליצור זרם עם אלמנטים אלו בכל אמצעי. אותה שיטת flatMap, אבל עבור כפול, מספר שלם וארוך:
  • flatMapToDouble(מפה פונקציות)
  • flatMapToInt(מפה פונקציות)
  • flatMapToLong(מפה פונקציות)
ועוד דוגמה להשוואה, flatMap:
Stream.of(2, 3, 0, 1, 3)
        .flatMapToInt(x -> IntStream.range(0, x))
        .forEach(System.out::print);// 010120012
  • IntStream.range(0,x) - מפלט אלמנטים מ-0 (כולל) עד ​​x (לא כולל) לזרם;

    מַפָּה:

    Stream.of(2, 3, 0, 1, 3)
            .map(x -> IntStream.range(0, x))
            .forEach(System.out::print);//list of streams (streams);
  • limit(long maxSize) - מגביל את הזרם במספר האלמנטים:

    stream.limit(5).forEach(x -> System.out.println(x));
  • skip(long n) – דלג על n אלמנטים:

    stream.skip(3).forEach(x -> System.out.println(x));
  • מְמוּיָן()

  • sorted(Comparator comparator) - ממיין את הזרם (ממיין כמו TreeMap):

    stream.sorted().forEach(x -> System.out.println(x));
  • distinct() - בודק את הזרם עבור ייחודיות של אלמנטים (מסיר חזרות על אלמנטים);

  • dropWhile(Predicate Predicate) - מדלגת על אלמנטים העומדים בתנאי (הופיעו ב-java 9, הממשק הפונקציונלי Predicate<T> בודק אם תנאי כלשהו מתקיים. אם הוא מתקיים, אזי true מוחזר. ביטוי lambda לוקח אובייקט מסוג טיפוס T כפרמטר:

    Predicate<Integer> isPositive = x -> x > 0;
           System.out.println(isPositive.test(3)); // true
           System.out.println(isPositive.test(-9)); // false
מפעילי מסוף:
Stream API - 8
  • forEach(פעולת צרכן) – אנלוגי של עבור כל אחד (צרכן<T> מבצע פעולה כלשהי על אובייקט מסוג T, מבלי להחזיר דבר);

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

    System.out.println(stream.count());

  • collect(Collector collector) – השיטה אוספת את כל האלמנטים לרשימה, סט או אוסף אחר, מקבצת אלמנטים לפי קריטריון כלשהו, ​​משלבת הכל למחרוזת וכו':

    List<String> list = Stream.of(One,Two,Three).collect(Collectors.toList());
  • collect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner)- כמו , collect(collector)רק הפרמטרים מפורקים מטעמי נוחות ( supplierמספק אובייקטים חדשים (מכולות), למשל new ArrayList(), accumulatorמוסיף אלמנט למיכל, combinerמשלב חלקים מהנחל יחדיו);

  • reduce(T identity, BinaryOperator accumulator) - ממירה את כל האלמנטים של הזרם לאובייקט אחד (חשב את סכום כל האלמנטים, או מצא את האלמנט המינימלי), תחילה נלקחים האובייקט identityוהאלמנט הראשון של הזרם, הפונקציה מוחלת accumulatorוהתוצאה identityשלו הופכת. ואז הכל ממשיך עבור האלמנטים הנותרים.

    int sum = Stream.of(1, 2, 3, 4, 5).reduce(10, (acc, x) -> acc + x);// = 25
  • reduce(BinaryOperator accumulator)- אותה שיטה כמו לעיל אבל הראשונית חסרה identity, זה האלמנט הראשון של הנחל

    Optional min(Comparator comparator)
    max(Comparator comparator) אופציונלי מחפש את רכיב המינימום/מקסימום בהתבסס על המשווה שעבר;

  • findFirst()- שולף את האלמנט הראשון של הזרם:

    Stream.of(1, 2, 3, 4, 9).findFirst();
  • allMatch(Predicate predicate)- מחזירה true אם כל הרכיבים של הזרם עומדים בתנאי. אם נתקלים באלמנט כלשהו שהתוצאה של הקריאה לפונקציית הפרדיקט עבורו היא false , אז האופרטור מפסיק לסרוק את האלמנטים ומחזיר false :

    Stream.of(1, 2, 3, 4, 9).allMatch(x -> x <= 7);//false
  • anyMatch(Predicate predicate)- יחזיר אמת אם לפחות אלמנט אחד של הזרם יעמוד בתנאי predicate:

    Stream.of(1, 2, 3, 4, 9).anyMatch(x -> x >= 7);//true
  • noneMatch(Predicate predicate)- יחזור אמת אם, לאחר שעבר על כל מרכיבי הנחל, אף אחד מהם לא עמד בתנאי predicate:

    Stream.of(1, 2, 3, 4, 9).noneMatch(x -> x >= 7);//false
ולבסוף אני רוצה להסתכל על כמה שיטות Collectors:
  • toList()- אוסף אלמנטים ל List:

    List<Integer> list = Stream.of(99, 2, 3).collect(Collectors.toList());
  • toSet()- אוסף אלמנטים לקבוצה:

    Set<Integer> set = Stream.of(99, 2, 3).collect(Collectors.toSet());
  • counting()- סופר את מספר האלמנטים:

    Long count = Stream.of("1", "2", "3", "4").collect(Collectors.counting());
  • joining()

  • joining(CharSequence delimiter)

  • joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix)- אוסף אלמנטים לשורה אחת. בנוסף, אתה יכול לציין מפריד, כמו גם קידומת וסיומת עבור הרצף כולו:

    String a = Stream.of("s", "u" ,"p", "e", "r").collect(Collectors.joining());
           System.out.println(a); // super
    
           String b = Stream.of("s", "u", "p", "e", "r").collect(Collectors.joining("-"));
           System.out.println(b); // s-u-p-e-r
    
           String c = Stream.of("s", "u", "p", "e", "r").collect(Collectors.joining(" -> ", "[ ", " ]"));
           System.out.println(c);  // [ s -> u -> p -> e -> r ]
  • summingInt(ToIntFunction mapper)

  • summingLong(ToLongFunction mapper)

  • summingDouble(ToDoubleFunction mapper)- אספן הממיר חפצים ל-int/long/double ומחשב את הסכום.

קישורים שימושיים: נ.ב: אל תתביישו להרעיף עלינו לייקים ^ : ^
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION