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.

from old java to java8 - KanJava Edition

2,399 views

Published on

from old Java to modern Java : reloaded
for Kansai Java Engineers' Group

Published in: Software
  • D0WNL0AD FULL ▶ ▶ ▶ ▶ http://1lite.top/AXdws ◀ ◀ ◀ ◀
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

from old java to java8 - KanJava Edition

  1. 1. from old Java
 to modern Java ∼ レビューで学ぶJava8時代のコーディング作法 Acroquest Technology株式会社
 JJUG / 関西Javaエンジニアの会 谷本 心 ( @cero_t )
  2. 2. 自己紹介 • 名前 : 谷本 心 (たにもと しん) • 職業 : Javaエンジニア / トラブルシューター
    トラブルシュート教育も引き受けます! • Twitter : @cero_t • その他 : 日本Javaユーザ会(JJUG) 幹事
     関西Javaエンジニアの会 主催
  3. 3. さて、
 Java8が出ましたが
  4. 4. 今日は
 関ジャバ∞
 と考えて
 差し支えないですか?
  5. 5.
  6. 6. 自己紹介 • 名前 : 谷本 心 (たにもと しん) • 職業 : Javaエンジニア / トラブルシューター
    トラブルシュート教育も引き受けます! • Twitter : @cero_t • その他 : 日本Javaユーザ会(JJUG) 幹事
     関西Javaエンジニアの会 主催
  7. 7. さて、
 Java8が出ましたが
  8. 8. 「どうせ、使うのはまだ先」
 とか思ってませんか?
  9. 9. きっと、ずっと先でしょう。
  10. 10. でも、たとえば今
  11. 11. Java6やJava7の勉強を
 きちんとできますか?
  12. 12. 出始めこそ、
 たくさん情報が出てくる
  13. 13. じゃ、いつやるか?
  14. 14. やらせねーよ (我が家)
  15. 15. from old Java
 to modern Java ∼ レビューで学ぶJava8時代のコーディング作法 Acroquest Technology株式会社
 JJUG / 関西Javaエンジニアの会 谷本 心 ( @cero_t )
  16. 16. ソースコードレビュー
 してますか?
  17. 17. レビューを
 する方が多いですか?
 受ける方が多いですか?
  18. 18. もちろん
 レビューする方が
 多いですね
  19. 19. 若いんで(?)
 レビューを受ける方が
 多いです
  20. 20. レビューなんて文化
 ありません
  21. 21. 履歴書の送付先 :
 tanimoto.shin@gmail.com
  22. 22. では早速、コード。
  23. 23. Map<Dept, Long> groupByDeptAndFilter(List<Emp> list) { return list.stream() .collect(Collectors.groupingBy(emp -> emp.dept)) .entrySet() .stream() .collect(Collectors.toMap(entry -> entry.getKey(), entry -> entry.getValue() .stream() .filter(emp -> emp.sal > 1000) .count())); }
  24. 24. 何これ読めない
  25. 25. 「よく分からないし
 for文とmapで
 書き直してくれる?」
  26. 26. Map<Dept, Long> groupByDeptClassic(List<Emp> list) { Map<Dept, Long> result = new HashMap<>(); for (Emp emp : list) { if (result.containsKey(emp.dept) == false) { result.put(emp.dept, 0L); } if (emp.sal > 1000) { Long count = result.get(emp.dept); count++; result.put(emp.dept, count); } } return result; }
  27. 27. 「あー、読みやすくて
 安心するー」
  28. 28. Welcome to
 老 害 世 代
  29. 29. from old Java
 to modern Java ∼ 老害にならないためのJava8入門 Acroquest Technology株式会社
 JJUG / 関西Javaエンジニアの会 谷本 心 ( @cero_t )
  30. 30. Lesson1 今の時代のファイル操作を
 理解せよ!
  31. 31. おさらい: finallyでcloseするという定石
  32. 32. List<String> readFileSE6(String fileName) { List<String> lines = new ArrayList<String>(); BufferedReader reader = null; try { reader = new BufferedReader(new FileReader(fileName)); String line; while ((line = reader.readLine()) != null) { lines.add("<" + line + ">"); } reader.close();
 } catch (IOException ex) { throw new RuntimeException(ex); } return lines; } これあかん やつや!
  33. 33. List<String> readFileSE6(String fileName) { List<String> lines = new ArrayList<String>(); BufferedReader reader = null; try { reader = new BufferedReader(new FileReader(fileName)); String line; while ((line = reader.readLine()) != null) { lines.add("<" + line + ">"); } } catch (IOException ex) { throw new RuntimeException(ex); // 例外処理は割愛 } finally { try { if (reader != null) { reader.close(); } } catch (IOException ex) { // この例外は無視する? } } return lines; } やっぱfinallyで
 closeですよね!
  34. 34. finallyでcloseするのは
 古い定石
 (∼Java6)
  35. 35. try-with-resourcesで
 イマドキのJavaに!
 (Java7∼)
  36. 36. List<String> readFileSE7_1(String fileName) { List<String> lines = new ArrayList<>(); try (FileReader in = new FileReader(fileName); BufferedReader reader = new BufferedReader(in)) { String line; while ((line = reader.readLine()) != null) { lines.add("<" + line + ">"); } } catch (IOException ex) { throw new RuntimeException(ex); } return lines; } これが
 try-with-resources!
  37. 37. でも! 変なところがあるんです。
  38. 38. List<String> readFileSE7_1(String fileName) { List<String> lines = new ArrayList<>(); try (FileReader in = new FileReader(fileName); BufferedReader reader = new BufferedReader(in)) { String line; while ((line = reader.readLine()) != null) { lines.add("<" + line + ">"); } } catch (IOException ex) { throw new RuntimeException(ex); } return lines; } !?
  39. 39. List<String> readFileSE7_2(String fileName) { List<String> lines = new ArrayList<>(); Path path = Paths.get(fileName); try (BufferedReader reader = Files.newBufferedReader(path)) { String line; while ((line = reader.readLine()) != null) { lines.add("<" + line + ">"); } } catch (IOException ex) { throw new RuntimeException(ex); } return lines; }
  40. 40. 新定石①: try-with-resourcesと
 FilesとPathで操作する
 (Java7∼)
  41. 41. 新定石②:
 ファイルを一気に読むなら
 Files.readAllLines!
 (Java7∼)
  42. 42. List<String> readFileSE7_3(String fileName) { try { List<String> lines = Files.readAllLines(Paths.get(fileName)); for (int i = 0; i < lines.size(); i++) { lines.set(i, "<" + lines.get(i) + ">"); } return lines; } catch (IOException ex) { throw new RuntimeException(ex); } } 一気に読み込むのは便利だけど、 ヒープメモリもたくさん使っちゃう し、それぞれの行に対する処理が 必要な場合は、どうしてもループを 回し直さなきゃいけないよね。
  43. 43. Java8時代は?
  44. 44. List<String> readFileSE8_1(String fileName) { List<String> lines = new ArrayList<>(); try { Files.lines(Paths.get(fileName)) .forEach(s -> lines.add("<" + s + ">")); } catch (IOException ex) { throw new UncheckedIOException(ex); } 
 return lines;
 }
  45. 45. 新定石③?: Files.linesで処理をする
 (Java8∼)
  46. 46. 新定石③: forやwhileを見たら
 Stream APIへの
 置き換えを考える
  47. 47. List<String> readFileSE8_1(String fileName) { try { return Files.lines(Paths.get(fileName)) .map(s -> "<" + s + ">") .collect(Collectors.toList()); } catch (IOException ex) { throw new UncheckedIOException(ex); } } 外部のオブジェクトを
 操作しない方が安心。
  48. 48. ちょっとクイズ
  49. 49. void writeSE8_1(String fileName, List<String> lines) { Path path = Paths.get(fileName); try (BufferedWriter writer = Files.newBufferedWriter(path)) { lines.forEach(s -> writer.write("<" + s + ">")); } catch (IOException e) { throw new UncheckedIOException(ex); } }
  50. 50. void writeSE8_1(String fileName, List<String> lines) { Path path = Paths.get(fileName); try (BufferedWriter writer = Files.newBufferedWriter(path)) { lines.forEach(s -> writer.write("<" + s + ">")); } catch (IOException e) { throw new UncheckedIOException(ex); } } 1. ちゃんと出力されるんじゃない? 2. 順番がグチャグチャになりそうだな・・・ 3. コンパイルエラーが起きるよ、これ 4. 実行時例外が起きるよ、これ
  51. 51. void writeSE8_1(String fileName, List<String> lines) { Path path = Paths.get(fileName); try (BufferedWriter writer = Files.newBufferedWriter(path)) { lines.forEach(s -> writer.write("<" + s + ">")); } catch (IOException e) { throw new UncheckedIOException(ex); } } 1. ちゃんと出力されるんじゃない? 2. 順番がグチャグチャになりそうだな・・・ 3. コンパイルエラーが起きるよ、これ 4. 実行時例外が起きるよ、これ
  52. 52. void writeSE8_2(String fileName, List<String> lines) { Path path = Paths.get(fileName); try (BufferedWriter writer = Files.newBufferedWriter(path)) { lines.forEach(s -> { try { writer.write(s); } catch (IOException ex) { throw new UncheckedIOException(ex); } }); } catch (IOException ex) { throw new UncheckedIOException(ex); } }
  53. 53. なんでもかんでも
 Lambdaにすれば
 良いってもんでもない
  54. 54. Lesson2
 文字列操作は
 どう変わる?
  55. 55. String joinSE7(List<String> lines) { StringBuilder builder = new StringBuilder(); for (int i = 0; i < lines.size(); i++) { if (i > 0) { builder.append(","); } builder.append(lines.get(i)); } return builder.toString(); } String joinCommons(List<String> lines) { return StringUtils.join(lines, ","); } String joinGuava(List<String> lines) { return Joiner.on(",").join(lines); } みんな大好き
 文字列結合 Commons Langとか
 Guavaとか使うよねー
  56. 56. String joinSE8(List<String> lines) { return String.join(",", lines); } ようやく搭載された
 String#join
  57. 57. 新定石④: String.joinさん
 こんにちは!
 (Java8∼)
  58. 58. String joinPrefixSE7(List<String> lines) { StringBuilder builder = new StringBuilder(); for (int i = 0; i < lines.size(); i++) { if (i > 0) { builder.append(","); } builder.append(“<") .append(lines.get(i)) .append(">"); } return builder.toString(); } じゃ、こういうパター ンはどうするの?
  59. 59. private String joinPrefixCommons(List<String> lines) { return "<" + StringUtils.join(lines, ">,<") + ">"; } private String joinPrefixGuava(List<String> lines) { return "<" + Joiner.on(">,<").join(lines) + ">"; }
  60. 60. 助けてJava8マン!
  61. 61. private String joinPrefixSE8(List<String> lines) { return lines.stream() .map(s -> "<" + s +”>") .collect(Collectors.joining(",")); } 要するに
 StreamAPIが正義
  62. 62. 新定石⑤: String.joinさん
 さようなら!
 (Java8∼)
  63. 63. 結局、新定石③: forやwhileを見たら
 Stream APIへの
 置き換えを考える
  64. 64. Lesson3 forやwhileとifとか
 いろいろ行なう集計的なアレ
  65. 65. Map<Dept, Long> groupByDeptAndFilterClassic(List<Emp> list) { Map<Dept, Long> result = new HashMap<>(); for (Emp emp : list) { if (result.containsKey(emp.dept) == false) { result.put(emp.dept, 0L); } if (emp.sal > 1000) { Long count = result.get(emp.dept) + 1; result.put(emp.dept, count); } } return result; } 給料が1000ドルを超える社員 の数を部署ごとに集計する
  66. 66. Java8時代は、
 最初、こうなると思う
  67. 67. Map<Dept, Long> groupByDeptAndFilterClassic(List<Emp> list) { Map<Dept, Long> result = new HashMap<>(); for (Emp emp : list) { result.putIfAbsent(emp.dept, 0L); if (emp.sal > 1000) { Long count = result.get(emp.dept) + 1; result.put(emp.dept, count); } } return result; } 新しい便利API
  68. 68. でも、新定石③: forやwhileを見たら
 Stream APIへの
 置き換えを考える
  69. 69. Map<Dept, Long> groupByDeptAndFilterLambda(List<Emp> list) { return list.stream() .collect(Collectors.groupingBy(emp -> emp.dept)) .entrySet() .stream() .collect(Collectors.toMap(entry -> entry.getKey(), entry -> entry.getValue() .stream() .filter(emp -> emp.sal > 1000) .count())); }
  70. 70. どうやって書くの? どうやって読むの?
  71. 71. select DEPT_ID, COUNT(EMP_ID) from EMP where EMP.SAL > 1000 group by EMP.DEPT_ID
  72. 72. SQLと一緒。
 勉強して、書いて、
 書いて、書いて、
 そして、書く。
  73. 73. input : List<Emp> output : Map<Dept, Empの数>     ただしEmpは給与が1000より大きい 1. いったん List<Emp> を Map<Dept, List<Emp>> にグルーピングする。 2. Mapの値であるList<Emp>を1000でフィルタリングする。 3. フィルタリング後のList<Emp>をカウントする。
  74. 74. Map<Dept, Long> groupByDeptAndFilterLambda2(List<Emp> list) { Map<Dept, List<Emp>> groupByDept = list.stream() .collect(Collectors.groupingBy(emp -> emp.dept)); Map<Dept, List<? super Emp>> filtered = groupByDept.entrySet() .stream() .collect(Collectors.toMap(entry -> entry.getKey(), entry -> entry.getValue() .stream() .filter(emp -> emp.sal > 1000) .collect(Collectors.toList()))); Map<Dept, Long> counted = filtered.entrySet() .stream() .collect(Collectors.toMap(entry -> entry.getKey(), entry -> entry.getValue() .stream() .count())); return counted; }
  75. 75. Map<Dept, Long> groupByDeptAndFilterLambda(List<Emp> list) { return list.stream() .collect(Collectors.groupingBy(emp -> emp.dept)) .entrySet() .stream() .collect(Collectors.toMap(entry -> entry.getKey(), entry -> entry.getValue() .stream() .filter(emp -> emp.sal > 1000) .count())); }
  76. 76. 正直、ちょっとAPIが
 足りない感じなので
 自分で追加すると良い
 (この辺は熟成待ち?) 
 http://blog.exoego.net/2013/12/control-collector-to-rule-stream-api.html
 Collectorを征す者はStream APIを征す(部分的に) - I am programmer and proud
  77. 77. 検索: ラムダ禁止
  78. 78. まとめ
  79. 79. forとwhileを見たら
 Lambda化を考えよう
  80. 80. レビューで
 forとwhileを見つけたら
 Lambda化させよう
  81. 81. レビューで
 100行ぐらいの
 Lambdaが出てきたら
  82. 82.
  83. 83. 自分たちの標準として
 どうすれば読みやすくするか
 チームで考えよう!
  84. 84. from old Java
 to modern Java ∼ 老害にならないためのJava8入門 Acroquest Technology株式会社
 JJUG / 関西Javaエンジニアの会 谷本 心 ( @cero_t )
  85. 85. あ、そうそう
  86. 86. from old Java
 to modern Java がきっかけで
  87. 87. Java本格入門(仮) 鋭意執筆中!
  88. 88. 頑張ります m(_ _)m
  89. 89. Let s Study Java8!

×