Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Upcoming SlideShare
JavaOne2014サンフランシスコ報告会in大阪
Next
Download to read offline and view in fullscreen.

7

Share

Download to read offline

Brand new Data Processing - StreamAPI

Download to read offline

関西Javaエンジニアの会スペシャル! Java 8リリース で発表させていただいた「Brand new Data Processing - StreamAPI」です.

Related Books

Free with a 30 day trial from Scribd

See all

Brand new Data Processing - StreamAPI

  1. 1. Brand new Data Processing 2014/7/12 15:30-16:30 Shinya Yoshida(@bitter_fox) 関西Javaエンジニアの会スペシャル!Java 8リリース StreamAPI
  2. 2. 2 Who are you? ● 吉田真也(@bitter_fox) ● 立命館大学 情報理工学部 情報システム学科 – 高性能計算機ソフトウェアシステム研究室 ● 立命館コンピュータクラブ(RCC) 執行委員長 (代表) ● http://www.rcc.ritsumei.ac.jp/
  3. 3. 3 OSC 2014 Kyoto
  4. 4. 4 OSC 2014 Kyoto
  5. 5. 5 HashTag #kanjava
  6. 6. 6 JavaSE8
  7. 7. 7 JavaSE8 Revolution
  8. 8. 8 JavaSE8 Revolution JavaSE5以来 (2004年)
  9. 9. 9 JavaSE8 Revolution JavaSE5以来 (2004年) 10年 ぶり
  10. 10. 10 JavaSE8 Data Processing Revolution JavaSE5以来 (2004年) 10年 ぶり
  11. 11. 11 JavaSE8 Project Lambda Revolution JavaSE5以来 (2004年) 10年 ぶり
  12. 12. 12 Project Lambda ● 並列処理を容易に書ける様に増強 – ライブラリ – 言語 ● StreamAPI(!=IOStream)の導入 ● ラムダ式の導入
  13. 13. 13 Why Project Lambda?
  14. 14. 14 マルチコアCPU
  15. 15. 15 マルチコアCPU ● CPU(ハード)のパラダイムシフト – クロック数はそのまま コア(数)を増やす – 並列処理 ● ソフトウェアにもパラダイムシフト ● 並列プログラミングにしないと性能をフルに利用で きない – アムダールの法則
  16. 16. 16 アムダールの法則 90% 10% 90% 80% 20% 80% 5 % 1コア 1コア ∞コア 4コア 逐次処理 並列処理
  17. 17. 17 現代的なアーキテクチャ 少しでも多くの部分で並列処理
  18. 18. 18 並列処理ライブラリの歴史 java.lang.Thread 扱いが難しかった/大きな粒度 JavaSE5(J2SE 5.0) Concurrency Utilities(java.util.concurrent.*) 簡単化/大きな粒度 JavaSE7 Fork/Join Framework 小さな粒度/やや難
  19. 19. 19 ProjectLambda発足当時(JavaSE6〜JavaSE7) 小さな粒度向けのライブラリが無かった JavaSE7後 小さな粒度向けのライブラリがあるものの使いづらい
  20. 20. 20 Fork/Join Frameworkを利用した 並列データ処理APIを
  21. 21. 21 コアライブラリ Project Lambda
  22. 22. 22 ライブラリでは不十分 new Runnable(){ public void run(){ // proc } } ● 処理を分けるだけで5行 ● いくらライブラリが良くても・・・ ● 言語的に解決する必要がある
  23. 23. 23 コアライブラリ ラムダ式 メソッド参照 型推論の強化 実質的にfinal 交差型キャスト Project Lambda
  24. 24. 24 ライブラリの増強 ● 一度公開されたインターフェース – 変更を加えにくい – メソッド追加 ● 具象クラスが追随する必要がある – 実装の提供
  25. 25. 25 コアライブラリ ラムダ式 メソッド参照 型推論の強化 実質的にfinal 交差型キャスト defaultメソッド stat. Intf. メソッド Project Lambda
  26. 26. 26 徹底解説!Project Lambdaのすべて ● 言語特徴のより詳細な情報 ● On Slideshare – http://www.slideshare.net/bitter_fox/jjug-ccc-2013-fa ul – http://www.slideshare.net/bitter_fox/java8-launch – http://www.slideshare.net/bitter_fox/ss-35882498 – ↑最新版
  27. 27. 27 コアライブラリ ラムダ式 メソッド参照 型推論の強化 実質的にfinal 交差型キャスト defaultメソッド stat. Intf. メソッド Project Lambda
  28. 28. 28 コアライブラリ Project Lambdaに関連 defaultメソッド Collections Framework StreamAPIOptional IO/NIO Concurrensy Utilities Logging Etc... java.utill.function
  29. 29. 29 コアライブラリ Project Lambdaに関連 defaultメソッド Collections Framework StreamAPIOptional IO/NIO Concurrensy Utilities Logging Etc... java.utill.function
  30. 30. Enhancement Collection Framework ● Iterable – #forEach ● Collection – #removeIf ● List – #replaceAll – #sort ● Map – #forEach – #compute ● IfAbsent ● IfPresent – #getOrDefault – #merge – #replace ● All – #remove – #putIfAbsent
  31. 31. Enhancement Collection Framework ● Iterable – #forEach ● Collection – #removeIf ● List – #replaceAll – #sort ● Map – #forEach – #compute ● IfAbsent ● IfPresent – #getOrDefault – #merge – #replace ● All – #remove – #putIfAbsent
  32. 32. Iterable#forEach for (String s : strings) { System.out.println(s); }
  33. 33. 外部イテレーション ● イテレーションをユーザコードが行う ● for文,while文 ● 並列化が困難 – ユーザコードの大幅な変更が必要
  34. 34. Iterable#forEach for (String s : strings) { System.out.println(s); } strings.forEach(new Consumer<String>() { public void apply(String s) { System.out.println(s); } });
  35. 35. 内部イテレーション ● イテレーションがライブラリの中に隠れてる ● イテレーション以外の処理を受け取る ● 並列化が容易 – イテレーションの方法を簡単に切り替えられる – ユーザコードの変更は最小限
  36. 36. 内部イテレーション ● イテレーションがライブラリの中に隠れてる ● イテレーション以外の処理を受け取る ● 並列化が容易 – イテレーションの方法を簡単に切り替えられる – ユーザコードの変更は最小限
  37. 37. Iterable#forEach public void forEach(Consumer<T> c) { for (T t : this) { c.apply(t); } }
  38. 38. 並列化のイメージ public void forEach(Consumer<T> c) { if (isParallel()) { this.parallelForEach(c); } else { this.sequentialForEach(c); } }
  39. 39. Collection#removeIf ● for (Iterator<String> i = strings.iterator(); i.hasNext(); ) { String s = i.next(); if (s.length() > 10) { i.remove(); } }
  40. 40. Collection#removeIf strings.removeIf(new Predicate<String>() { public boolean test(String s) { return s.length() > 10; } });
  41. 41. Map#computeIfAbsent if (map.get(dep) == null) { map.put(dep, new ArrayList<Emp>()); }
  42. 42. Map#computeIfAbsent map.computeIfAbsent(name, new Function<String, List<Emp>>() { public List<Emp> apply(String s) { return new ArrayList<>(); } }); ● イテレーションではないが知っていると便利
  43. 43. Collection拡張の不満 ● 内部イテレーションのほうが長い – 特に縦に長い ● インターフェースの拡張性が低い – インターフェースへのメソッド追加 – 追加されたメソッドの実装を追加しないといけない
  44. 44. Collection拡張の不満 ● 内部イテレーションのほうが長い – 特に縦に長い – ラムダ式・メソッド参照で解決 ● インターフェースの拡張性が低い – インターフェースへのメソッド追加 – 追加されたメソッドの実装を追加しないといけない – デフォルトメソッドで解決
  45. 45. 問題点 ● 内部イテレーションのほうが長い – 特に縦に長い – ラムダ式・メソッド参照で解決 ● インターフェースの拡張性が低い – インターフェースへのメソッド追加 – 追加されたメソッドの実装を追加しないといけない – デフォルトメソッドで解決
  46. 46. 内部イテレーションのほうが長い ● 処理の分離が長い – 匿名クラス strings.forEach(new Consumer<String>() { public void apply(String s) { System.out.println(s); } });
  47. 47. 内部イテレーションのほうが長い ● 処理の分離が長い – 匿名クラス strings.forEach(new Consumer<String>() { public void apply(String s) { System.out.println(s); } }); 実装するべきメソッドが一つ
  48. 48. 内部イテレーションのほうが長い ● 処理の分離が長い – 匿名クラス strings.forEach(new Consumer<String>() { public void apply(String s) { System.out.println(s); } }); 実装するべきメソッドが一つ インターフェース
  49. 49. 49 ● 実装するべきメソッド(抽象メソッド)が一つ ● インターフェース – java.lang.Runnable – java.lang.Callable – java.nio.file.PathMatcher – java.awt.event.ActionListener – java.swing.event.ChangeListner – ...
  50. 50. 50 関数型インターフェース ● 実装するべきメソッド(抽象メソッド)が一つ ● インターフェース – java.lang.Runnable – java.lang.Callable – java.nio.file.PathMatcher – java.awt.event.ActionListener – java.swing.event.ChangeListner – ...
  51. 51. 51 関数型インターフェース ● 処理を分けるのに十分 ● ライブラリの多くで利用されている ● 実装&インスタンス化する構文としてラムダ式 – 匿名クラスに代わる構文
  52. 52. 52 関数型インターフェース? interface F { void f(); }
  53. 53. 53 関数型インターフェース? interface F { void f(); } ● Yes!
  54. 54. 54 関数型インターフェース? interface F { boolean equals(Object o); }
  55. 55. 55 関数型インターフェース? interface F { boolean equals(Object o); } ● No! ● equalsはObjectクラスで定義されている – インターフェースにおいて暗黙的なメソッド 抽象メソッドは0個
  56. 56. 56 関数型インターフェース? interface F { Object clone(); }
  57. 57. 57 関数型インターフェース? interface F { Object clone(); } ● Yes! ● cloneもObjectクラスで宣言されているが protected – Fではpublicで再宣言されている
  58. 58. 58 関数型インターフェース(JLS9.8) A functional interface is an interface that has just one abstract method, and thus represents a single function contract. (In some cases, this "single" method may take the form of multiple abstract methods with override-equivalent signatures (8.4.2) inherited from superinterfaces; in this case, the inherited methods logically represent a single method.) More precisely, for interface I, let M be the set of abstract methods that are members of I but that do not have the same signature as any public instance method of the class Object. Then I is a functional interface if there exists a method m in M for which the following conditions hold: The signature of m is a subsignature (8.4.2) of every method's signature in M. m is return-type-substitutable (8.4.5) for every method in M. In addition to the usual process of creating an interface instance by declaring (8.1) and instantiating (15.9) a class, instances of functional interfaces can be created with lambda expressions (15.27), method references (15.28), or constructor references. The function descriptor of a functional interface I is a method type (8.2) that can be used to legally override (8.4.8) the abstract method(s) of I. Let M be the set of abstract methods defined above for I. The descriptor of I consists of the following: Type parameters, formal parameters, and return types: Let m be a method in M with i) a signature that is a subsignature of every method's signature in M and ii) a return type that is a subtype of every method's return type in M (after adapting for any type parameters (8.4.4)); if no such method exists, then let m be a method in M that i) has a signature that is a subsignature of every method's signature in M and ii) is return-type-substitutable for every method in M. Then the descriptor's type parameters, formal parameter types, and return type are as given by m. Thrown types: The descriptor's thrown types are derived from the throws clauses of the methods in M. If the descriptor is generic, these clauses are first adapted to the type parameters of the descriptor (8.4.4); if the descriptor is not generic but at least one method in M is, these clauses are first erased. Then the descriptor's thrown types include every type, E, satisfying the following constraints: E is mentioned in one of the throws clauses. For each throws clause, E is a subtype of some type named in that clause. A functional interface type is one of the following: A functional interface A parameterization (4.5) of a functional interface An intersection (4.9) of interface types that meets the following criteria: Exactly one element of the intersection is a functional interface, or a parameterization of a functional interface. Let F be this interface. A notional interface, I, that extends all the interfaces in the intersection would be a functional interface. If any of the intersection elements is a parameterized type, then I is generic: for each element of the intersection that is a parameterized type J<A1...An>, let P1...Pn be the type parameters of J; then P1...Pn are also type parameters of I, and I extends the type J<P1...Pn>. The function descriptor of I is the same as the function descriptor of F. The function descriptor of a parameterized functional interface, F<A1...An>, where A1...An are type arguments (4.5.1), is derived as follows. Let P1...Pn be the type parameters of F; types T1...Tn are derived from the type arguments according to the following rules (for 1 ≤ i ≤ n): If Ai is a type, then Ti = Ai. If Ai is a upper-bounded wildcard ? extends Ui, then Ti = Ui. If Ai is a lower-bounded wildcard ? super Li, then Ti = Li. If Ai is an unbound wildcard ?, then if Pi has upper bound Bi that mentions none of P1...Pn, then Ti = Bi; otherwise, Ti = Object. If F<T1...Tn> is a well-formed type, then the descriptor of F<A1...An> is the result of applying substitution [P1:=T1, ..., Pn:=Tn] to the descriptor of interface F. Otherwise, the descriptor of F<A1...An> is undefined. The function descriptor of an intersection that is a functional interface type is the same as the function descriptor of the functional interface or parameterization of a functional interface that is an element of the intersection.
  59. 59. 59 関数型インターフェース(JLS9.8) A functional interface is an interface that has just one abstract method, and thus represents a single function contract. (In some cases, this "single" method may take the form of multiple abstract methods with override-equivalent signatures (8.4.2) inherited from superinterfaces; in this case, the inherited methods logically represent a single method.) More precisely, for interface I, let M be the set of abstract methods that are members of I but that do not have the same signature as any public instance method of the class Object. Then I is a functional interface if there exists a method m in M for which the following conditions hold: The signature of m is a subsignature (8.4.2) of every method's signature in M. m is return-type-substitutable (8.4.5) for every method in M. In addition to the usual process of creating an interface instance by declaring (8.1) and instantiating (15.9) a class, instances of functional interfaces can be created with lambda expressions (15.27), method references (15.28), or constructor references. The function descriptor of a functional interface I is a method type (8.2) that can be used to legally override (8.4.8) the abstract method(s) of I. Let M be the set of abstract methods defined above for I. The descriptor of I consists of the following: Type parameters, formal parameters, and return types: Let m be a method in M with i) a signature that is a subsignature of every method's signature in M and ii) a return type that is a subtype of every method's return type in M (after adapting for any type parameters (8.4.4)); if no such method exists, then let m be a method in M that i) has a signature that is a subsignature of every method's signature in M and ii) is return-type-substitutable for every method in M. Then the descriptor's type parameters, formal parameter types, and return type are as given by m. Thrown types: The descriptor's thrown types are derived from the throws clauses of the methods in M. If the descriptor is generic, these clauses are first adapted to the type parameters of the descriptor (8.4.4); if the descriptor is not generic but at least one method in M is, these clauses are first erased. Then the descriptor's thrown types include every type, E, satisfying the following constraints: E is mentioned in one of the throws clauses. For each throws clause, E is a subtype of some type named in that clause. A functional interface type is one of the following: A functional interface A parameterization (4.5) of a functional interface An intersection (4.9) of interface types that meets the following criteria: Exactly one element of the intersection is a functional interface, or a parameterization of a functional interface. Let F be this interface. A notional interface, I, that extends all the interfaces in the intersection would be a functional interface. If any of the intersection elements is a parameterized type, then I is generic: for each element of the intersection that is a parameterized type J<A1...An>, let P1...Pn be the type parameters of J; then P1...Pn are also type parameters of I, and I extends the type J<P1...Pn>. The function descriptor of I is the same as the function descriptor of F. The function descriptor of a parameterized functional interface, F<A1...An>, where A1...An are type arguments (4.5.1), is derived as follows. Let P1...Pn be the type parameters of F; types T1...Tn are derived from the type arguments according to the following rules (for 1 ≤ i ≤ n): If Ai is a type, then Ti = Ai. If Ai is a upper-bounded wildcard ? extends Ui, then Ti = Ui. If Ai is a lower-bounded wildcard ? super Li, then Ti = Li. If Ai is an unbound wildcard ?, then if Pi has upper bound Bi that mentions none of P1...Pn, then Ti = Bi; otherwise, Ti = Object. If F<T1...Tn> is a well-formed type, then the descriptor of F<A1...An> is the result of applying substitution [P1:=T1, ..., Pn:=Tn] to the descriptor of interface F. Otherwise, the descriptor of F<A1...An> is undefined. The function descriptor of an intersection that is a functional interface type is the same as the function descriptor of the functional interface or parameterization of a functional interface that is an element of the intersection. @ FunctionalInterface
  60. 60. 60 @FunctionalInterface ● 関数型インターフェースかどうか検査する – コンパイル時 @FunctionalInterface interface F { boolean equals(Object o); }
  61. 61. 61 @FunctionalInterface ● 関数型インターフェースかどうか検査する – コンパイル時 @FunctionalInterface interface F { boolean equals(Object o); } @FunctionalInterface ^ Fは機能インタフェースではありません インタフェース Fで抽象メソッドが見つかりません エラー1個
  62. 62. 62 java.util.function.* 名前 第一引数 第二引数 戻り値 Consumer<T> T - void Function<T, R> T - R Predicate<T> T - boolean Supplier<T> - - T BiConsumer<T, U> T U void BiFunction<T, U, R> T U R BiPredicate<T, R> T U boolean
  63. 63. 63 匿名クラスからラムダ式へ strings.forEach( new Consumer<String>() { public void apply(String s) { System.out.println(s); } });
  64. 64. 64 匿名クラスからラムダ式へ strings.forEach( new Consumer<String>() { public void apply(String s) { System.out.println(s); } }); forEachの引数から推 論できる
  65. 65. 65 匿名クラスからラムダ式へ strings.forEach( new Consumer<String>() { public void apply(String s) { System.out.println(s); } }); 実装するべきメソッド も一意に定まる
  66. 66. 66 ラムダ式 strings.forEach( (String s) -> { System.out.println(s); }); ● (仮引数) -> {メソッド本体} ● (int n1, int n2) -> {return n1+n2;}
  67. 67. 67 ラムダ式 ● 関数型インターフェースをインスタンス化 ● (仮引数) -> {メソッド本体} – 型推論で型が決まる ● 関数型インターフェースのインスタンスが 予期される場面で利用可 – ターゲット型
  68. 68. 68 ターゲット型が曖昧な場合 Object o = () -> {}; ● () -> {}の型として – Objectが予期される – 関数型インターフェースが予期されない – 何を実装したらいいのかわからない
  69. 69. 69 ターゲット型が曖昧な場合 Object o = (Runnable)() -> {}; – キャストを用いる – Runnableが予期される – 実装するべきインターフェースが分かる
  70. 70. 70 ラムダ式の引数 strings.forEach( (String s) -> { System.out.println(s); });
  71. 71. 71 ラムダ式の引数 strings.forEach( (String s) -> { System.out.println(s); }); 引数の型も一意に定ま る
  72. 72. 72 ラムダ式の引数 strings.forEach( (s) -> { System.out.println(s); }); ● 引数の型も省略可 ● (n1, n2) -> {return n1+n2;}
  73. 73. 73 ラムダ式の引数 strings.forEach( (s) -> { System.out.println(s); }); 引数が一つで型が推論される 場合の()は不要
  74. 74. 74 ラムダ式の引数 strings.forEach( s -> { System.out.println(s); }); ● 引数が一つで型が省略される場合()不要 ● n1 -> {return n1+5;}
  75. 75. 75 ラムダ式の引数と_ ● ラムダ式の引数としての_はコンパイルエラー this.addActionListener( _ -> {/**/} ); – 他の言語での_は特殊な意味 – 混乱を招かないように利用不可に – 将来の利用を見据え予約語に ● それ以外の_は警告に
  76. 76. 76 ラムダ式のメソッド本体 (int n) -> {return n + 5;} (n) -> {return n + 5;} n -> {return n + 5;}
  77. 77. 77 ラムダ式のメソッド本体 (int n) -> {return n + 5;} (n) -> {return n + 5;} n -> {return n + 5;} ● return文のみ場合,return等を省略できる (int n) -> n + 5 (n) -> n + 5 n -> n + 5
  78. 78. 78 ラムダ式のメソッド本体 (String s) -> {println(s);} (s) -> {println(s);} s -> {println(s);}
  79. 79. 79 ラムダ式のメソッド本体 (String s) -> {println(s);} (s) -> {println(s);} s -> {println(s);} ● 戻り値がvoidでも,{;}を省略できる場合がある (String s) -> println(s) (s) -> println(s); s -> println(s);
  80. 80. 80 ラムダ式.equals(匿名クラス)?
  81. 81. 81 ラムダ式.equals(匿名クラス)? ● 違います! – 匿名クラスのシンタックスシュガーではない ● 意味論も実装方法(OpenJDKの場合)も異なる – 主にスコーピング規則 – 同じ部分もある
  82. 82. 82 ラムダ式のスコーピング規則 1.ラムダ式内では外のスコープを引き継ぐ 2.常にアウタークラスのインスタンスを保持しない – 匿名クラスなどとは大きく違う 3.ローカル変数の参照はfinalな変数のみ – 匿名クラスと同様 – 注:実質的にfinal(後ほど説明)
  83. 83. 83 1.外のスコープを引き継ぐ class Main { void method() { Runnable r = () -> System.out.println(this); } }
  84. 84. 84 1.外のスコープを引き継ぐ class Main { void method() { Runnable r = () -> System.out.println(this); } } ● ラムダ式内のthis=エンクロージングクラス
  85. 85. 85 1.外のスコープを引き継ぐ class Main { void method(int n) { Runnable r = () -> {int n;}; } }
  86. 86. 86 1.外のスコープを引き継ぐ class Main { void method(int n) { Runnable r = () -> {int n;}; } } ● 多重定義 ● コンパイルエラー
  87. 87. 87 1.外のスコープを引き継ぐ class Main { void method(int n) { Function<Integer, Integer> f = n -> n + 5; } } ● 多重定義 ● コンパイルエラー
  88. 88. 88 2.アウタークラスへの参照 ● 匿名クラス – 常に保持 – メモリリークの危険性高 ● ラムダ式 – 必要に応じて保持
  89. 89. 89 2.アウタークラスへの参照 class Register { void register(Processer p) { p.add(new Func() { public int f(int n) {return n * n;} }); } }
  90. 90. 90 2.アウタークラスへの参照 class Register { void register(Processer p) { p.add(new Func() { public int f(int n) {return n * n;} }); } } Registerのインスタンスへの参照が残るRegisterのインスタンスへの参照が残る
  91. 91. 91 2.アウタークラスへの参照 class Register { void register(Processer p) { p.add(n -> n * n); } }
  92. 92. 92 2.アウタークラスへの参照 class Register { void register(Processer p) { p.add(n -> n * n); } } Registerのインスタンスは保持しない
  93. 93. 93 3.ローカル変数の参照 ● 匿名クラスと同様 – finalな変数 – 実質的にfinalな変数 ● Java8から ● 実質的にfinal – 再代入されていない変数 – コンパイラがfinal性を推論 – final修飾されている変数と同じ扱い – 値の変更不可
  94. 94. 94 ラムダ式の利用例 p -> p.getName() s -> Integer.parseInt(s) (k, v) -> map.put(k, v) init -> new MyClass(init) n -> new int[n] ● 引数を受け流すパターン
  95. 95. 95 ラムダ式の利用例 p -> p.getName() s -> Integer.parseInt(s) (k, v) -> map.put(k, v) init -> new MyClass(init) n -> new int[n] ● 引数を受け流すパターン ● メソッド・コンストラクタ参照
  96. 96. 96 メソッド・コンストラクタ参照 p -> p.getName() s -> Integer.parseInt(s) (k, v) -> map.put(k, v) init -> new MyClass(init) n -> new int[n] ● クラス名等::メソッド or new Person::getName Integer::perseInt map::put MyClass::new int[]::new
  97. 97. 97 ラムダ式との違い ● finalでない変数をレシーバにできる String s; while ((s = br.readLine()) != null) { task.add(() -> s.length()); // NG task.add(s::length); // OK } ● 注:この処理はJava8では別の書き方をします
  98. 98. 問題点 ● 内部イテレーションのほうが長い – 特に縦に長い – ラムダ式・メソッド参照で解決 ● インターフェースの拡張性が低い – インターフェースへのメソッド追加 – 追加されたメソッドの実装を追加しないといけない – デフォルトメソッドで解決
  99. 99. 99 <interface> PublishedInterface +already() +exist() +methods()
  100. 100. 100 <interface> PublishedInterface +already() +exist() +methods() ReferenceImpl +already() +exist() +methods() AnotherImpl +already() +exist() +methods() UserImpl +already() +exist() +methods()
  101. 101. 101 <interface> PublishedInterface +already() +exist() +methods() +newMethod() ReferenceImpl +already() +exist() +methods() AnotherImpl +already() +exist() +methods() UserImpl +already() +exist() +methods()
  102. 102. 102 <interface> PublishedInterface +already() +exist() +methods() +newMethod() ReferenceImpl +already() +exist() +methods() AnotherImpl +already() +exist() +methods() UserImpl +already() +exist() +methods()
  103. 103. 103 インターフェースに拡張性を ● 新しいメソッドを加えても互換性を保つ ● デフォルトメソッド – デフォルトの実装を提供する – インターフェースに実装 – 実装が提供されない場合に使用される
  104. 104. 104 デフォルトメソッド interface Person { Sex getSex(); default boolean isMan() { return getSex() == Sex.MAN; } }
  105. 105. 105 デフォルトメソッド class PersonImpl implements Person { public Sex getSex() {/*...*/} // isManへの実装はなくてもOK // Person#isManが使われる }
  106. 106. 106 デフォルトメソッド class PersonImpl implements Person { public Sex getSex() {/*...*/} public boolean isMan() {/*...*/} } ● オーバーライド可
  107. 107. 107 デフォルトメソッド ● default修飾子 ● publicメソッドとなる – 既存のインターフェースメソッドと同様 ● strictfp修飾のみ可 ● 具象クラスで実装が提供されなくても無問題 ● 拡張性を実現できた – 新たな問題が・・・
  108. 108. 108 実装の多重継承問題
  109. 109. 109 多重継承 class BasicPerson { public boolean isMan() {/*...*/} } class ComplexPerson extends BasicPerson implements Person { public Sex getSex() {/*...*/} }
  110. 110. 110 多重継承 BasicPerson #isMan Person #isMan ComplexPerson #isMan
  111. 111. 111 “Class always win”
  112. 112. 112 クラスで定義された実装が 常に勝つ
  113. 113. 113 Class always win class BasicPerson { public boolean isMan() {/*...*/} } class ComplexPerson extends BasicPerson implements Person { public Sex getSex() {/*...*/} } ● BasicPerson#isManが使われる – “Class always win”
  114. 114. 114 親インターフェースの呼び出し class ComplexPerson extends BasicPerson implements Person { public Sex getSex() {/*...*/} public boolean isMan() { return Person.super.isMan(); } } ● インターフェース名.super.メソッド名(...)
  115. 115. 115 クラスを介さない多重継承 interface Base1 {default void m() {}}
  116. 116. 116 クラスを介さない多重継承 interface Base1 {default void m() {}} interface Base2 {default void m() {}}
  117. 117. 117 クラスを介さない多重継承 interface Base1 {default void m() {}} interface Base2 {default void m() {}} interface ExBase extends Base1, Base2 {}
  118. 118. 118 多重継承 Base1#m Base2#m ExBase#m
  119. 119. 119 クラスを介さない多重継承 interface ExBase extends Base1, Base2 {} ● コンパイルエラー – オーバーライドして選択
  120. 120. 120 クラスを介さない多重継承 interface ExBase extends Base1, Base2 { default void m() { Base1.super.m(); } }
  121. 121. 121 多重継承は怖くない!! ● 大原則1:Class always win – クラスで定義された実装が常に勝つ ● 大原則2:いつでもオーバーライドできる – 親クラスでfinal修飾されてたら別 – インターフェースの実装を呼べる
  122. 122. 122 Objectメソッドのデフォルトメソッド ● Objectで定義されたpublicメソッド – そもそもデフォルトの実装 ● Objectのpublicメソッドのデフォルトメソッドは不可 – interface I {default String toString() {/* */}} – コンパイルエラー
  123. 123. 123 コアライブラリ Project Lambdaに関連 defaultメソッド Collections Framework StreamAPIOptional IO/NIO Concurrensy Utilities Logging Etc... java.utill.function
  124. 124. Collection拡張の問題点 ● データ列はCollectionだけではない – ファイルの各行もデータ列 – 0から10までの数値もデータ列 ● パイプライン化が難しい – 処理量の増加
  125. 125. Collection拡張の問題点 ● データ列はCollectionだけではない – ファイルの各行もデータ列 – 0から10までの数値もデータ列 ● パイプライン化が難しい – 処理量の増加
  126. 126. 処理量の増加 ● removeIfしてforEachを考える strings.removeIf(s -> s.length() > 10); strings.forEach(System.out::println); ● 2回ループ
  127. 127. 処理量の増加 for (Iterator<String> i = strings.iterator(); i.hasNext(); ) if (i.next().length > 10) i.remove(); for (String s : strings) System.out.println(s);
  128. 128. StreamAPI
  129. 129. StreamAPI ● 内部イテレーション&パイプライン化 – 処理量そのままに並列化容易 ● 汎用性高い – あらゆる形式のデータ列に対応可 ● Collection ● 値の範囲 ● 任意の値 など – データ列自体は保持していない ● データへのアクセス手段を保持
  130. 130. 130 StreamAPI java.util.stream. ● Stream ● IntStream ● LongStream ● DoubleStream – ソースから生成される – 中間操作と終端操作でデータを弄る – 並列化が容易
  131. 131. 131 Collection 配列 BufferReader etc... Stream IntStream LongStream DoubleStream 中間操作 終端操作 j.u.stream.*Source
  132. 132. 132 Collection 配列 BufferReader etc... Stream IntStream LongStream DoubleStream 中間操作 終端操作 j.u.stream.*Source
  133. 133. 133 Make Streams ソース メソッド 使用例 Collection Collection#stream list.stream() 配列 Arrays#stream Arrays.stream(args) BufferedReader BufferedReader#lines br.lines() n〜m-1までの数値 IntStream#range IntStream.range(n, m) n〜mまでの数値 IntStream#rangeClosed IntStream.rangeClosed(n, m) 任意の要素 Stream#of Stream.of(“J”, “a”, “v”, “a”)
  134. 134. 134 Collection 配列 BufferReader etc... Stream IntStream LongStream DoubleStream 中間操作 終端操作 j.u.stream.*Source
  135. 135. 135 java.util.stream. StreamAPI 要素の型 Stream<T> T(参照型) IntStream int(プリミティブ型) LongStream long(プリミティブ型) DoubleStream double(プリミティブ型)
  136. 136. 136 2 types of Stream Sequential Stream Parallel Stream
  137. 137. 137 Change the type of Stream Sequential Stream Parallel Stream parallel() sequential()
  138. 138. 138 Collection 配列 BufferReader etc... Stream IntStream LongStream DoubleStream 中間操作 終端操作 j.u.stream.*Source
  139. 139. 139 中間操作? ● filterやmapなど – Streamを返すメソッド ● 終端操作が行われるまで処理されない – 遅延される
  140. 140. 140 主要な中間操作 メソッド名 概要 使用例 filter フィルタリング s.filter(n -> n % 2 == 0) map 写像・変換 s.map(p -> p.getName()) flatMap 写像・変換&平坦化 s.flatMap(room -> room.getPersons().stream()) distinct 同一の要素を除外 s.distinct() sorted 並び替え s.sorted((p1, p2) -> compare(p1.age, p2.age)) peek デバッグ向け forEach s.peek(e -> System.out.println(e)) limit 要素数制限 s.limit(5) skip 読み飛ばす s.skip(5)
  141. 141. 141 Collection 配列 BufferReader etc... Stream IntStream LongStream DoubleStream 非終端操作 終端操作 j.u.stream.*Source
  142. 142. 142 終端操作? ● forEachやreduceやcollectなど – Streamを返さないメソッド ● 遅延されていた中間操作を確定 – 1回のループで済む
  143. 143. 143 主要な終端操作 メソッド名 概要 使用例 forEach 反復処理 s.forEach(e -> System.out.println(e)) reduce 畳み込み演算 s.reduce(1, (n1, n2) -> n1 * n2) collect 集約化 s.collect(Collectors.toList()) toArray 配列化 s.toArray(String[]::new) min/max 最小値/最大値 s.min(String::compareToIgnoreCase) count 要素数 s.count()
  144. 144. 144 ● 0から10まで出力 ● 0から10までの偶数を出力 ● Personのリストから名前を出力 ● 1から100までの総和を出力 ● 年齢の合計,平均,最小,最大 ● 名前の連結 ● Personの名前のリストを得る ● 部署別の社員のリストを得る
  145. 145. 145 ● 0から10まで出力 ● 0から10までの偶数を出力 ● Personのリストから名前を出力 ● 1から100までの総和を出力 ● 年齢の合計,平均,最小,最大 ● 名前の連結 ● Personの名前のリストを得る ● 部署別の社員のリストを得る
  146. 146. 146 0から10まで出力したい for (int i = 0; i <= 10; i++) { System.out.println(i); }
  147. 147. 147 forEach[終端] T->void[j.u.function.Consumer<T>#void accept(T)] ● forEach(T -> void) – 各要素に引数で渡した処理を行なう – s.forEach(t -> System.out.println(t)); Stream<T> IntStream LongStream DoubleStream
  148. 148. 148 0から10まで出力したい for (int i = 0; i <= 10; i++) { System.out.println(i); } IntStream.rangeClose(0, 10) .forEach(i -> System.out.println(i));
  149. 149. 149 0から10まで出力したい for (int i = 0; i <= 10; i++) { System.out.println(i); } IntStream.rangeClose(0, 10) .forEach(System.out::println);
  150. 150. 150 ● 0から10まで出力 ● 0から10までの偶数を出力 ● Personのリストから名前を出力 ● 1から100までの総和を出力 ● 年齢の合計,平均,最小,最大 ● 名前の連結 ● Personの名前のリストを得る ● 部署別の社員のリストを得る
  151. 151. 151 0から10までの偶数を出力したい for (int i = 0; i <= 10; i++) { if (i % 2 == 0) { System.out.println(i); } }
  152. 152. 152 filter[中間] ● filter(T -> boolean) – フィルタリング – 各要素を引数に適用しtrueを返したもののみ残す – s.filter(Objects::nonNull) // nullを除外 Stream<T> IntStream LongStream DoubleStream
  153. 153. 153 filter[中間] T->boolean[j.u.function.Predicate<T>#boolean test(T)]
  154. 154. 154 0から10までの偶数を出力したい IntStream.rangeClose(0, 10) .filter(i -> i % 2 == 0) .forEach(System.out::println);
  155. 155. 155 ● 0から10まで出力 ● 0から10までの偶数を出力 ● Personのリストから名前を出力 ● 1から100までの総和を出力 ● 年齢の合計,平均,最小,最大 ● 名前の連結 ● Personの名前のリストを得る ● 部署別の社員のリストを得る
  156. 156. 156 Personのリストから名前を出力 for (Person p : persons) { System.out.println(p.getName()); }
  157. 157. 157 Personのリストから名前を出力 for (Person p : persons) { System.out.println(p.getName()); }
  158. 158. 158 map[中間操作] ● map(T -> R) – 写像・変換 – 各要素を引数に適用した結果のStreamを作る – personStream.map(p -> p.getName()) – seq.map(n -> n * 2) Stream<T> IntStream LongStream DoubleStream
  159. 159. 159 map[中間操作] T -> R[java.util.function.Function<T, R>#R map(T)] R
  160. 160. 160 Personのリストから名前を出力 persons.stream() .map(p -> p.getName()) .forEach(n -> System.out.println(n));
  161. 161. 161 Personのリストから名前を出力 persons.stream() .map(Person::getName) .forEach(System.out::println);
  162. 162. 162 Streamを横断するmap Stream<T> IntStream LongStream DoubleStream #mapToObj #mapToInt #mapToLong #mapToDouble #mapToDouble #mapToLong #mapToInt
  163. 163. 163 ● 0から10まで出力 ● 0から10までの偶数を出力 ● Personのリストから名前を出力 ● 1から100までの総和を出力 ● 年齢の合計,平均,最小,最大 ● 名前の連結 ● Personの名前のリストを得る ● 部署別の社員のリストを得る
  164. 164. 164 1から100までの総和を求める int sum; for (int i = 1; i <= 100; i++) { sum += i; }
  165. 165. 165 reduce[終端] ● Optional<T> reduce((T, T) -> T) ● T reduce(T, (T, T) -> T) – 集約 – s.reduce((n, m) -> n < m ? n : m) ● Optional – 値が無いという状態を表すことができる Stream<T> IntStream LongStream DoubleStream
  166. 166. 166 reduce[終端]
  167. 167. 167 reduce[終端]
  168. 168. 168 reduce[終端]
  169. 169. 169 reduce[終端]
  170. 170. 170 reduce[終端]
  171. 171. 171 reduce[終端]
  172. 172. 172 1から100までの総和を求める int sum = IntStream.rangeClosed(1, 100) .reduce(0, (l, r) -> l + r);
  173. 173. 173 1から100までの総和を求める int sum = IntStream.rangeClosed(1, 100) .reduce(0, Integer::sum);
  174. 174. 174 1から100までの総和を求める 0 21 2 3 4 5
  175. 175. 175 1から100までの総和を求める 1 0 1 2 3 4 5
  176. 176. 176 1から100までの総和を求める 1 0 1 2 3 4 5
  177. 177. 177 1から100までの総和を求める 1 3 0 1 2 3 4 5
  178. 178. 178 1から100までの総和を求める 1 3 0 1 2 3 4 5
  179. 179. 179 1から100までの総和を求める 1 3 6 10 16 0 1 2 3 4 5
  180. 180. 180 1から100までの総和を求める int sum = IntStream.rangeClosed(1, 100) .parallel() .reduce(0, (l, r) → l + r);
  181. 181. 181 1から100までの総和を求める 1 22 3 4 5 6
  182. 182. 182 1から100までの総和を求める 1 22 3 4 5 6
  183. 183. 183 1から100までの総和を求める 1 22 3 4 5 6 3 7 11
  184. 184. 184 1から100までの総和を求める 1 22 3 4 5 6 3 7 11
  185. 185. 185 1から100までの総和を求める 6 3 7 11 10 1 22 3 4 5 6
  186. 186. 186 1から100までの総和を求める 6 3 7 11 10 1 22 3 4 5 6
  187. 187. 187 1から100までの総和を求める 6 3 7 11 10 1 22 3 4 5 6 21
  188. 188. 188 sum[終端] ● int sum() ● long sum() ● double sum() – 総和を求める ● そのものズバリ – s.sum() Stream<T> IntStream LongStream DoubleStream
  189. 189. 189 1から100までの総和を求める int sum = IntStream.rangeClosed(1, 100) .sum();
  190. 190. 190 1から100までの総和を求める int sum = 101 * 100 / 2;
  191. 191. 191 ● 0から10まで出力 ● 0から10までの偶数を出力 ● Personのリストから名前を出力 ● 1から100までの総和を出力 ● 年齢の合計,平均,最小,最大 ● 名前の連結 ● Personの名前のリストを得る ● 部署別の社員のリストを得る
  192. 192. 192 年齢の合計,平均,最大,最小 int sum = 0, max = 0, min = 0; double ave; for (Person p : persons) { int age = p.getAge(); sum += age; max = Math.max(max, age); min = Math.min(min, age); } ave = sum / (double)persons.size();
  193. 193. 193 Ave, max, min[終端] ● average(), max(), min() – Optional系を返す – 平均,最大,最小値を求める Stream<T> IntStream LongStream DoubleStream
  194. 194. 194 年齢の合計,平均,最大,最小 int sum = persons.stream() .mapToInt(Person::getAge).sum(); OptionalInt max = persons.stream() .mapToInt(Person::getAge).max(); OptionalInt min = persons.stream() .mapToInt(Person::getAge).min(); OptionalDouble ave = persons.stream() .mapToInt(Person::getAge).average();
  195. 195. 195 年齢の合計,平均,最大,最小 int sum = persons.stream() .mapToInt(Person::getAge).sum(); OptionalInt max = persons.stream() .mapToInt(Person::getAge).max(); OptionalInt min = persons.stream() .mapToInt(Person::getAge).min(); OptionalDouble ave = persons.stream() .mapToInt(Person::getAge).average(); ループ四回
  196. 196. 196 年齢の合計,平均,最大,最小 IntStream s = persons.stream() .mapToInt(Person::getAge); int sum = s.sum(); OptionalInt max = s.max(); OptionalInt min = s.min(); OptionalDouble ave = s.average();
  197. 197. 197 年齢の合計,平均,最大,最小 IntStream s = persons.stream() .mapToInt(Person::getAge); int sum = s.sum(); OptionalInt max = s.max(); OptionalInt min = s).min(); OptionalDouble ave = s.average(); IllegalStateException
  198. 198. 198 summaryStatistics[終端] ● XxxSummaryStatistics summaryStatistics() – 統計処理 ● 合計,平均,最大,最小,個数 – stream.summaryStatistics().getSum() Stream<T> IntStream LongStream DoubleStream
  199. 199. 199 年齢の合計,平均,最大,最小 IntSummaryStatistics iss = persons.stream() .mapToInt(Person::getAge) .summaryStatistics();
  200. 200. 200 年齢の合計,平均,最大,最小 IntSummaryStatistics iss = persons.stream() .mapToInt(Person::getAge) .summaryStatistics(); int sum = iss.getSum(); int min = iss.getMin(), max = iss.getMax(); double ave = iss.getAverage(); int count = iss.getCount();
  201. 201. 201 ● 0から10まで出力 ● 0から10までの偶数を出力 ● Personのリストから名前を出力 ● 1から100までの総和を出力 ● 年齢の合計,平均,最小,最大 ● 名前の連結 ● Personの名前のリストを得る ● 部署別の社員のリストを得る
  202. 202. 202 生徒の名前を連結する StringBuilder sb = new StringBuilder(); for (Student s : students) { sb.append(s.getName()); } String name = sb.toString();
  203. 203. 203 生徒の名前を連結する String name = students.stream() .map(Student::getName) .reduce(“”, (l, r) -> l + r);
  204. 204. 204 生徒の名前を連結する String name = students.stream() .map(Student::getName) .reduce(“”, (l, r) -> l + r); Stringの連結
  205. 205. 205 生徒の名前を連結する String name = students.stream() .map(Student::getName) .map(StringBuilder::new) .reduce(new StringBuilder(), (l, r) -> l.append(r)) .toString();
  206. 206. 206 生徒の名前を連結する String name = students.stream() .map(Student::getName) .map(StringBuilder::new) .reduce(new StringBuilder(), (l, r) -> l.append(r)) .toString(); StringBuilderの 連結
  207. 207. 207 collect ● R collect(() -> R, (R, T) -> R, (R, R) -> void) ● R collect(Collector<T, ?, R>) – 集約処理 – R:集約先のオブジェクト – () -> R:集約先のオブジェクトの生成 – (R, T) -> R:集約先のオブジェクトに要素を集約 – (R, R) -> void:集約先のオブジェクト同士のcombine ● 並列処理用
  208. 208. 208 生徒の名前を連結する String name = students.stream() .map(Student::getName) .collect(_________________________, _______________________, _____________________________) .toString();
  209. 209. 209 生徒の名前を連結する String name = students.stream() .map(Student::getName) .collect(() -> new StringBuilder(), _______________________, _____________________________) .toString();
  210. 210. 210 生徒の名前を連結する String name = students.stream() .map(Student::getName) .collect(() -> new StringBuilder(), (sb, s) -> sb.append(s), _____________________________) .toString();
  211. 211. 211 生徒の名前を連結する String name = students.stream() .map(Student::getName) .collect(() -> new StringBuilder(), (sb, s) -> sb.append(s), (sb1, sb2) -> sb1.append(sb2)) .toString();
  212. 212. 212 生徒の名前を連結する String name = students.stream() .map(Student::getName) .collect(StringBuilder::new, StringBuilder::append, StringBuilder::append) .toString();
  213. 213. 213 Sequential collect(SB::new, SB::append, SB::append) H e l l o , W o r l d !H e l lH e o , W o r l d !
  214. 214. 214 H e l l o , W o r l d ! SB Sequential collect(SB::new, SB::append, SB::append) H e l l o , W o r l d !H e l lH e o , W o r l d ! SB
  215. 215. 215 H e l l o , W o r l d ! SB Sequential collect(SB::new, SB::append, SB::append) H e l l o , W o r l d !H e l lH e o , W o r l d ! SB
  216. 216. 216 H e l l o , W o r l d ! SB Sequential collect(SB::new, SB::append, SB::append) H e l l o , W o r l d !H e l lH e o , W o r l d ! SB
  217. 217. 217 Parallel collect(SB::new, SB::append, SB::append) H e l l o , W o r l d !H e l l o , W o r l d !H e l lH e o , W o r l d !
  218. 218. 218 Parallel collect(SB::new, SB::append, SB::append) H e l l o , W o r l d ! Split!! H e o ,l l W o r l d !
  219. 219. 219 Parallel collect(SB::new, SB::append, SB::append) H e l l o , W o r l d !H e o ,l l W o r l d !
  220. 220. 220 Parallel collect(SB::new, SB::append, SB::append) H e l l o , W o r l d ! He WoHe WoWoWoWoHeHe H e o ,l l W o r l d !
  221. 221. 221 Parallel collect(SB::new, SB::append, SB::append) H e l l o , W o r l d ! He WoWoWoWoHeHe H e o ,l l W o r l d !
  222. 222. 222 Parallel collect(SB::new, SB::append, SB::append) H e l l o , W o r l d ! He WoHe WoWoWoWoHeHe H e o ,l l W o r l d !
  223. 223. 223 Parallel collect(SB::new, SB::append, SB::append) H e l l o , W o r l d ! He WoSBll SBd!He WoWoWoWoHeHe H e o ,l l W o r l d ! SBllHeHeWoll SBd!SBllHeHeWod!
  224. 224. 224 Parallel collect(SB::new, SB::append, SB::append) H e l l o , W o r l d ! He WoSBll SBd!He WoWoWoWoHeHe H e o ,l l W o r l d ! HeHeWoll SBllHeHeWod!
  225. 225. 225 Parallel collect(SB::new, SB::append, SB::append) H e l l o , W o r l d ! Hell Wo SBd!WoWoWo H e o ,l l W o r l d ! SBd!SBllHeHeWod!Hell
  226. 226. 226 Parallel collect(SB::new, SB::append, SB::append) H e l l o , W o r l d ! Hell Wo SBd!WoWoWoWo H e o ,l l W o r l d ! SBd!SBllHeHeWod!Hell
  227. 227. 227 Parallel collect(SB::new, SB::append, SB::append) H e l l o , W o r l d ! Hell Wo SBd!SBo, SBrlWoWoWoWo H e o ,l l W o r l d ! Hell SBd!SBd!SBllHeHeWod!Wo SBd!WoWoWoWo SBd!SBd!SBllHeHeWod!SBd!SBd!SBd!SBllHeHeWod!SBd!SBd!SBd!SBllHeHeWorlSBd!SBd!SBd!SBllHeHeWod!SBd!SBd!SBd!SBllHeHeWoo,
  228. 228. 228 Parallel collect(SB::new, SB::append, SB::append) H e l l o , W o r l d ! Hell Wo SBd!SBo, SBrlWoWoWoWo H e o ,l l W o r l d ! Hell SBd!SBd!SBllHeHeWod!SBo, SBrlSBd!SBd!SBd!SBllHeHeWod!SBd!SBd!SBd!SBllHeHeWorlSBd!SBd!SBd!SBllHeHeWod!SBd!SBd!SBd!SBllHeHeWoo,
  229. 229. 229 Parallel collect(SB::new, SB::append, SB::append) H e l l o , W o r l d ! Hello, Worl SBd! H e o ,l l W o r l d ! SBd!SBd!SBllHeHeWod!
  230. 230. 230 Parallel collect(SB::new, SB::append, SB::append) H e l l o , W o r l d ! Hello, Worl SBd! H e o ,l l W o r l d ! SBd!SBd!SBllHeHeWod!
  231. 231. 231 Parallel collect(SB::new, SB::append, SB::append) H e l l o , W o r l d ! Hello,Worl SBd! H e o ,l l W o r l d ! SBd!SBd!SBllHeHeWod!
  232. 232. 232 Parallel collect(SB::new, SB::append, SB::append) H e l l o , W o r l d ! Hello,Worl SBd! H e o ,l l W o r l d ! SBd!SBd!SBllHeHeWod!
  233. 233. 233 Parallel collect(SB::new, SB::append, SB::append) H e l l o , W o r l d ! Hello,World! H e o ,l l W o r l d !
  234. 234. 234 Collectors#joining ● Collector<CharSeq, ?, String> joining() joining(delimiter) joining(delimiter, prefix, suffix) – 文字列の連結をするCollectorを返す – 単なる連結だけでなく,デリミタなども指定可
  235. 235. 235 生徒の名前を連結する String name = students.stream() .map(Student::getName) .collect(Collectors.joining()); AliceBobCharlie
  236. 236. 236 生徒の名前を連結する String name = students.stream() .map(Student::getName) .collect(Collectors.joining(“, ”)); Alice, Bob, Charlie
  237. 237. 237 生徒の名前を連結する String name = students.stream() .map(Student::getName) .collect(Collectors .joining(“, ”, “[”, “]”)); [Alice, Bob, Charlie]
  238. 238. 238 ● 0から10まで出力 ● 0から10までの偶数を出力 ● Personのリストから名前を出力 ● 1から100までの総和を出力 ● 年齢の合計,平均,最小,最大 ● 名前の連結 ● Personの名前のリストを得る ● 部署別の社員のリストを得る
  239. 239. 239 Personのリストから名前のリスト List<String> names = new ArrayList<>(); for (Person p : persons) { names.add(p.getName()); }
  240. 240. 240 Collectors#toXxx ● toCollection() ● toList() ● toSet() – リストなどへの集約をするCollector
  241. 241. 241 Personのリストから名前のリスト persons.stream() .map(Person::getName) .collect(Collectors.toList())
  242. 242. 242 ● 0から10まで出力 ● 0から10までの偶数を出力 ● Personのリストから名前を出力 ● 1から100までの総和を出力 ● 年齢の合計,平均,最小,最大 ● 名前の連結 ● Personの名前のリストを得る ● 部署別の社員のリストを得る
  243. 243. 243 社員の部署別のMapを得たい Map<Dep, List<Emp>> empsByDep = new HashMap<>(); for (Emp e : emps) { Dep d = e.getDep(); if (empsByDep.containsKey(d)) { empsByDep.put(d, new ArrayList<>()); } empsByDep.get(d).add(e); }
  244. 244. 244 社員の部署別のMapを得たい Map<Dep, List<Emp>> empsByDep = new HashMap<>(); for (Emp e : emps) { Dep d = e.getDep(); empsByDep.computeIfAbsent(d, ArrayList::new) .add(e); }
  245. 245. 245 Collectors#groupingBy ● Collector<T, ?, Map<K, List<T>> groupingBy(T -> K) groupingByConcurrent(T -> K) – 型Kでグループ化
  246. 246. 246 社員の部署別のMapを得たい Map<Dep, List<Emp>> empsByDep = emps.stream() .collect(Collectors.groupingBy( Emp::getDep));
  247. 247. 247 Streamと並列処理
  248. 248. 248 Streamと並列処理 ● parallel()で並列モードへ – 適度な大きさで分割してFork/Join ● すべての場合で並列化できるのか? – No – Streamが様々な情報を考慮して並列化する ● データ数 ● 終端操作の内容 – 処理の順序に依存する物は並列化しにくい
  249. 249. 249 Streamと並列処理 ● 並列化したら早くなるのか – 一概には言えない・・・ ● データ数依存 ● マシン依存 ● 操作依存 – 早くなるものもある – 並列化に際してはベンチマーク必須
  250. 250. 250 並列処理で早くならないんだったら 今までのfor文でいいやー
  251. 251. 251 並列処理で早くならないんだったら 今までのfor文でいいやー ● やめましょう! – 簡単なイテレーションはStreamで – 複雑なイテレーションを要するものはfor文で ● Streamを使った時のメリット – 並列処理化に簡単に対応できる ● .parallel()を挟むだけ – 将来実装が変わって,何もしなくても早くなるかも ● JDK開発者が頑張る
  252. 252. 252 Project Lambdaまとめ ● もともとはマルチコア対応 ● 結果としては汎用的な仕様に – ラムダ式等 – コアライブラリ ● よりスマートなコードへ – RubyやScalaっぽい
  253. 253. 253 Thank you for your listening Enjoy JavaSE8
  • takahirosatou5686

    Dec. 5, 2017
  • ohtsuchi

    Jul. 31, 2014
  • jk-white045

    Jul. 21, 2014
  • objectx

    Jul. 20, 2014
  • hiroftp

    Jul. 12, 2014
  • nagasama

    Jul. 12, 2014
  • odango_San

    Jul. 12, 2014

関西Javaエンジニアの会スペシャル! Java 8リリース で発表させていただいた「Brand new Data Processing - StreamAPI」です.

Views

Total views

8,110

On Slideshare

0

From embeds

0

Number of embeds

55

Actions

Downloads

12

Shares

0

Comments

0

Likes

7

×