מהו Stream API?
ה-stream API הוא דרך חדשה לעבוד עם מבני נתונים בסגנון פונקציונלי. זרם API (תיאור של הדרכים שבהן תוכנת מחשב אחת יכולה לתקשר עם תוכנה אחרת) הוא, בבסיסו, זרם של נתונים. המונח "פתיל" עצמו די מעורפל בתכנות בכלל וב-Java בפרט.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.empty()
- שידור מהרשימה:
list.stream()
- זרם ממפה:
map.entrySet().stream()
- זרם מהמערך:
Arrays.stream(array)
- זרם מהאלמנטים שצוינו:
Stream.of("1", "2", "3")
- ביניים (נקרא גם "עצלן") - עיבוד אלמנטים נכנסים והחזרת הזרם. יכולים להיות מפעילי ביניים רבים בשרשרת עיבוד האלמנטים.
- טרמינל ("טרמינל", נקרא גם "להוט") - מעבד אלמנטים ומסיים את הזרם, כך שיכול להיות רק מפעיל טרמינל אחד בשרשרת.
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))
אשר בתורו עובר על כל מרכיבי האוסף המועברים אליו ומציג אותו)
- העיבוד לא יתחיל עד שיתקשרו למפעיל המסוף.
list.stream().filter(s -> s > 5)
(לא ייקח אלמנט אחד מהרשימה); - לא ניתן להשתמש במופע של זרם יותר מפעם אחת =( ;
לכן, בכל פעם שזה חדש:
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));
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(מפה פונקציות)
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
-
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 ומחשב את הסכום.
GO TO FULL VERSION