20150302 java8 第一回_ラムダ式(1)
-
Upload
appresso-engineering-team -
Category
Engineering
-
view
219 -
download
0
Transcript of 20150302 java8 第一回_ラムダ式(1)
Java 8 勉強会 第一回 ラムダ式 (1) 2015/3/2
開発部 3G 野口光太郎
ついに Java 8 が使える
Java 8 導入予定 • Thunderbus
• 1.0 で導入済(8u31)
• PIMSYNC
• 2.2 で導入予定
• DataSpider Servista
• 4.0 で導入予定
Java 8 の新機能 • ラムダ式
• Stream API
• Date and Time API
• JavaFX 8
• etc…
Java 8 の新機能 • ラムダ式
• Stream API
• Date and Time API
• JavaFX 8
• etc…
ついに ラムダ式 が使える
Java 8 勉強会 第一回 ラムダ式 (1) 2015/3/2
開発部 3G 野口光太郎
アジェンダ 1. ラムダ式は何が違うのか
2. ラムダ式を書く
3. forEach によるイテレーション
1. ラムダ式は 何が 違うのか
ラムダ式とは
• 匿名関数の簡略な記法
• Java 8(2014/3)で導入
• 取り立てて新しい概念ではない
• C++11(2011 年)
• C# 3.0(2008 年)
• Lisp(ざっと 50 年くらい前)
ラムダ式とは
• 匿名関数の簡略な記法
• Java 8(2014/3)で導入
• 取り立てて新しい概念ではない
• C++11(2011 年)
• C# 3.0(2008 年)
• Lisp(ざっと 50 年くらい前)
匿名関数の 簡略な記法 ……?
匿名関数とは
• 匿名の関数
• 要するにこれのこと
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; } });
匿名関数の簡略な記法
• こう書ける
List numbers = Arrays.asList(1, 1, 2, 3, 5); Collections.sort(numbers, (i1, i2) -> i2 - i1);
で?
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()); } } ); }
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()); } } ); }
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
テストの内容にとっては全部どうでもいい
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()); } } ); }
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 アダプタのテストコードの例(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)
(匿名関数) • こう書ける
• メソッドに関数を直接渡せる
(注意) 実際に過去に書いたコードの中からノイズが減って嬉しい例としてたまたまこれを思い出したので挙げましたが、関数型のスタイルという観点では、そもそもあまり長いラムダ式は推奨されない、という考え方もあるようです。 あとそもそもアサーションの仕方がダサいとかは今はツッコまない方向で……。
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(); } }); }
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
@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
@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
@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
@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
@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
22 テストケース
6 ページ
247 行
• こう書ける @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
@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
@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
22 テストケース
3 ページ
107 行
テストケース数 : 22 → 22 (100%) ページ数 : 6 → 3 (50%) 行数 : 247→107 (43%)
嬉しい • ノイズの減少
• 本質的なコードだけが残る
• 一覧性の向上
• たとえばテストがスペックに近づく
• 気がする
Q: ラムダ式は 何が 違うのか
A: 匿名関数が 簡略に書けて 嬉しい
それだけ?
そうだけど、 (全然むずかしくない)
そうではない。 (文字数が減るとか、 それだけではない)
開かれる 関数型スタイルへの道
• 私たちが愛する
• 不変性
• 実装の隠蔽
• ドキュメントとしてのコード
• 遅延評価
• 並列化
がもたらされることを他の人が次回以降に説明してくれます
2. ラムダ式を 書く
2. ラムダ式を書く • 何をラムダ式で書けるのか
• どのようにラムダ式を書けるのか
• いつラムダ式を書くべきか
• ラムダ式さえ書かなくてもよいときもある
2. ラムダ式を書く • 何をラムダ式で書けるのか
• どのようにラムダ式を書けるのか
• いつラムダ式を書くべきか
• ラムダ式さえ書かなくてもよいときもある
Q : 何をラムダ式で 書けるのか
A : 関数型インタフェースをラムダ式で置き換えることができる
関数型インタフェース
• 実装が必要なメソッドを一つだけ持つインタフェース
• 実装が必要なメソッド? → 未実装の abstract メソッド
• 唯一の abstract メソッド以外に、static メソッドや default メソッドが定義されている場合もある
関数型インタフェースの例
• ~ JDK 7
• Runnable
• Callable
• Comparator
• JDK 8 ~
• Predicate
• Consumer
• Supplier
関数型インタフェースの例
• ~ JDK 7
• Runnable
• Callable
• Comparator
• JDK 8 ~
• Predicate
• Consumer
• Supplier
JDK 7 までの Comparator
public interface Comparator<T> { int compare(T o1, T o2); boolean equals(Object obj); }
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) }
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) }
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) }
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) }
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) }
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) }
@FunctionalInterface
• 関数型インタフェースにつけることができるアノテーション
• つけなくてもよい
• つけるとコンパイラが関数型インタフェースかどうかチェックしてくれる
• 人間の目にもやさしい
デフォルトメソッド
• インタフェースに実装を定義できる記法
• default キーワードを記述
• 後方互換性を保ちながらインタフェースを拡張するために導入された
• 詳細は次回……。
2. ラムダ式を書く • 何をラムダ式で書けるのか
• どのようにラムダ式を書けるのか
• いつラムダ式を書くべきか
• ラムダ式さえ書かなくてもよいときもある
Q : どのように ラムダ式を 書けるのか
A : 次のように
ラムダ式の記法
• ( 実装するメソッドの引数 ) -> { 処理 }
• 例 : Comparator<Integer> の場合 int compare(Integer o1, Integer o2) に対して
(Integer o1, Integer o2) -> { return o1 – o2 }
ラムダ式の記法
• ( 実装するメソッドの引数 ) -> { 処理 }
• 例 : Comparator<Integer> の場合 int compare(Integer o1, Integer o2) に対して
(Integer o1, Integer o2) -> { return o1 – o2 }
ラムダ式の記法
• ( 実装するメソッドの引数 ) -> { 処理 }
• 例 : Comparator<Integer> の場合 int compare(Integer o1, Integer o2) に対して
(Integer o1, Integer o2) -> { return o1 – o2; }
ここから色々と省略できる
ラムダ式の記法 (省略前)
• ( 実装するメソッドの引数 ) -> { 処理 }
• 例 : Comparator<Integer> の場合 int compare(Integer o1, Integer o2) に対して
(Integer o1, Integer o2) -> { return o1 – o2; }
ラムダ式の記法 (省略 1)
• 型推論
• 例 : Comparator の場合 int compare(Integer o1, Integer o2) に対して
(Integer o1, Integer o2) -> { return o1 – o2; }
ラムダ式の記法 (省略 1)
• 型推論
• 例 : Comparator<Integer> の場合 int compare(Integer o1, Integer o2) に対して
(o1, o2) -> { return o1 – o2; }
ラムダ式の記法 (省略 2)
• 波括弧(「{}」)と return の省略
• 例 : Comparator<Integer> の場合 int compare(Integer o1, Integer o2) に対して
(o1, o2) -> { return o1 – o2; }
ラムダ式の記法 (省略 2)
• 波括弧(「{}」)と return の省略
• 例 : Comparator<Integer> の場合 int compare(Integer o1, Integer o2) に対して
(o1, o2) -> o1 – o2
ラムダ式の記法 (省略 3)
• 丸括弧(「()」)の省略
• 丸括弧が省略できるのは、メソッドの引数が 1 つだけの場合
ラムダ式の記法 (省略 3)
• 丸括弧(「()」)の省略前
• 例 : Predicate<Integer> の場合 boolean test(Integer t) に対して
(Integer t) -> { return (t > 100); }
ラムダ式の記法 (省略 3)
• 丸括弧(「()」)の省略後
• 例 : Predicate<Integer> の場合 boolean test(Integer t) に対して
(Integer t) -> { return (t > 100); }
ラムダ式の記法 (省略 3)
• 丸括弧(「()」)の省略後
• 例 : Predicate<Integer> の場合 boolean test(Integer t) に対して
t -> { return (t > 100); }
ラムダ式の記法 (省略 3)
• さらに省略すると
• 例 : Predicate<Integer> の場合 boolean test(Integer t) に対して
t -> { return (t > 100); }
ラムダ式の記法 (省略 3)
• さらに省略すると
• 例 : Predicate<Integer> の場合 boolean test(Integer t) に対して
t -> t > 100
ラムダ式の記法 (引数なし)
• メソッドに引数がない場合 丸括弧のみ記述する
ラムダ式の記法 (引数なし)
• メソッドに引数がない場合 丸括弧のみ記述する
• 例 : Callable<Integer> の場合 Integer call() に対して
() -> { return 100; }
ラムダ式の記法 (引数なし)
• メソッドに引数がない場合 丸括弧のみ記述する
• 例 : Callable<Integer> の場合 Integer call() に対して
() -> { return 100; }
ラムダ式の記法 (実質的に final)
• 実質的に final
• 匿名クラスでは、メソッド内で参照するローカル変数には final キーワードが必要
• ラムダ式では、その変数について final と同等に扱っていれば、final キーワードは不要
ラムダ式の記法 (this が表すもの)
• http://www.atmarkit.co.jp/ait/articles/1403/17/news105_2.html
• (手抜きでスミマセン……)
2. ラムダ式を書く • 何をラムダ式で書けるのか
• どのようにラムダ式を書けるのか
• いつラムダ式を書くべきか
• ラムダ式さえ書かなくてもよいときもある
Q : いつラムダ式を 書くべきか
A : 書けるところ ならどこでも
書けるところなら どこでもラムダ式を書く
• ラムダ式は関数型インタフェースの略記法にすぎない
• むずかしくない
• こわくない
• ラムダ式はノイズを減らして本質を残す
• 簡潔で読みやすいコードをつくる
と思っていますが、プロダクションコードで色々と書くにつれて合わない場面が出てくるかもしれません
たとえば、ラムダ式の意味をよく知っている(今のみなさん)にもかかわらず、なぜか読みづらい、という場面があるかも……?
そういうときはコードレビュー等を通して適宜共有していきましょう
2. ラムダ式を書く • 何をラムダ式で書けるのか
• どのようにラムダ式を書けるのか
• いつラムダ式を書くべきか
• ラムダ式さえ書かなくてもよいときもある
ラムダ式さえ書かなくてもよいときもある
• メソッド参照
• ざっくり言うとこう書ける仕組み
• Before : name -> System.out.println(name)
• After : System.out.println
• のちほどもうちょっと説明します
3. forEach による イテレーション
forEach による イテレーション
• ラムダ式の活用例
• イテレーションが高級になっていく歴史
• for (int i = 0; i < list.size(); i++)
• for (String s : list)
• list.forEach()
forEach による イテレーション
• ラムダ式の活用例
• イテレーションが高級になっていく歴史の第三段階
• for (int i = 0; i < list.size(); i++)
• for (String s : list)
• list.forEach()
原始 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)); }
原始 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 や変数の取り違えが起こりかねない
拡張 for 文(Java 5~) final List<String> members = Arrays.asList(“Ohshima”, “Hirose”, “Nancii”, “Tanaka”, “Chen”, “Takano”); for (String member : members) { System.out.println(member); }
拡張 for 文(Java 5~) final List<String> members = Arrays.asList(“Ohshima”, “Hirose”, “Nancii”, “Tanaka”, “Chen”, “Takano”); for (String member : members) { System.out.println(member); }
• もう OBOE は起こらない
• が、まだ冗長だ……。
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); } });
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); } });
• ウッけっこうノイズが多いような……
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
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
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
forEach(Java 8~) final List<String> members = Arrays.asList(“Ohshima”, “Hirose”, “Nancii”, “Tanaka”, “Chen”, “Takano”); members.forEach( name -> System.out.println(name));
• そんなときのためのラムダ式
• 2
forEach(Java 8~) final List<String> members = Arrays.asList(“Ohshima”, “Hirose”, “Nancii”, “Tanaka”, “Chen”, “Takano”); members.forEach( name -> System.out.println(name));
• そんなときのためのラムダ式
• さえいらない(メソッド参照)
forEach(Java 8~) final List<String> members = Arrays.asList(“Ohshima”, “Hirose”, “Nancii”, “Tanaka”, “Chen”, “Takano”); members.forEach(System.out.println);
• そんなときのためのラムダ式
• さえいらない(メソッド参照)
forEach(Java 8~) final List<String> members = Arrays.asList(“Ohshima”, “Hirose”, “Nancii”, “Tanaka”, “Chen”, “Takano”); members.forEach(System.out.println);
• そんなときのためのラムダ式
• さえいらない(メソッド参照)
メンバーを それぞれ 標準出力に出す
メソッド参照
• http://www.atmarkit.co.jp/ait/articles/1407/28/news023_3.html
• (例によって手抜きでスミマセン……)
まずは forEach の例を紹介しましたが、Stream API と組み合わせるとこのラムダ式の簡潔さが大活躍します
次回以降を 乞うご期待
白状すると
DataSpider の中にこの forEach で置き換えられるコードがなかなか見つかりません
たとえばこれがいけるかな…… と思ったのですが
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)); }
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)); });
• これだけだと 大して簡潔にならないし、しかも
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
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 {
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); } });
モサすぎる
(注意) これはラムダ式固有の問題というわけではなく、あくまで forEach と関数型インタフェース周辺の問題です。ただし、Stream API(と関数型インタフェース)を使用する際にもこの問題は頻出すると思われます
関数型のコードと親和性の高い設計や API 設計に少しずつ寄せていく努力が必要になりそうです
(XML Framework と Stream API との可能性も含めた親和性が気になるところ……)
次回以降が 楽しみです