【java8 勉強会】 怖くない!ラムダ式, Stream API

1,326 views

Published on

デーコムでは9月30日に職場でJava 8の勉強会を実施しました。その時の資料を公開しますので、ぜひJava 8の世界に触れてみてください。

■ 【java8 勉強会】 怖くない!ラムダ式, Stream API
http://www.dcom-web.co.jp/technology/java8study/ ‎
■ デーコムHP
http://www.dcom-web.co.jp/
■ デーコムFacebook
https://www.facebook.com/dcom.corp/

Published in: Technology
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,326
On SlideShare
0
From Embeds
0
Number of Embeds
508
Actions
Shares
0
Downloads
0
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

【java8 勉強会】 怖くない!ラムダ式, Stream API

  1. 1. Java 8 勉強会 怖くない!ラムダ式, Stream API 2015/09/30 株式会社デーコム Ken
  2. 2. 自己紹介  名前  Ken  所属  株式会社デーコム (4年目)  やってること  Webアプリの実装  Java, SAStruts  Javascript, CSS3  jQuery, flotr2(グラフ表示)  SPARQL (sqlっぽいやつ)  今熱いこと  数学, 哲学  『数学ガール』(結城浩) とか  コンピュータ将棋(電王戦)
  3. 3. 自己紹介 – つづき  趣味とか  趣味プログラミング(まれに)  なぞぷよ, 2chブラウザ, ルービックキューブ用タイマーなど  音ゲー  beatmaniaIIDX 全曲ハードクリア(未解禁曲以外)  Dance Dance Revolution 足鳳凰  Splatoon  ウデマエ S, 最近のブキ:ノヴァブラスターネオ  タイムアタック  ルービックキューブ (自己べ22秒, 最近は40秒)  海腹川背, 星のカービィSDX, ロックマンX4
  4. 4. 勉強会のtarget  Java 6,7の知識で止まっている方  ラムダ式、あぁあの 気持ち悪い やつね という方  StreamAPI、って何だ という方
  5. 5. Java 8の新機能のうち、今回話さないこと  話さないこと  Stream API の parallel()  (使ったことない & 排他など複雑なので)  Optional  (準備できませんでした)  DateTime API  デフォルトメソッド  など...
  6. 6. 前提知識  Java 6  interface  匿名クラス  ジェネリクス
  7. 7. ラムダ式 (Lambda Expression) 舎 λ λ λ λ.....
  8. 8. x -> x * 2
  9. 9. ラムダ式  x -> x * 2  x を引数に取って、x * 2 を返す  メソッドとして考えると  int convert(int x) { return x * 2; }  JavaScriptなら  function(x){ return x * 2; }
  10. 10. ありそうな例
  11. 11. ラムダ式 - ありそうな例  人を表すクラス  class Person { String name; int age; }
  12. 12. ラムダ式 - ありそうな例  20歳以上の人だけ処理する  public void main(){ method(list, 20); }  void method (List<Person> list, int minAge) { for(Person p : list) { if(p.age >= minAge) doSomething(p); } }
  13. 13. ラムダ式 - ありそうな例  6歳以上12歳以下の人だけを処理する  public void main(){ method(list, 6, 12); }  void method (List<Person> list, int minAge, int maxAge) { for(Person p : list) { if(p.age >= minAge && p.age <= maxAge) doSomething(p); } }
  14. 14. ラムダ式 - ありそうな例  名前が「A」で始まる人だけを処理する  public void main(){ method(list, 0, 999, “A”); }  void method (List<Person> list, int minAge, int maxAge, String nameStartWith) { for(Person p : list) { if(p.age >= minAge && p.age <= maxAge && p.name.startWith(nameStartWith)) doSomething(p); } }
  15. 15. ラムダ式 - ありそうな例  名前が「B」で終わる人だけを処理  年齢が偶数の人だけを処理  名前の文字数が10以上の人だけを処理 ・ ・ ・
  16. 16. _人人人人人人_ > 引数地獄 <  ̄Y^Y^Y^Y^Y ̄
  17. 17. ラムダ式 – ありそうな例  interfaceを導入する  interface PersonFilter { /** * pをフィルタに通過させる場合はtrueを返します。 */ boolean test(Person p); }
  18. 18. ラムダ式 – ありそうな例  メソッド呼び出し側でフィルタ条件のプログラムを 書く (匿名クラスを利用)  public void main(){ method(list, new PersonFilter(){ boolean test(Person p) { return p.age >= 20; } }); }  void method(List<Person> list, PersonFilter filter) { for(Person p : list) { if(filter.test(p)) { doSomething(p); } } }
  19. 19. ラムダ式 – ありそうな例  メソッド呼び出し側でフィルタ条件のプログラムを 書く (匿名クラスを利用)  public void main(){ method(list, new PersonFilter(){ boolean test(Person p) { return p.age >= 20; } }); }  void method(List<Person> list, PersonFilter filter) { for(Person p : list) { if(filter.test(p)) { doSomething(p); } } } 絞り込み条件を変更しても 処理する側は変更なし
  20. 20. ラムダ式 – ありそうな例  匿名クラスの記法は無駄が多い(定型文が多い)  method(list, new PersonFilter(){ boolean test(Person p) { return p.age >= 20; } });
  21. 21. ラムダ式 – ありそうな例  匿名クラスの記法は無駄が多い(定型文が多い)  method(list, new PersonFilter(){ boolean test(Person p) { return p.age >= 20; } }); やりたいこと 定型文
  22. 22. ラムダ式
  23. 23. ラムダ式 – ありそうな例  ラムダ式を使った記法  method(list, p -> p.age >= 20);
  24. 24. ラムダ式 – ありそうな例  ラムダ式を使った記法  method(list, p -> p.age >= 20); アロー演算子 (ハイフン+大なり)
  25. 25. ラムダ式 – ありそうな例  ラムダ式を使った記法  method(list, p -> p.age >= 20); 引数 返す値
  26. 26. ラムダ式 – ありそうな例  ラムダ式 = 匿名クラスの省略記法  匿名クラス  new PersonFilter(){ boolean test(Person p) { return p.age >= 20; } });  ラムダ式  p -> p.age >= 20
  27. 27. ラムダ式 – ありそうな例  省略しない書き方  method(list,(Person p) -> { return p.age >= 20;}); 引数 処理
  28. 28. ラムダ式 – ありそうな例  省略しない書き方  method(list,(Person p) -> { return p.age >= 20;}); 引数の型が推測可能 な場合は不要
  29. 29. ラムダ式 – ありそうな例  省略しない書き方  method(list, (p) -> { return p.age >= 20;}); 引数1個なら カッコは不要
  30. 30. ラムダ式 – ありそうな例  省略しない書き方  method(list, p -> { return p.age >= 20;}); 単に値を返すだけなら 式だけを書けばOK
  31. 31. ラムダ式 – ありそうな例  省略しない書き方  method(list, p -> p.age >= 20);  ↑同じ!↓  method(list,(Person p) -> { return p.age >= 20;});
  32. 32. ラムダ式 – 記法の例  引数0個  () -> 1  引数1個  (x) -> x * 2  x -> x * 2  引数1個の場合のみ引数のカッコを省略できる  引数2個  (a, b) -> a - b
  33. 33. 他の例
  34. 34. ラムダ式 – 他の例  Android とか (イベントドリブンでよく見かけるパター ン)  Buttonがクリックされたときの処理を設定する  匿名クラス  button.addOnClickListener(new OnClickListener(){ void onClick() { doSomething(); } });  ラムダ式  button.addOnClickListener( () -> { doSomething(); });
  35. 35. ラムダ式 – 他の例  Android とか (イベントドリブンでよく見かけるパター ン)  Buttonがクリックされたときの処理を設定する  匿名クラス  button.addOnClickListener(new OnClickListener(){ void onClick() { doSomething(); } });  ラムダ式  button.addOnClickListener( () -> { doSomething(); }); ・行数が少ない ・インデントが浅い
  36. 36. 関数型interface
  37. 37. どんなinterfaceにもラムダ式を渡せるの?  引数の型が「関数型interface」の条件を満たしてい る場合だけ  ≒ メソッド数が1個のinterfaceのこと  例外: デフォルトメソッドはあってもいい etc...  interface Example { // メソッド1個なので関数型interface void hoge (); }
  38. 38. @FunctionalInterface アノテーション  interfaceが関数型interfaceであると宣言するアノテー ション  これを付けると「関数型interface」の条件を満たさない ときにコンパイルエラーにしてくれる  付けなくても条件を満たせば関数型interfaceになる  @FunctionalInterface interface InvalidExample { // メソッド2個なので関数型interfaceではない // コンパイルエラー void methodA(); void methodB(); }
  39. 39. 標準の関数型interface
  40. 40. ラムダ式 – 標準の関数型interface  例ではこのようなinterfaceを自分で定義した  interface PersonFilter { /** * pをフィルタに通過させる場合はtrueを返します。 */ boolean test(Person p); }  よく使うinterfaceが標準で定義されている  interface Predicate<T> { boolean test(T elem); // 実際にはもうちょっと複雑な定義 }
  41. 41. ラムダ式 – 標準の関数型interface  標準の関数型interfaceを使う場合  public void main(){ method(list, p -> p.age >= 20); }  void method(List<Person> list, Predicate<Person> filter) { for(Person p : list) { if(filter.test(p)) { doSomething(p); } } }
  42. 42. ラムダ式 – 標準の関数型interface  いろいろある  引数なし, 戻り値なし  Runnable  引数なし, 戻り値T  Supplier<T>  引数T, 戻り値なし  Consumer<T>  引数T, 戻り値U  Function<T, U>  引数T, 戻り値boolean  Predicate<T>  ほかに30種類くらいあります
  43. 43. メソッド参照  interfaceのメソッドと同じシグネチャを持つメソッ ドがあれば、メソッド自体を引数で渡せる  ラムダ式  button.addOnClickListener(() -> {doSomething();});  メソッド参照  button.addOnClickListener(this::doSomething);  コロン2個の後にメソッド名  ラムダ式よりもコードが短くなる  引数リストが隠れるのでわかりづらくなる場合がある
  44. 44. Stream API
  45. 45. Stream API の導入 – for文からの変換  5文字より長い文字列を大文字に変換して処理を行う  for(String s : list) { if (s.length() > 5) { String upper = s.toUpperCase(); method(upper); } }
  46. 46. Stream API の導入 – for文からの変換  5文字より長い文字列を大文字に変換して処理を行う  for(String s : list) { if (s.length() > 5) { String upper = s.toUpperCase(); method(upper); } } 絞り込み (filter)
  47. 47. Stream API の導入 – for文からの変換  5文字より長い文字列を大文字に変換して処理を行う  for(String s : list) { if (s.length() > 5) { String upper = s.toUpperCase(); method(upper); } } 変換 (map : 写像)
  48. 48. Stream API の導入 – for文からの変換  5文字より長い文字列を大文字に変換して処理を行う  for(String s : list) { if (s.length() > 5) { String upper = s.toUpperCase(); method(upper); } } 順次処理 (for each)
  49. 49. Stream API の導入 – for文からの変換  5文字より長い文字列を大文字に変換して処理を行う  for(String s : list) { filter (5文字より長い) map (大文字に変換) forEach (methodで処理) }
  50. 50. Stream API の導入  Stream APIによる記法  list.stream() .filter( s -> s.length() > 5) .map( s -> s.toUpperCase()) .forEach( s -> {method(s);} );
  51. 51. Stream API の導入  Stream APIによる記法  list.stream() .filter( s -> s.length() > 5) .map( s -> s.toUpperCase()) .forEach( s -> {method(s);} ); メソッドチェイン (4行で1文)
  52. 52. Stream API の導入  Stream APIによる記法  list.stream() .filter( s -> s.length() > 5) .map( s -> s.toUpperCase()) .forEach( s -> {method(s);} );  for(String s : list) { if (s.length() > 5) { String upper = s.toUpperCase(); method(upper); } } しっぽが無い
  53. 53. Stream API のメソッド
  54. 54. Stream API のメソッド - Streamの始め方  ListからStreamを作成する  List list = new ArrayList(Arrays.asList(“a”, “b”, “c”)); list.stream()  配列からStreamを作成する  String[] array = {“a”, “b”, “c”}; Arrays.stream(array)  整数を列挙したStreamを作成する  IntStream.range(0, 10)  for(int i=0; i<10; i++) と同じ  IntStream.rangeClosed(0, 10)  for(int i=0; i<=10; i++) と同じ  テキストファイルなどから  BufferedReader br = /*省略*/; br.lines()  1行ぶんの文字列を1要素としたStreamになる
  55. 55. Stream API のメソッド – Streamに対する処理  中間処理と終端処理がある  中間処理  Streamの要素を変化させる  戻り値はStream  メソッドチェインで処理が継続  終端処理  Streamの要素を使って 最終的な結果を得る or 処理を行う  戻り値は void とか 要素の型 とか boolean とか
  56. 56. Stream API のメソッド – 中間処理  filter (Predicate<T>)  Streamの要素を絞り込む  map (Function<T, U>)  Streamの要素を変換する  別の型に変えてもok  .map(p -> p.name) とか(Person → String)  skip (long n)  Streamの最初のn個の要素を飛ばす  peek (Consumer<T>)  各要素を処理する。forEachに似ているが、Streamを継続できる点で異 なる  デバッグ用  list.stream().peek( s -> {log.debug(s);}).…  etc.
  57. 57. Stream API のメソッド – 終端処理  forEach (Consumer<T>)  各要素を処理する  拡張for文とほぼ同じ使い方  for( String s : list) { }  list.stream().forEach( s -> { });  anyMatch (Predicate<T>) allMatch(Predicate<T>)  条件に一致する要素が存在するか / 全て一致するか を booleanで返す  collect (Collector)  Streamの全要素を格納したコレクションを生成して返す  引数には Collectors.toList() などを渡せる  etc.
  58. 58. 色々な例
  59. 59. Stream API – 他の例  Listの中身が全て条件を満たすかどうか  Java 7  boolean valid = true; for(Person p : list) { if( p.age < 18 ){ valid = false; break; } }  Java 8  boolean valid = list.stream() .allMatch( p -> p.age >= 18 );
  60. 60. Stream API – 他の例  Listの要素を標準出力に表示  java 7  for(String s : list) { System.out.plintln(s); }  java 8 (ラムダ式)  list.stream().forEach(s -> {System.out.println(s);});  java 8 (メソッド参照)  list.stream().forEach(System.out::println);
  61. 61. Stream API – 他の例  Listの要素を絞り込んで新しいListに格納する  Java 7  List<String> newList = new ArrayList<>(); for (String s : list) { if (s.length > 5){ newList.add(s); } }  Java 8  List<String> newList = list.stream() .filter( s -> s.length() > 5 ) .collect(Collectors.toList());
  62. 62. Stream API – 他の例  Listの要素を全て変換する  List#replaceAll  (Stream APIではなくListの新メソッド)  Java 7  List<String> newList = new ArrayList<>(); for(String s : list) { newList.add(s.toUpperCase()); }  Java 8  list.replaceAll( s -> s.toUpperCase() );
  63. 63. Stream API – 他の例  Mapの要素を順次処理  Map#forEach  (Stream API ではなくMapの新メソッド)  java 7  for(String k : map.keySet()){ Object v = map.get(v); method(k, v); }  java 8  map.forEach( (k, v) -> { method(k, v); } );
  64. 64. まとめ
  65. 65. まとめ  ラムダ式  匿名クラスの省略記法  関数型interfaceを引数にとるメソッドに渡せる  標準の関数型interfaceをうまく利用したい  Stream API  コレクションに新しく用意された便利な操作方法  Stream生成 → 中間処理*n → 終端処理  for文やwhile文はだいたいStream APIに書き換えできる  for文禁止時代の到来
  66. 66. ご清聴ありがとう ございました
  67. 67. 質問&雑談タイム

×