Upcoming SlideShare
×

# Java8 stream

1,631 views

Published on

Published in: Technology
8 Likes
Statistics
Notes
• Full Name
Comment goes here.

Are you sure you want to Yes No
• Be the first to comment

Views
Total views
1,631
On SlideShare
0
From Embeds
0
Number of Embeds
9
Actions
Shares
0
44
0
Likes
8
Embeds 0
No embeds

No notes for slide

### Java8 stream

1. 1. Java 8 Stream @kojilin 2014/3/29@TWJUG
2. 2. Stream •java.util.stream •Support functional-style operations on streams of elements  int sum =   widgetList.stream()  .filter(b -> b.color == RED)  .mapToInt(b -> b.getWeight())  .sum();
3. 3. External Iteration long sum = 0; for(int i = 0; i < N; ++i){ sum += i * i; }
4. 4. Internal Iteration long sum = LongStream .range(0, N) .map(i -> i * i) .sum();
5. 5. •為什麼需要 Stream ? •從外部迭代轉為內部迭代 •外部迭代需要注意要做什麼跟如何做 •內部迭代著重在要做什麼比如何做更多 •將行為資料化 •讓函式庫幫你更多的忙 •讓程式碼更簡潔好讀
6. 6. Stream •Stream 不是資料結構，沒有 存資料 •包裹在現有的資料結構之上 •透過內部迭代 •Multi-thread •Laziness •Stream 有 iterator 方法，但沒有實作 Iterable •所以不能寫 for (String item : stream)
7. 7. Stream 的種類 •Stream<T> •Primitive Streams •IntStream •DoubleStream •LongStream •彼此之間可以透過像 mapToInt, mapToDouble, mapToObj 等方式切換
8. 8. Stream 的使用方式 long sum = LongStream .range(0, N) .map(i -> i * i) .filter(i -> i % 2 == 0) .sum(); •建立 Stream
9. 9. Stream 的使用方式 long sum = LongStream .range(0, N) .map(i -> i * i) .filter(i -> i % 2 == 0) .sum(); •透過連續的 intermediate operation 操作
10. 10. Stream 的使用方式 long sum = LongStream .range(0, N) .map(i -> i * i) .filter(i -> i % 2 == 0) .sum(); •最後用 terminal operation 結束
11. 11. 如何取得 Stream? •Collection#stream() •Arrays.stream(Object[]) •Stream.of(Object[]) •IntStream.range(int, int) •BufferedReader#lines() •Stream#filter() •etc.
12. 12. Intermediate Operation •回傳 Stream，可以接下一個 operation •Lazy •直到遇到 terminal operation 的方法前不 會有效果
13. 13. •ﬁlter  •map  •ﬂatMap    •sorted stream.filter( p -> p > 20); stream.map( p -> p.name); stream.flatMap( p ->   p.cars.stream()); stream.sorted(p1, p2 ->   p1.name.compareTo(p2.name));
14. 14. •limit  •distinct  •skip stream.limit(5); stream.distinct(); stream.skip(5);
15. 15. Stateful & Stateless •Stateful 表示在操作元素時，除了當下的元 素外需要考慮其他狀態 •sorted, skip, limit •Stateless 表示在操作元素時，除了當下的元 素外不用考慮其他狀態 •ﬁlter, map
16. 16. Terminal Operation •不會回傳 stream，整個 stream 只能有一個 terminal operation 呼叫 •呼叫後才會開始走查 stream，最後產生並回 傳結果或是製造 side-eﬀect •呼叫完 terminal operation 後 stream 會被 當作被使用完畢 •Stream -> (Intermediate)* -> Terminal
17. 17. •forEach  •reduce  •collect    •count stream.forEach( p -> print(p)); stream.reduce( 0, (a, b) -> a + b); stream.collect(  Collectors.toList()); stream.count();
18. 18. •toArray  •max  •sum ( Primitive Stream )  •average ( Primitive Stream ) stream.toArray(String[]::new); stream.max(String::compareTo); intStream.sum(); intStream.average();
19. 19. Reduction •將元素組合成一個結果 •reduce, collect, sum, max, count intStream.sum(); numbers.stream().reduce(0,   (x,y) -> x + y);
20. 20. <U> U reduce( U identity, BiFunction<U, ? super T, U > accumulator, BinaryOperator<U> combiner); Stream<T>#reduce •accumulator 和 combiner 每次處理完元素 後，必須回傳新的值
21. 21. Integer result = stream.reduce(0, (sum, b) -> sum + b.getWeight(), Integer::sum); Stream<T>#reduce
22. 22. list.stream().reduce( new ArrayList<>(), (integers, o) -> { integers.add(o); return integers; }, (integers, integers2) -> { integers.addAll(integers2); return integers; }); ❌
23. 23. list.stream().reduce( new ArrayList<>(), (integers, o) -> { ArrayList<Integer> list = new ArrayList<>(integers); list.add(o); return list; }, (integers, integers2) -> { ArrayList<Integer> list = new ArrayList<>(integers); list.addAll(integers2); return list; }); △
24. 24. Mutable Reduction •將元素累加到 mutable 的容器中 •Stream#collect •和 reduce 不同，是改變已經存在的值
25. 25. <R> R collect( Supplier<R> supplier, BiConsumer<R,? super T> accumulator, BiConsumer<R,R> combiner); Stream<T>#collect •accumulator 和 combiner 都是 consumer
27. 27. <R> R collect( Collector<? super T,A,R> collector); Stream<T>#collect •Collector 並不是很容易實作
28. 28. •所以 Collectors 提供了許多預設的方法提供 常用的 Collector •toList, groupingBy, toSet, toMap, counting stream.collect(Collectors.toList()); stream.collect(Collectors  .groupingBy(…)); strStream.collect(Collectors  .join(","));
29. 29. ???
30. 30. ????
31. 31. ! List<Item> items = new ArrayList<>…; Map<String, List<Item>> result =   items.stream().collect(groupingBy(  Item::getOwner)); ! >> {owner1=[i1, i2], owner2=[i3],…}
32. 32. ! List<Item> items = new ArrayList<>…; Map<String, Set<String>> result =   items.stream().collect(groupingBy(  Item::getOwner,  toSet()));    >> {owner1=[i1], owner2=[i3], …}
33. 33. List<Item> items = new ArrayList<>…; Map<String, Set<String>> result =   items.stream().collect(groupingBy(  Item::getOwner,  mapping(Item::getName(),  toSet()))); ! >> {owner1=[name1], owner2=[name2],…}
34. 34. Lazy Evaluation List<Integer> items =   Arrays.asList(1, 2, 3, 4); items.stream() .filter( i -> { sout("A"+i); i % 2 == 0; }) .map( i -> { sout("B"+i); return i; }) .map( i -> { sout("C"+i); return i; }); •不會印出東西
35. 35. Lazy Evaluation List<Integer> items =   Arrays.asList(1, 2, 3, 4); items.stream() .filter( i -> { sout("A"+i); i % 2 == 0; }) .map( i -> { sout("B"+i); return i; }) .map( i -> { sout("C"+i); return i; }) .collect(toList());
36. 36. Lazy Evaluation List<Integer> items =   Arrays.asList(1, 2, 3, 4); items.stream() .filter( i -> { sout("A"+i); i % 2 == 0; }) .map( i -> { sout("B"+i); return i; }) .map( i -> { sout("C"+i); return i; }) .collect(toList()); >> A1, A2, B2, C2, A3, A4, B4, C4
37. 37. Parallel List<Integer> items =   Arrays.asList(1, 2, 3, 4); items.parallelStream() .filter( i -> { sout("A"+i); return i % 2 == 0; }) .map( i -> { sout("B"+i); return i; }) .map( i -> { sout("C"+i); return i; }) .collect(toList()); >> A1, A3, A4, A2, B4, B2, C2, C4
38. 38. Short-circuit Operation •Intermediate operation •能將無限的輸入轉換成有限的 stream •limit long sum = IntStream .iterate(1, n -> n+1) .limit(10) .sum();
39. 39. Short-circuit Operation •Terminal operation •能將無限的輸入, 在有限時間內結束 •ﬁndFirst, anyMatch, allMatch long sum = IntStream .iterate(1, n -> n+1) .filter(i -> i > 100) .findFirst();
40. 40. Example 1 •找出第一個 age > 20 的 Student for (Student student : students) { if (student.age > 20) { return student; } } }
41. 41. Optional<Student> student = students.stream() .filter(s -> s.age > 20) .findFirst();
42. 42. Example 2 •尋找 age > 20，成績 > 90 的 10 位 Student 的 id
43. 43. List<String> result = …; for (Student student : students) { if (student.age > 20 && student.grade > 90) { result.add(student.id); if(result.size() >= 10){ break; } } }
44. 44. List<String> result = students.stream() .filter(student -> student.age > 20) .filter(student -> student.grade > 90) .limit(10) .map(student -> student.id) .collect(Collectors.toList());
45. 45. Example 3 •找出所有 Article 評論大於 20 的 Category，並依照名稱排序。
46. 46. List<Category> result = …; for (Category category : categories) { for (Article a : c.getArticles()) { if (a.getCommentCount() >= 20) { result.add(c); break; } } } Collections.sort(result,   Comparator.comparing(c -> c.getName()));
47. 47. categories.stream() .filter(c -> c.getArticles() .stream() .anyMatch(a -> a.getCommentCount() >= 20)) .sorted(Comparator.comparing(c -> c.getName())) .collect(Collectors.toList());
48. 48. Example 4 •將 Person 依照年齡分類到不同 List •Map<Integer, List< Person >>
49. 49. Map<Integer, List<Person>> result = …; for (Person person : people) { result.computeIfAbsent(person.age, t -> new ArrayList<>()) .add(person); }
50. 50. Map<Integer,List<Person>> peopleByAge = people.stream() .collect(groupingBy(Person::getAge));
51. 51. •Stream 走查很容易跟預期的不同，所以操作 過程要避免產生副作用 •順序，走了 些元素，是否並行 注意
52. 52. ArrayList<String> results = new   ArrayList<>(); stream.filter(…)  .forEach(s -> results.add(s)); List<String>results = stream  .filter(…)  .collect(Collectors.toList()); Side Eﬀects
53. 53. Set<Integer> seen =   Collections.synchronizedSet(  new HashSet<>()); stream.parallel().map(e -> {   if (seen.add(e)) return 0;   else return e;   })... Stateless Behaviors
54. 54. List<String> source = ...; source.stream()  .filter(s -> {  source.add(...);  return s.length() > 10;   })  ... Non-inferences •走查過程中不該動到來源資料結構 •除非該資料結構是支援 concurrent 存取
55. 55. •使用 Stream 的方式和外部迭代差異不小 •很多方法只看參數型態很難理解，從方法和 變數名稱去理解使用方式 •只能多寫多習慣 •通常寫完後會有較佳的可讀性 最後