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.

20150302 java8 第一回_ラムダ式(1)

1,076 views

Published on

Published in: Engineering
  • Be the first to comment

20150302 java8 第一回_ラムダ式(1)

  1. 1. Java 8 勉強会 第一回 ラムダ式 (1) 2015/3/2 開発部 3G 野口光太郎
  2. 2. ついに Java 8 が使える
  3. 3. Java 8 導入予定 • Thunderbus • 1.0 で導入済(8u31) • PIMSYNC • 2.2 で導入予定 • DataSpider Servista • 4.0 で導入予定
  4. 4. Java 8 の新機能 • ラムダ式 • Stream API • Date and Time API • JavaFX 8 • etc…
  5. 5. Java 8 の新機能 • ラムダ式 • Stream API • Date and Time API • JavaFX 8 • etc…
  6. 6. ついに ラムダ式 が使える
  7. 7. Java 8 勉強会 第一回 ラムダ式 (1) 2015/3/2 開発部 3G 野口光太郎
  8. 8. アジェンダ 1. ラムダ式は何が違うのか 2. ラムダ式を書く 3. forEach によるイテレーション
  9. 9. 1. ラムダ式は 何が 違うのか
  10. 10. ラムダ式とは • 匿名関数の簡略な記法 • Java 8(2014/3)で導入 • 取り立てて新しい概念ではない • C++11(2011 年) • C# 3.0(2008 年) • Lisp(ざっと 50 年くらい前)
  11. 11. ラムダ式とは • 匿名関数の簡略な記法 • Java 8(2014/3)で導入 • 取り立てて新しい概念ではない • C++11(2011 年) • C# 3.0(2008 年) • Lisp(ざっと 50 年くらい前)
  12. 12. 匿名関数の 簡略な記法 ……?
  13. 13. 匿名関数とは • 匿名の関数 • 要するにこれのこと List<Integer> numbers = Arrays.asList(1, 1, 2, 3, 5); Collections.sort(numbers, new Comparator<Integer>() { @Override public int compare(Integer i1, Integer i2) { return i2 - i1; } });
  14. 14. 匿名関数の簡略な記法 • こう書ける List numbers = Arrays.asList(1, 1, 2, 3, 5); Collections.sort(numbers, (i1, i2) -> i2 - i1);
  15. 15. で?
  16. 16. Excel アダプタのテスト コードの例(Before) • こういうのも private interface Assertion { public void call(Sheet expectedSheet, Sheet actualSheet, int row, int column) throws Exception; } private void assertDataAndFormat(String expectedExcelFileName, String sheetName, int startRowIndex, int startColumnIndex, int endRowIndex, int endColumnIndex) throws Exception { assertWithExpectedExcelFile( expectedExcelFileName, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, new Assertion() { @Override public void call(Sheet expectedSheet, Sheet actualSheet, int row, int column) throws Exception { Cell expetedCell = expectedSheet.getCell(column, row); Cell actualCell = actualSheet.getCell(column, row); assertEquals(expetedCell.getContents(), actualCell.getContents()); assertEquals(expetedCell.getType().toString(), actualCell.getType().toString()); assertEquals(expetedCell.getCellFormat().getFormat().getFormatString(), actualCell.getCellFormat().getFormat().getFormatString()); AssertUtil.assertCellFormatByJExcelApi( expetedCell.getCellFormat(), actualCell.getCellFormat()); } } ); }
  17. 17. Excel アダプタのテスト コードの例(Before) • こういうのも private interface Assertion { public void call(Sheet expectedSheet, Sheet actualSheet, int row, int column) throws Exception; } private void assertDataAndFormat(String expectedExcelFileName, String sheetName, int startRowIndex, int startColumnIndex, int endRowIndex, int endColumnIndex) throws Exception { assertWithExpectedExcelFile( expectedExcelFileName, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, new Assertion() { @Override public void call(Sheet expectedSheet, Sheet actualSheet, int row, int column) throws Exception { Cell expetedCell = expectedSheet.getCell(column, row); Cell actualCell = actualSheet.getCell(column, row); assertEquals(expetedCell.getContents(), actualCell.getContents()); assertEquals(expetedCell.getType().toString(), actualCell.getType().toString()); assertEquals(expetedCell.getCellFormat().getFormat().getFormatString(), actualCell.getCellFormat().getFormat().getFormatString()); AssertUtil.assertCellFormatByJExcelApi( expetedCell.getCellFormat(), actualCell.getCellFormat()); } } ); }
  18. 18. Excel アダプタのテスト コードの例(Before) • こういうのも private interface Assertion { public void call(Sheet expectedSheet, Sheet actualSheet, int row, int column) throws Exception; } private void assertDataAndFormat(String expectedExcelFileName, String sheetName, int startRowIndex, int startColumnIndex, int endRowIndex, int endColumnIndex) throws Exception { assertWithExpectedExcelFile( expectedExcelFileName, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, new Assertion() { @Override public void call(Sheet expectedSheet, Sheet actualSheet, int row, int column) { Cell expetedCell = expectedSheet.getCell(column, row); Cell actualCell = actualSheet.getCell(column, row); assertEquals(expetedCell.getContents(), actualCell.getContents()); assertEquals(expetedCell.getType().toString(), actualCell.getType().toString()); assertEquals(expetedCell.getCellFormat().getFormat().getFormatString(), actualCell.getCellFormat().getFormat().getFormatString()); AssertUtil.assertCellFormatByJExcelApi( expetedCell.getCellFormat(), actualCell.getCellFormat()); } } ); } ノイズ ・new ・Assertion() ・@Override ・public ・void ・call テストの内容にとっては全部どうでもいい
  19. 19. Excel アダプタのテスト コードの例(Before) • こういうのも private interface Assertion { public void call(Sheet expectedSheet, Sheet actualSheet, int row, int column) throws Exception; } private void assertDataAndFormat(String expectedExcelFileName, String sheetName, int startRowIndex, int startColumnIndex, int endRowIndex, int endColumnIndex) throws Exception { assertWithExpectedExcelFile( expectedExcelFileName, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, new Assertion() { @Override public void call(Sheet expectedSheet, Sheet actualSheet, int row, int column) throws Exception { Cell expetedCell = expectedSheet.getCell(column, row); Cell actualCell = actualSheet.getCell(column, row); assertEquals(expetedCell.getContents(), actualCell.getContents()); assertEquals(expetedCell.getType().toString(), actualCell.getType().toString()); assertEquals(expetedCell.getCellFormat().getFormat().getFormatString(), actualCell.getCellFormat().getFormat().getFormatString()); AssertUtil.assertCellFormatByJExcelApi( expetedCell.getCellFormat(), actualCell.getCellFormat()); } } ); }
  20. 20. Excel アダプタのテスト コードの例(Before) • こういうのも private interface Assertion { public void call(Sheet expectedSheet, Sheet actualSheet, int row, int column) throws Exception; } private void assertDataAndFormat(String expectedExcelFileName, String sheetName, int startRowIndex, int startColumnIndex, int endRowIndex, int endColumnIndex) throws Exception { assertWithExpectedExcelFile( expectedExcelFileName, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, (expectedSheet, actualSheet, row, column) -> { Cell expetedCell = expectedSheet.getCell(column, row); Cell actualCell = actualSheet.getCell(column, row); assertEquals(expetedCell.getContents(), actualCell.getContents()); assertEquals(expetedCell.getType().toString(), actualCell.getType().toString()); assertEquals(expetedCell.getCellFormat().getFormat().getFormatString(), actualCell.getCellFormat().getFormat().getFormatString()); AssertUtil.assertCellFormatByJExcelApi( expetedCell.getCellFormat(), actualCell.getCellFormat()); } } ); } • こう書ける
  21. 21. Excel アダプタのテスト コードの例(Before) • こういうのも private interface Assertion { public void call(Sheet expectedSheet, Sheet actualSheet, int row, int column) throws Exception; } private void assertDataAndFormat(String expectedExcelFileName, String sheetName, int startRowIndex, int startColumnIndex, int endRowIndex, int endColumnIndex) throws Exception { assertWithExpectedExcelFile( expectedExcelFileName, sheetName, startRowIndex, startColumnIndex, endRowIndex, endColumnIndex, (expectedSheet, actualSheet, row, column) -> { Cell expetedCell = expectedSheet.getCell(column, row); Cell actualCell = actualSheet.getCell(column, row); assertEquals(expetedCell.getContents(), actualCell.getContents()); assertEquals(expetedCell.getType().toString(), actualCell.getType().toString()); assertEquals(expetedCell.getCellFormat().getFormat().getFormatString(), actualCell.getCellFormat().getFormat().getFormatString()); AssertUtil.assertCellFormatByJExcelApi( expetedCell.getCellFormat(), actualCell.getCellFormat()); } } ); } Excel アダプタのテスト コードの例(After) (匿名関数) • こう書ける • メソッドに関数を直接渡せる
  22. 22. (注意) 実際に過去に書いたコードの中からノイズが減って 嬉しい例としてたまたまこれを思い出したので挙げ ましたが、関数型のスタイルという観点では、そも そもあまり長いラムダ式は推奨されない、という考 え方もあるようです。 あとそもそもアサーションの仕方がダサいとかは今 はツッコまない方向で……。
  23. 23. xxx アダプタのテスト コードの例(Before) • こういうのも @Test public void ソート_標準カラム_文書管理番号_昇順() throws Exception { ソート(STANDARD_COLUMN, MANAGE_NUM, TAG_DOC_NUM, 0, new Comparator() { @Override public int compare(XXXDocument o1, XXXDocument o2){ return o1.getDocNum() - o2.getDocNum(); } }); }
  24. 24. xxx アダプタのテスト コードの例(Before) • こういうのも @Test public void ソート_標準カラム_文書管理番号_昇順() throws Exception { ソート(STANDARD_COLUMN, MANAGE_NUM, TAG_DOC_NUM, 0, new Comparator() { @Override public int compare(XXXDocument o1, XXXDocument o2) { return o1.getDocNum() - o2.getDocNum(); } }); } @Test public void ソート_標準カラム_文書管理番号_降順() throws Exception { ソート(STANDARD_COLUMN, MANAGE_NUM, TAG_DOC_NUM, 1, new Comparator() { @Override public int compare(XXXDocument o1, XXXDocument o2) { return o2.getDocNum() - o1.getDocNum(); } }); } 1
  25. 25. @Test public void ソート_標準カラム_文書名_昇順() throws Exception { ソート(STANDARD_COLUMN, DOC_NAME, TAG_DOC_NAME, 0, new Comparator() { @Override public int compare(XXXDocument o1, XXXDocument o2) { String v1 = o1.getDocName(); String v2 = o2.getDocName(); return compareNull(v1, v2); } }); } @Test public void ソート_標準カラム_文書名_降順() throws Exception { ソート(STANDARD_COLUMN, DOC_NAME, TAG_DOC_NAME, 1, new Comparator() { @Override public int compare(XXXDocument o1, XXXDocument o2) { String v1 = o1.getDocName(); String v2 = o2.getDocName(); return compareNull(v2, v1); } }); } @Test public void ソート_標準カラム_コンピューター名_昇順() throws Exception { ソート(STANDARD_COLUMN, COMPUTER_NAME, TAG_COMPUTER_NAME, 0, new Comparator() { @Override public int compare(XXXDocument o1, XXXDocument o2) { String v1 = o1.getComputerName(); String v2 = o2.getComputerName(); return compareNull(v1, v2); } }); } @Test public void ソート_標準カラム_コンピューター名_降順() throws Exception { ソート(STANDARD_COLUMN, COMPUTER_NAME, TAG_COMPUTER_NAME, 1, new Comparator() { @Override public int compare(XXXDocument o1, XXXDocument o2) { String v1 = o1.getComputerName(); String v2 = o2.getComputerName(); return compareNull(v2, v1); } }); } 2
  26. 26. @Test public void ソート_標準カラム_ユーザー名_昇順() throws Exception { ソート(STANDARD_COLUMN, USER_NAME, TAG_USER_NAME, 0, new Comparator() { @Override public int compare(XXXDocument o1, XXXDocument o2) { String v1 = o1.getUserName(); String v2 = o2.getUserName(); return compareNull(v1, v2); } }); } @Test public void ソート_標準カラム_ユーザー名_降順() throws Exception { ソート(STANDARD_COLUMN, USER_NAME, TAG_USER_NAME, 1, new Comparator() { @Override public int compare(XXXDocument o1, XXXDocument o2) { String v1 = o1.getUserName(); String v2 = o2.getUserName(); return compareNull(v2, v1); } }); } @Test public void ソート_標準カラム_印刷プリンター名_昇順() throws Exception { ソート(STANDARD_COLUMN, PRINTER_NAME, TAG_PRINTER_NAME, 0, new Comparator() { @Override public int compare(XXXDocument o1, XXXDocument o2) { String v1 = o1.getPrinterName(); String v2 = o2.getPrinterName(); return compareNull(v1, v2); } }); } @Test public void ソート_標準カラム_印刷プリンター名_降順() throws Exception { ソート(STANDARD_COLUMN, PRINTER_NAME, TAG_PRINTER_NAME, 1, new Comparator() { @Override public int compare(XXXDocument o1, XXXDocument o2) { String v1 = o1.getPrinterName(); String v2 = o2.getPrinterName(); return compareNull(v2, v1); } }); } 3
  27. 27. @Test public void ソート_標準カラム_印刷プリンターグループ名_昇順() throws Exception { ソート(STANDARD_COLUMN, GROUP_NAME, TAG_PRINTER_GROUP_NAME, 0, new Comparator() { @Override public int compare(XXXDocument o1, XXXDocument o2) { String v1 = o1.getPrinterGroupName(); String v2 = o2.getPrinterGroupName(); return compareNull(v1, v2); } }); } @Test public void ソート_標準カラム_印刷プリンターグループ名_降順() throws Exception { ソート(STANDARD_COLUMN, GROUP_NAME, TAG_PRINTER_GROUP_NAME, 1, new Comparator() { @Override public int compare(XXXDocument o1, XXXDocument o2) { String v1 = o1.getPrinterGroupName(); String v2 = o2.getPrinterGroupName(); return compareNull(v2, v1); } }); } @Test public void ソート_標準カラム_スプール開始時刻_昇順() throws Exception { ソート(STANDARD_COLUMN, SPOOL_START_TIME, TAG_SPOOL_START_TIME, 0, new Comparator() { @Override public int compare(XXXDocument o1, XXXDocument o2) { Date v1 = o1.getSpoolStartTime(); Date v2 = o2.getSpoolStartTime(); return compareNull(v1, v2); } }); } @Test public void ソート_標準カラム_スプール開始時刻_降順() throws Exception { ソート(STANDARD_COLUMN, SPOOL_START_TIME, TAG_SPOOL_START_TIME, 1, new Comparator() { @Override public int compare(XXXDocument o1, XXXDocument o2) { Date v1 = o1.getSpoolStartTime(); Date v2 = o2.getSpoolStartTime(); return compareNull(v2, v1); } }); } 4
  28. 28. @Test public void ソート_標準カラム_スプール終了時刻_昇順() throws Exception { ソート(STANDARD_COLUMN, SPOOL_END_TIME, TAG_SPOOL_END_TIME, 0, new Comparator() { @Override public int compare(XXXDocument o1, XXXDocument o2) { Date v1 = o1.getSpoolEndTime(); Date v2 = o2.getSpoolEndTime(); return compareNull(v1, v2); } }); } @Test public void ソート_標準カラム_スプール終了時刻_降順() throws Exception { ソート(STANDARD_COLUMN, SPOOL_END_TIME, TAG_SPOOL_END_TIME, 1, new Comparator() { @Override public int compare(XXXDocument o1, XXXDocument o2) { Date v1 = o1.getSpoolEndTime(); Date v2 = o2.getSpoolEndTime(); return compareNull(v2, v1); } }); } @Test public void ソート_標準カラム_印刷開始時刻_昇順() throws Exception { ソート(STANDARD_COLUMN, PRINT_START_TIME, TAG_PRINT_START_TIME, 0, new Comparator() { @Override public int compare(XXXDocument o1, XXXDocument o2) { Date v1 = o1.getPrintStartTime(); Date v2 = o2.getPrintStartTime(); return compareNull(v1, v2); } }); } @Test public void ソート_標準カラム_印刷開始時刻_降順() throws Exception { ソート(STANDARD_COLUMN, PRINT_START_TIME, TAG_PRINT_START_TIME, 1, new Comparator() { @Override public int compare(XXXDocument o1, XXXDocument o2) { Date v1 = o1.getPrintStartTime(); Date v2 = o2.getPrintStartTime(); return compareNull(v2, v1); } }); } 5
  29. 29. @Test public void ソート_標準カラム_印刷終了時刻_昇順() throws Exception { ソート(STANDARD_COLUMN, PRINT_END_TIME, TAG_PRINT_END_TIME, 0, new Comparator() { @Override public int compare(XXXDocument o1, XXXDocument o2) { Date v1 = o1.getPrintEndTime(); Date v2 = o2.getPrintEndTime(); return compareNull(v1, v2); } }); } @Test public void ソート_標準カラム_印刷終了時刻_降順() throws Exception { ソート(STANDARD_COLUMN, PRINT_END_TIME, TAG_PRINT_END_TIME, 1, new Comparator() { @Override public int compare(XXXDocument o1, XXXDocument o2) { Date v1 = o1.getPrintEndTime(); Date v2 = o2.getPrintEndTime(); return compareNull(v2, v1); } }); } @Test public void ソート_標準カラム_最終更新時刻_昇順() throws Exception { ソート(STANDARD_COLUMN, UPDATE_TIME, TAG_UPDATE_TIME, 0, new Comparator() { @Override public int compare(XXXDocument o1, XXXDocument o2) { Date v1 = o1.getUpdateTime(); Date v2 = o2.getUpdateTime(); return compareNull(v1, v2); } }); } @Test public void ソート_標準カラム_最終更新時刻_降順() throws Exception { ソート(STANDARD_COLUMN, UPDATE_TIME, TAG_UPDATE_TIME, 1, new Comparator() { @Override public int compare(XXXDocument o1, XXXDocument o2) { Date v1 = o1.getUpdateTime(); Date v2 = o2.getUpdateTime(); return compareNull(v2, v1); } }); } 6
  30. 30. 22 テストケース 6 ページ 247 行
  31. 31. • こう書ける @Test public void ソート_標準カラム_文書管理番号_昇順() throws Exception { ソート(STANDARD_COLUMN, MANAGE_NUM, TAG_DOC_NUM, 0, (o1, o2) -> o1.getDocNum() - o2.getDocNum()); } @Test public void ソート_標準カラム_文書管理番号_降順() throws Exception { ソート(STANDARD_COLUMN, MANAGE_NUM, TAG_DOC_NUM, 1, (o1, o2) -> o2.getDocNum() - o1.getDocNum()); } @Test public void ソート_標準カラム_文書名_昇順() throws Exception { ソート(STANDARD_COLUMN, DOC_NAME, TAG_DOC_NAME, 0, (o1, o2) -> compareNull(o1.getDocName(), o2.getDocName()); } @Test public void ソート_標準カラム_文書名_降順() throws Exception { ソート(STANDARD_COLUMN, DOC_NAME, TAG_DOC_NAME, 1, (o1, o2) -> compareNull(o2.getDocName(), o1.getDocName()); } @Test public void ソート_標準カラム_コンピューター名_昇順() throws Exception { ソート(STANDARD_COLUMN, COMPUTER_NAME, TAG_COMPUTER_NAME, 0, (o1, o2) -> compareNull(o1.getComputerName(), o2.getComputerName()); } xxx アダプタのテスト コードの例(After) 1
  32. 32. @Test public void ソート_標準カラム_コンピューター名_降順() throws Exception { ソート(STANDARD_COLUMN, COMPUTER_NAME, TAG_COMPUTER_NAME, 1, (o1, o2) -> compareNull(o2.getComputerName(), o1.getComputerName()); } @Test public void ソート_標準カラム_ユーザー名_昇順() throws Exception { ソート(STANDARD_COLUMN, USER_NAME, TAG_USER_NAME, 0, (o1, o2) -> compareNull(o1.getUserName(), o2.getUserName()); } @Test public void ソート_標準カラム_ユーザー名_降順() throws Exception { ソート(STANDARD_COLUMN, USER_NAME, TAG_USER_NAME, 1, (o1, o2) -> compareNull(o2.getUserName(), o1.getUserName()); } @Test public void ソート_標準カラム_印刷プリンター名_昇順() throws Exception { ソート(STANDARD_COLUMN, PRINTER_NAME, TAG_PRINTER_NAME, 0, (o1, o2) -> compareNull(o1.getPrinterName(), o2.getPrinterName()); } @Test public void ソート_標準カラム_印刷プリンター名_降順() throws Exception { ソート(STANDARD_COLUMN, PRINTER_NAME, TAG_PRINTER_NAME, 1, (o1, o2) -> compareNull(o2.getPrinterName(), o1.getPrinterName()); } @Test public void ソート_標準カラム_印刷プリンターグループ名_昇順() throws Exception { ソート(STANDARD_COLUMN, GROUP_NAME, TAG_PRINTER_GROUP_NAME, 0, (o1, o2) -> compareNull(o1.getPrinterGroupName(), o2.getPrinterGroupName()); } @Test public void ソート_標準カラム_印刷プリンターグループ名_降順() throws Exception { ソート(STANDARD_COLUMN, GROUP_NAME, TAG_PRINTER_GROUP_NAME, 1, (o1, o2) -> compareNull(o2.getPrinterGroupName(), o1.getPrinterGroupName()); } @Test public void ソート_標準カラム_スプール開始時刻_昇順() throws Exception { ソート(STANDARD_COLUMN, SPOOL_START_TIME, TAG_SPOOL_START_TIME, 0, (o1, o2) -> compareNull(o1.getSpoolStartTime(), o2.getSpoolStartTime()); } @Test public void ソート_標準カラム_スプール開始時刻_降順() throws Exception { ソート(STANDARD_COLUMN, SPOOL_START_TIME, TAG_SPOOL_START_TIME, 1, (o1, o2) -> compareNull(o2.getSpoolStartTime(), o1.getSpoolStartTime()); } @Test public void ソート_標準カラム_スプール終了時刻_昇順() throws Exception { ソート(STANDARD_COLUMN, SPOOL_END_TIME, TAG_SPOOL_END_TIME, 0, (o1, o2) -> compareNull(o1.getSpoolEndTime(), o2.getSpoolEndTime()); } 2
  33. 33. @Test public void ソート_標準カラム_スプール終了時刻_降順() throws Exception { ソート(STANDARD_COLUMN, SPOOL_END_TIME, TAG_SPOOL_END_TIME, 1, (o1, o2) -> compareNull(o2.getSpoolEndTime(), o1.getSpoolEndTime()); } @Test public void ソート_標準カラム_印刷開始時刻_昇順() throws Exception { ソート(STANDARD_COLUMN, PRINT_START_TIME, TAG_PRINT_START_TIME, 0, (o1, o2) -> compareNull(o1.getPrintStartTime(), o2.getPrintStartTime()); } @Test public void ソート_標準カラム_印刷開始時刻_降順() throws Exception { (o1, o2) -> compareNull(o2.getPrintStartTime(), o1.getPrintStartTime()); } @Test public void ソート_標準カラム_印刷終了時刻_昇順() throws Exception { ソート(STANDARD_COLUMN, PRINT_END_TIME, TAG_PRINT_END_TIME, 0, (o1, o2) -> compareNull(o1.getPrintEndTime(), o2.getPrintEndTime()); } @Test public void ソート_標準カラム_印刷終了時刻_降順() throws Exception { ソート(STANDARD_COLUMN, PRINT_END_TIME, TAG_PRINT_END_TIME, 1, (o1, o2) -> compareNull(o2.getPrintEndTime(), o1.getPrintEndTime()); } @Test public void ソート_標準カラム_最終更新時刻_昇順() throws Exception { (o1, o2) -> compareNull(o1.getUpdateTime(), o2.getUpdateTime()); } @Test public void ソート_標準カラム_最終更新時刻_降順() throws Exception { ソート(STANDARD_COLUMN, UPDATE_TIME, TAG_UPDATE_TIME, 1, (o1, o2) -> compareNull(o2.getUpdateTime(), o1.getUpdateTime()); } 3
  34. 34. 22 テストケース 3 ページ 107 行
  35. 35. テストケース数 : 22 → 22 (100%) ページ数 : 6 → 3 (50%) 行数 : 247→107 (43%)
  36. 36. 嬉しい • ノイズの減少 • 本質的なコードだけが残る • 一覧性の向上 • たとえばテストがスペックに近 づく • 気がする
  37. 37. Q: ラムダ式は 何が 違うのか
  38. 38. A: 匿名関数が 簡略に書けて 嬉しい
  39. 39. それだけ?
  40. 40. そうだけど、 (全然むずかしくない) そうではない。 (文字数が減るとか、 それだけではない)
  41. 41. 開かれる 関数型スタイルへの道 • 私たちが愛する • 不変性 • 実装の隠蔽 • ドキュメントとしてのコード • 遅延評価 • 並列化
  42. 42. がもたらされる ことを他の人が 次回以降に説明 してくれます
  43. 43. 2. ラムダ式を 書く
  44. 44. 2. ラムダ式を書く • 何をラムダ式で書けるのか • どのようにラムダ式を書けるのか • いつラムダ式を書くべきか • ラムダ式さえ書かなくてもよいと きもある
  45. 45. 2. ラムダ式を書く • 何をラムダ式で書けるのか • どのようにラムダ式を書けるのか • いつラムダ式を書くべきか • ラムダ式さえ書かなくてもよいと きもある
  46. 46. Q : 何をラムダ式で 書けるのか
  47. 47. A : 関数型インタ フェースをラム ダ式で置き換え ることができる
  48. 48. 関数型インタフェース • 実装が必要なメソッドを一つだけ 持つインタフェース • 実装が必要なメソッド? → 未実装の abstract メソッド • 唯一の abstract メソッド以外に、 static メソッドや default メソッ ドが定義されている場合もある
  49. 49. 関数型インタフェースの例 • ~ JDK 7 • Runnable • Callable • Comparator • JDK 8 ~ • Predicate • Consumer • Supplier
  50. 50. 関数型インタフェースの例 • ~ JDK 7 • Runnable • Callable • Comparator • JDK 8 ~ • Predicate • Consumer • Supplier
  51. 51. JDK 7 までの Comparator public interface Comparator<T> { int compare(T o1, T o2); boolean equals(Object obj); }
  52. 52. JDK 8 の Comparator @FunctionalInterface public interface Comparator<T> { int compare(T o1, T o2); boolean equals(Object obj); default Comparator<T> reversed() { return Collections.reverseOrder(this); } ... (6 default methods) public static <T extends Comparable<? super T>> Comparator<T> reverseOrder() { return Collections.reverseOrder(); } ... (8 static methods) }
  53. 53. JDK 8 の Comparator @FunctionalInterface public interface Comparator<T> { int compare(T o1, T o2); boolean equals(Object obj); default Comparator<T> reversed() { return Collections.reverseOrder(this); } ... (6 default methods) public static <T extends Comparable<? super T>> Comparator<T> reverseOrder() { return Collections.reverseOrder(); } ... (8 static methods) }
  54. 54. JDK 8 の Comparator @FunctionalInterface public interface Comparator<T> { int compare(T o1, T o2); boolean equals(Object obj); default Comparator<T> reversed() { return Collections.reverseOrder(this); } ... (6 default methods) public static <T extends Comparable<? super T>> Comparator<T> reverseOrder() { return Collections.reverseOrder(); } ... (8 static methods) }
  55. 55. JDK 8 の Comparator @FunctionalInterface public interface Comparator<T> { int compare(T o1, T o2); boolean equals(Object obj); default Comparator<T> reversed() { return Collections.reverseOrder(this); } ... (6 default methods) public static <T extends Comparable<? super T>> Comparator<T> reverseOrder() { return Collections.reverseOrder(); } ... (8 static methods) }
  56. 56. JDK 8 の Comparator @FunctionalInterface public interface Comparator<T> { int compare(T o1, T o2); boolean equals(Object obj); default Comparator<T> reversed() { return Collections.reverseOrder(this); } ... (6 default methods) public static <T extends Comparable<? super T>> Comparator<T> reverseOrder() { return Collections.reverseOrder(); } ... (8 static methods) }
  57. 57. JDK 8 の Comparator @FunctionalInterface public interface Comparator<T> { int compare(T o1, T o2); boolean equals(Object obj); default Comparator<T> reversed() { return Collections.reverseOrder(this); } ... (6 default methods) public static <T extends Comparable<? super T>> Comparator<T> reverseOrder() { return Collections.reverseOrder(); } ... (8 static methods) }
  58. 58. @FunctionalInterface • 関数型インタフェースにつけるこ とができるアノテーション • つけなくてもよい • つけるとコンパイラが関数型イ ンタフェースかどうかチェック してくれる • 人間の目にもやさしい
  59. 59. デフォルトメソッド • インタフェースに実装を定義でき る記法 • default キーワードを記述 • 後方互換性を保ちながらインタ フェースを拡張するために導入 された • 詳細は次回……。
  60. 60. 2. ラムダ式を書く • 何をラムダ式で書けるのか • どのようにラムダ式を書けるのか • いつラムダ式を書くべきか • ラムダ式さえ書かなくてもよいと きもある
  61. 61. Q : どのように ラムダ式を 書けるのか
  62. 62. A : 次のように
  63. 63. ラムダ式の記法 • ( 実装するメソッドの引数 ) -> { 処理 } • 例 : Comparator<Integer> の場合 int compare(Integer o1, Integer o2) に対して (Integer o1, Integer o2) -> { return o1 – o2 }
  64. 64. ラムダ式の記法 • ( 実装するメソッドの引数 ) -> { 処理 } • 例 : Comparator<Integer> の場合 int compare(Integer o1, Integer o2) に対して (Integer o1, Integer o2) -> { return o1 – o2 }
  65. 65. ラムダ式の記法 • ( 実装するメソッドの引数 ) -> { 処理 } • 例 : Comparator<Integer> の場合 int compare(Integer o1, Integer o2) に対して (Integer o1, Integer o2) -> { return o1 – o2; }
  66. 66. ここから色々と 省略できる
  67. 67. ラムダ式の記法 (省略前) • ( 実装するメソッドの引数 ) -> { 処理 } • 例 : Comparator<Integer> の場合 int compare(Integer o1, Integer o2) に対して (Integer o1, Integer o2) -> { return o1 – o2; }
  68. 68. ラムダ式の記法 (省略 1) • 型推論 • 例 : Comparator の場合 int compare(Integer o1, Integer o2) に対して (Integer o1, Integer o2) -> { return o1 – o2; }
  69. 69. ラムダ式の記法 (省略 1) • 型推論 • 例 : Comparator<Integer> の場合 int compare(Integer o1, Integer o2) に対して (o1, o2) -> { return o1 – o2; }
  70. 70. ラムダ式の記法 (省略 2) • 波括弧(「{}」)と return の省略 • 例 : Comparator<Integer> の場合 int compare(Integer o1, Integer o2) に対して (o1, o2) -> { return o1 – o2; }
  71. 71. ラムダ式の記法 (省略 2) • 波括弧(「{}」)と return の省略 • 例 : Comparator<Integer> の場合 int compare(Integer o1, Integer o2) に対して (o1, o2) -> o1 – o2
  72. 72. ラムダ式の記法 (省略 3) • 丸括弧(「()」)の省略 • 丸括弧が省略できるのは、メソッドの引数 が 1 つだけの場合
  73. 73. ラムダ式の記法 (省略 3) • 丸括弧(「()」)の省略前 • 例 : Predicate<Integer> の場合 boolean test(Integer t) に対して (Integer t) -> { return (t > 100); }
  74. 74. ラムダ式の記法 (省略 3) • 丸括弧(「()」)の省略後 • 例 : Predicate<Integer> の場合 boolean test(Integer t) に対して (Integer t) -> { return (t > 100); }
  75. 75. ラムダ式の記法 (省略 3) • 丸括弧(「()」)の省略後 • 例 : Predicate<Integer> の場合 boolean test(Integer t) に対して t -> { return (t > 100); }
  76. 76. ラムダ式の記法 (省略 3) • さらに省略すると • 例 : Predicate<Integer> の場合 boolean test(Integer t) に対して t -> { return (t > 100); }
  77. 77. ラムダ式の記法 (省略 3) • さらに省略すると • 例 : Predicate<Integer> の場合 boolean test(Integer t) に対して t -> t > 100
  78. 78. ラムダ式の記法 (引数なし) • メソッドに引数がない場合 丸括弧のみ記述する
  79. 79. ラムダ式の記法 (引数なし) • メソッドに引数がない場合 丸括弧のみ記述する • 例 : Callable<Integer> の場合 Integer call() に対して () -> { return 100; }
  80. 80. ラムダ式の記法 (引数なし) • メソッドに引数がない場合 丸括弧のみ記述する • 例 : Callable<Integer> の場合 Integer call() に対して () -> { return 100; }
  81. 81. ラムダ式の記法 (実質的に final) • 実質的に final • 匿名クラスでは、メソッド内で参照 するローカル変数には final キー ワードが必要 • ラムダ式では、その変数について final と同等に扱っていれば、final キーワードは不要
  82. 82. ラムダ式の記法 (this が表すもの) • http://www.atmarkit.co.jp/ait/ articles/1403/17/news105_2.h tml • (手抜きでスミマセン……)
  83. 83. 2. ラムダ式を書く • 何をラムダ式で書けるのか • どのようにラムダ式を書けるのか • いつラムダ式を書くべきか • ラムダ式さえ書かなくてもよいと きもある
  84. 84. Q : いつラムダ式を 書くべきか
  85. 85. A : 書けるところ ならどこでも
  86. 86. 書けるところなら どこでもラムダ式を書く • ラムダ式は関数型インタフェースの略 記法にすぎない • むずかしくない • こわくない • ラムダ式はノイズを減らして本質を残 す • 簡潔で読みやすいコードをつくる
  87. 87. と思っていますが、 プロダクション コードで色々と書 くにつれて合わな い場面が出てくる かもしれません
  88. 88. たとえば、ラムダ式の 意味をよく知っている (今のみなさん)にも かかわらず、なぜか読 みづらい、という場面 があるかも……?
  89. 89. そういうときは コードレビュー等 を通して適宜共有 していきましょう
  90. 90. 2. ラムダ式を書く • 何をラムダ式で書けるのか • どのようにラムダ式を書けるのか • いつラムダ式を書くべきか • ラムダ式さえ書かなくてもよいと きもある
  91. 91. ラムダ式さえ書かなくて もよいときもある • メソッド参照 • ざっくり言うとこう書ける仕組み • Before : name -> System.out.println(name) • After : System.out.println • のちほどもうちょっと説明します
  92. 92. 3. forEach による イテレーション
  93. 93. forEach による イテレーション • ラムダ式の活用例 • イテレーションが高級になっていく歴 史 • for (int i = 0; i < list.size(); i++) • for (String s : list) • list.forEach()
  94. 94. forEach による イテレーション • ラムダ式の活用例 • イテレーションが高級になっていく歴 史の第三段階 • for (int i = 0; i < list.size(); i++) • for (String s : list) • list.forEach()
  95. 95. 原始 for 文 final List<String> members = Arrays.asList(“Ohshima”, “Hirose”, “Nancii”, “Tanaka”, “Chen”, “Takano”); for (int i = 0; i < members.size(); i++) { System.out.println(members.get(i)); }
  96. 96. 原始 for 文 final List<String> members = Arrays.asList(“Ohshima”, “Hirose”, “Nancii”, “Tanaka”, “Chen”, “Takano”); for (int i = 0; i < members.size(); i++) { System.out.println(members.get(i)); } • ノイズが多い • OBOE や変数の取り違えが 起こりかねない
  97. 97. 拡張 for 文(Java 5~) final List<String> members = Arrays.asList(“Ohshima”, “Hirose”, “Nancii”, “Tanaka”, “Chen”, “Takano”); for (String member : members) { System.out.println(member); }
  98. 98. 拡張 for 文(Java 5~) final List<String> members = Arrays.asList(“Ohshima”, “Hirose”, “Nancii”, “Tanaka”, “Chen”, “Takano”); for (String member : members) { System.out.println(member); } • もう OBOE は起こらない • が、まだ冗長だ……。
  99. 99. forEach(Java 8~) final List<String> members = Arrays.asList(“Ohshima”, “Hirose”, “Nancii”, “Tanaka”, “Chen”, “Takano”); Members.forEach(new Consumer<String>() { public void accept(final String name) { System.out.println(name); } });
  100. 100. forEach(Java 8~) final List<String> members = Arrays.asList(“Ohshima”, “Hirose”, “Nancii”, “Tanaka”, “Chen”, “Takano”); members.forEach(new Consumer<String>() { public void accept(final String name) { System.out.println(name); } }); • ウッけっこうノイズが多いような ……
  101. 101. forEach(Java 8~) final List<String> members = Arrays.asList(“Ohshima”, “Hirose”, “Nancii”, “Tanaka”, “Chen”, “Takano”); members.forEach(new Consumer<String>() { public void accept(final String name) { System.out.println(name); } }); • そんなときのためのラムダ式 • 1
  102. 102. forEach(Java 8~) final List<String> members = Arrays.asList(“Ohshima”, “Hirose”, “Nancii”, “Tanaka”, “Chen”, “Takano”); members.forEach( (final String name) -> System.out.println(name)); • そんなときのためのラムダ式 • 1
  103. 103. forEach(Java 8~) final List<String> members = Arrays.asList(“Ohshima”, “Hirose”, “Nancii”, “Tanaka”, “Chen”, “Takano”); members.forEach( (final String name) -> System.out.println(name)); • そんなときのためのラムダ式 • 2
  104. 104. forEach(Java 8~) final List<String> members = Arrays.asList(“Ohshima”, “Hirose”, “Nancii”, “Tanaka”, “Chen”, “Takano”); members.forEach( name -> System.out.println(name)); • そんなときのためのラムダ式 • 2
  105. 105. forEach(Java 8~) final List<String> members = Arrays.asList(“Ohshima”, “Hirose”, “Nancii”, “Tanaka”, “Chen”, “Takano”); members.forEach( name -> System.out.println(name)); • そんなときのためのラムダ式 • さえいらない(メソッド参照)
  106. 106. forEach(Java 8~) final List<String> members = Arrays.asList(“Ohshima”, “Hirose”, “Nancii”, “Tanaka”, “Chen”, “Takano”); members.forEach(System.out.println); • そんなときのためのラムダ式 • さえいらない(メソッド参照)
  107. 107. forEach(Java 8~) final List<String> members = Arrays.asList(“Ohshima”, “Hirose”, “Nancii”, “Tanaka”, “Chen”, “Takano”); members.forEach(System.out.println); • そんなときのためのラムダ式 • さえいらない(メソッド参照) メンバーを それぞれ 標準出力に出す
  108. 108. メソッド参照 • http://www.atmarkit.co.jp/ait/ articles/1407/28/news023_3.h tml • (例によって手抜きでスミマセン ……)
  109. 109. まずは forEach の 例を紹介しましたが、 Stream API と組 み合わせるとこのラ ムダ式の簡潔さが大 活躍します
  110. 110. 次回以降を 乞うご期待
  111. 111. 白状すると
  112. 112. DataSpider の中 にこの forEach で 置き換えられる コードがなかなか 見つかりません
  113. 113. たとえばこれがい けるかな…… と思ったのですが
  114. 114. List<CellToWrite[]> rows = Arrays.asList(new CellToWrite[][] { new CellToWrite[neededColumnsCount] }); for (IntermediateCellData cell : data) { int row = cell.rowIndex - minRow; int column = cell.columnIndex - minColumn; rows.get(row)[column] = new CellToWrite( cell.address, cell.column, createWriteOption(cell)); }
  115. 115. List<CellToWrite[]> rows = Arrays.asList(new CellToWrite[][] { new CellToWrite[neededColumnsCount] }); data.forEach(cell -> { int row = cell.rowIndex - minRow; int column = cell.columnIndex - minColumn; rows.get(row)[column] = new CellToWrite( cell.address, cell.column, createWriteOption(cell)); }); • これだけだと 大して簡潔にならないし、しかも
  116. 116. List<CellToWrite[]> rows = Arrays.asList(new CellToWrite[][] { new CellToWrite[neededColumnsCount] }); data.forEach(cell -> { int row = cell.rowIndex - minRow; int column = cell.columnIndex - minColumn; rows.get(row)[column] = new CellToWrite( cell.address, cell.column, createWriteOption(cell)); }); • 言うほど読みやすくならない • ていうかコンパイルエラー処理されない例外の型 Exception
  117. 117. List<CellToWrite[]> rows = Arrays.asList(new CellToWrite[][] { new CellToWrite[neededColumnsCount] }); data.forEach(cell -> { int row = cell.rowIndex - minRow; int column = cell.columnIndex - minColumn; rows.get(row)[column] = new CellToWrite( cell.address, cell.column, createWriteOption(cell)); }); • 言うほど読みやすくならない • ていうかコンパイルエラー 処理されない例外の型 Exception Iterable#forEach(Consumer<? super T> action) @FunctionalInterface public interface Consumer<T> { void accept(T t); } public CellToWrite( String position, Column column, Excel2007WriteOption option) throws Exception {
  118. 118. List<CellToWrite[]> rows = Arrays.asList(new CellToWrite[][] { new CellToWrite[neededColumnsCount] }); data.forEach(cell -> { int row = cell.rowIndex - minRow; int column = cell.columnIndex - minColumn; try { rows.get(row)[column] = new CellToWrite( cell.address, cell.column, createWriteOption(cell)); } catch (Exception e) { throw new RuntimeException(e); } });
  119. 119. モサすぎる
  120. 120. (注意) これはラムダ式固有の問題というわけではなく、あ くまで forEach と関数型インタフェース周辺の問 題です。ただし、Stream API(と関数型インタ フェース)を使用する際にもこの問題は頻出すると 思われます
  121. 121. 関数型のコードと 親和性の高い設計 や API 設計に少し ずつ寄せていく努 力が必要になりそ うです
  122. 122. (XML Framework と Stream API との 可能性も含めた親 和性が気になると ころ……)
  123. 123. 次回以降が 楽しみです

×