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

124
Java 8 勉強会 第一回 ラムダ式 (1) 2015/3/2 開発部 3G 野口光太郎

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

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

Java 8 勉強会 第一回 ラムダ式 (1) 2015/3/2

開発部 3G 野口光太郎

Page 2: 20150302 java8 第一回_ラムダ式(1)
Page 3: 20150302 java8 第一回_ラムダ式(1)

ついに Java 8 が使える

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

Java 8 導入予定 • Thunderbus

• 1.0 で導入済(8u31)

• PIMSYNC

• 2.2 で導入予定

• DataSpider Servista

• 4.0 で導入予定

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

Java 8 の新機能 • ラムダ式

• Stream API

• Date and Time API

• JavaFX 8

• etc…

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

Java 8 の新機能 • ラムダ式

• Stream API

• Date and Time API

• JavaFX 8

• etc…

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

ついに ラムダ式 が使える

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

Java 8 勉強会 第一回 ラムダ式 (1) 2015/3/2

開発部 3G 野口光太郎

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

アジェンダ 1. ラムダ式は何が違うのか

2. ラムダ式を書く

3. forEach によるイテレーション

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

1. ラムダ式は 何が 違うのか

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

ラムダ式とは

• 匿名関数の簡略な記法

• Java 8(2014/3)で導入

• 取り立てて新しい概念ではない

• C++11(2011 年)

• C# 3.0(2008 年)

• Lisp(ざっと 50 年くらい前)

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

ラムダ式とは

• 匿名関数の簡略な記法

• Java 8(2014/3)で導入

• 取り立てて新しい概念ではない

• C++11(2011 年)

• C# 3.0(2008 年)

• Lisp(ざっと 50 年くらい前)

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

匿名関数の 簡略な記法 ……?

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

匿名関数とは

• 匿名の関数

• 要するにこれのこと

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; } });

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

匿名関数の簡略な記法

• こう書ける

List numbers = Arrays.asList(1, 1, 2, 3, 5); Collections.sort(numbers, (i1, i2) -> i2 - i1);

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

で?

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

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()); } } ); }

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

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()); } } ); }

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

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

テストの内容にとっては全部どうでもいい

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

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()); } } ); }

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

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()); } } ); } • こう書ける

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

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)

(匿名関数) • こう書ける

• メソッドに関数を直接渡せる

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

(注意) 実際に過去に書いたコードの中からノイズが減って嬉しい例としてたまたまこれを思い出したので挙げましたが、関数型のスタイルという観点では、そもそもあまり長いラムダ式は推奨されない、という考え方もあるようです。 あとそもそもアサーションの仕方がダサいとかは今はツッコまない方向で……。

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

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(); } }); }

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

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

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

@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

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

@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

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

@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

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

@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

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

@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

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

22 テストケース

6 ページ

247 行

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

• こう書ける @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

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

@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

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

@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

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

22 テストケース

3 ページ

107 行

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

テストケース数 : 22 → 22 (100%) ページ数 : 6 → 3 (50%) 行数 : 247→107 (43%)

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

嬉しい • ノイズの減少

• 本質的なコードだけが残る

• 一覧性の向上

• たとえばテストがスペックに近づく

• 気がする

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

Q: ラムダ式は 何が 違うのか

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

A: 匿名関数が 簡略に書けて 嬉しい

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

それだけ?

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

そうだけど、 (全然むずかしくない)

そうではない。 (文字数が減るとか、 それだけではない)

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

開かれる 関数型スタイルへの道

• 私たちが愛する

• 不変性

• 実装の隠蔽

• ドキュメントとしてのコード

• 遅延評価

• 並列化

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

がもたらされることを他の人が次回以降に説明してくれます

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

2. ラムダ式を 書く

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

2. ラムダ式を書く • 何をラムダ式で書けるのか

• どのようにラムダ式を書けるのか

• いつラムダ式を書くべきか

• ラムダ式さえ書かなくてもよいときもある

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

2. ラムダ式を書く • 何をラムダ式で書けるのか

• どのようにラムダ式を書けるのか

• いつラムダ式を書くべきか

• ラムダ式さえ書かなくてもよいときもある

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

Q : 何をラムダ式で 書けるのか

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

A : 関数型インタフェースをラムダ式で置き換えることができる

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

関数型インタフェース

• 実装が必要なメソッドを一つだけ持つインタフェース

• 実装が必要なメソッド? → 未実装の abstract メソッド

• 唯一の abstract メソッド以外に、static メソッドや default メソッドが定義されている場合もある

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

関数型インタフェースの例

• ~ JDK 7

• Runnable

• Callable

• Comparator

• JDK 8 ~

• Predicate

• Consumer

• Supplier

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

関数型インタフェースの例

• ~ JDK 7

• Runnable

• Callable

• Comparator

• JDK 8 ~

• Predicate

• Consumer

• Supplier

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

JDK 7 までの Comparator

public interface Comparator<T> { int compare(T o1, T o2); boolean equals(Object obj); }

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

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) }

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

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) }

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

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) }

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

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) }

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

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) }

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

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) }

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

@FunctionalInterface

• 関数型インタフェースにつけることができるアノテーション

• つけなくてもよい

• つけるとコンパイラが関数型インタフェースかどうかチェックしてくれる

• 人間の目にもやさしい

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

デフォルトメソッド

• インタフェースに実装を定義できる記法

• default キーワードを記述

• 後方互換性を保ちながらインタフェースを拡張するために導入された

• 詳細は次回……。

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

2. ラムダ式を書く • 何をラムダ式で書けるのか

• どのようにラムダ式を書けるのか

• いつラムダ式を書くべきか

• ラムダ式さえ書かなくてもよいときもある

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

Q : どのように ラムダ式を 書けるのか

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

A : 次のように

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

ラムダ式の記法

• ( 実装するメソッドの引数 ) -> { 処理 }

• 例 : Comparator<Integer> の場合 int compare(Integer o1, Integer o2) に対して

(Integer o1, Integer o2) -> { return o1 – o2 }

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

ラムダ式の記法

• ( 実装するメソッドの引数 ) -> { 処理 }

• 例 : Comparator<Integer> の場合 int compare(Integer o1, Integer o2) に対して

(Integer o1, Integer o2) -> { return o1 – o2 }

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

ラムダ式の記法

• ( 実装するメソッドの引数 ) -> { 処理 }

• 例 : Comparator<Integer> の場合 int compare(Integer o1, Integer o2) に対して

(Integer o1, Integer o2) -> { return o1 – o2; }

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

ここから色々と省略できる

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

ラムダ式の記法 (省略前)

• ( 実装するメソッドの引数 ) -> { 処理 }

• 例 : Comparator<Integer> の場合 int compare(Integer o1, Integer o2) に対して

(Integer o1, Integer o2) -> { return o1 – o2; }

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

ラムダ式の記法 (省略 1)

• 型推論

• 例 : Comparator の場合 int compare(Integer o1, Integer o2) に対して

(Integer o1, Integer o2) -> { return o1 – o2; }

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

ラムダ式の記法 (省略 1)

• 型推論

• 例 : Comparator<Integer> の場合 int compare(Integer o1, Integer o2) に対して

(o1, o2) -> { return o1 – o2; }

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

ラムダ式の記法 (省略 2)

• 波括弧(「{}」)と return の省略

• 例 : Comparator<Integer> の場合 int compare(Integer o1, Integer o2) に対して

(o1, o2) -> { return o1 – o2; }

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

ラムダ式の記法 (省略 2)

• 波括弧(「{}」)と return の省略

• 例 : Comparator<Integer> の場合 int compare(Integer o1, Integer o2) に対して

(o1, o2) -> o1 – o2

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

ラムダ式の記法 (省略 3)

• 丸括弧(「()」)の省略

• 丸括弧が省略できるのは、メソッドの引数が 1 つだけの場合

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

ラムダ式の記法 (省略 3)

• 丸括弧(「()」)の省略前

• 例 : Predicate<Integer> の場合 boolean test(Integer t) に対して

(Integer t) -> { return (t > 100); }

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

ラムダ式の記法 (省略 3)

• 丸括弧(「()」)の省略後

• 例 : Predicate<Integer> の場合 boolean test(Integer t) に対して

(Integer t) -> { return (t > 100); }

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

ラムダ式の記法 (省略 3)

• 丸括弧(「()」)の省略後

• 例 : Predicate<Integer> の場合 boolean test(Integer t) に対して

t -> { return (t > 100); }

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

ラムダ式の記法 (省略 3)

• さらに省略すると

• 例 : Predicate<Integer> の場合 boolean test(Integer t) に対して

t -> { return (t > 100); }

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

ラムダ式の記法 (省略 3)

• さらに省略すると

• 例 : Predicate<Integer> の場合 boolean test(Integer t) に対して

t -> t > 100

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

ラムダ式の記法 (引数なし)

• メソッドに引数がない場合 丸括弧のみ記述する

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

ラムダ式の記法 (引数なし)

• メソッドに引数がない場合 丸括弧のみ記述する

• 例 : Callable<Integer> の場合 Integer call() に対して

() -> { return 100; }

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

ラムダ式の記法 (引数なし)

• メソッドに引数がない場合 丸括弧のみ記述する

• 例 : Callable<Integer> の場合 Integer call() に対して

() -> { return 100; }

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

ラムダ式の記法 (実質的に final)

• 実質的に final

• 匿名クラスでは、メソッド内で参照するローカル変数には final キーワードが必要

• ラムダ式では、その変数について final と同等に扱っていれば、final キーワードは不要

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

ラムダ式の記法 (this が表すもの)

• http://www.atmarkit.co.jp/ait/articles/1403/17/news105_2.html

• (手抜きでスミマセン……)

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

2. ラムダ式を書く • 何をラムダ式で書けるのか

• どのようにラムダ式を書けるのか

• いつラムダ式を書くべきか

• ラムダ式さえ書かなくてもよいときもある

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

Q : いつラムダ式を 書くべきか

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

A : 書けるところ ならどこでも

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

書けるところなら どこでもラムダ式を書く

• ラムダ式は関数型インタフェースの略記法にすぎない

• むずかしくない

• こわくない

• ラムダ式はノイズを減らして本質を残す

• 簡潔で読みやすいコードをつくる

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

と思っていますが、プロダクションコードで色々と書くにつれて合わない場面が出てくるかもしれません

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

たとえば、ラムダ式の意味をよく知っている(今のみなさん)にもかかわらず、なぜか読みづらい、という場面があるかも……?

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

そういうときはコードレビュー等を通して適宜共有していきましょう

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

2. ラムダ式を書く • 何をラムダ式で書けるのか

• どのようにラムダ式を書けるのか

• いつラムダ式を書くべきか

• ラムダ式さえ書かなくてもよいときもある

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

ラムダ式さえ書かなくてもよいときもある

• メソッド参照

• ざっくり言うとこう書ける仕組み

• Before : name -> System.out.println(name)

• After : System.out.println

• のちほどもうちょっと説明します

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

3. forEach による イテレーション

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

forEach による イテレーション

• ラムダ式の活用例

• イテレーションが高級になっていく歴史

• for (int i = 0; i < list.size(); i++)

• for (String s : list)

• list.forEach()

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

forEach による イテレーション

• ラムダ式の活用例

• イテレーションが高級になっていく歴史の第三段階

• for (int i = 0; i < list.size(); i++)

• for (String s : list)

• list.forEach()

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

原始 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)); }

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

原始 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 や変数の取り違えが起こりかねない

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

拡張 for 文(Java 5~) final List<String> members = Arrays.asList(“Ohshima”, “Hirose”, “Nancii”, “Tanaka”, “Chen”, “Takano”); for (String member : members) { System.out.println(member); }

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

拡張 for 文(Java 5~) final List<String> members = Arrays.asList(“Ohshima”, “Hirose”, “Nancii”, “Tanaka”, “Chen”, “Takano”); for (String member : members) { System.out.println(member); }

• もう OBOE は起こらない

• が、まだ冗長だ……。

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

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); } });

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

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); } });

• ウッけっこうノイズが多いような……

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

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

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

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

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

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

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

forEach(Java 8~) final List<String> members = Arrays.asList(“Ohshima”, “Hirose”, “Nancii”, “Tanaka”, “Chen”, “Takano”); members.forEach( name -> System.out.println(name));

• そんなときのためのラムダ式

• 2

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

forEach(Java 8~) final List<String> members = Arrays.asList(“Ohshima”, “Hirose”, “Nancii”, “Tanaka”, “Chen”, “Takano”); members.forEach( name -> System.out.println(name));

• そんなときのためのラムダ式

• さえいらない(メソッド参照)

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

forEach(Java 8~) final List<String> members = Arrays.asList(“Ohshima”, “Hirose”, “Nancii”, “Tanaka”, “Chen”, “Takano”); members.forEach(System.out.println);

• そんなときのためのラムダ式

• さえいらない(メソッド参照)

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

forEach(Java 8~) final List<String> members = Arrays.asList(“Ohshima”, “Hirose”, “Nancii”, “Tanaka”, “Chen”, “Takano”); members.forEach(System.out.println);

• そんなときのためのラムダ式

• さえいらない(メソッド参照)

メンバーを それぞれ 標準出力に出す

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

まずは forEach の例を紹介しましたが、Stream API と組み合わせるとこのラムダ式の簡潔さが大活躍します

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

次回以降を 乞うご期待

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

白状すると

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

DataSpider の中にこの forEach で置き換えられるコードがなかなか見つかりません

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

たとえばこれがいけるかな…… と思ったのですが

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

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)); }

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

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)); });

• これだけだと 大して簡潔にならないし、しかも

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

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

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

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 {

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

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); } });

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

モサすぎる

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

(注意) これはラムダ式固有の問題というわけではなく、あくまで forEach と関数型インタフェース周辺の問題です。ただし、Stream API(と関数型インタフェース)を使用する際にもこの問題は頻出すると思われます

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

関数型のコードと親和性の高い設計や API 設計に少しずつ寄せていく努力が必要になりそうです

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

(XML Framework と Stream API との可能性も含めた親和性が気になるところ……)

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

次回以降が 楽しみです