ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 
Java8勉強会 
ウルシステムズ株式会社 
前多賢太郎 
2014/10/25
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 1 
はじめに 
今年3月にJava8がリリースされました。 
Java8には、インターフェースデフォルト実装, ラムダ式, Stream APIという 
設計・コーディングに大きな影響のあるアップデートが含まれます。 
そのためか、まだ開発の現場で採用になったという声は聞かれません。 
6/25にJava8対応版Eclipse4.4 Luna もリリースされ、Java8による開発 
がいよいよ広がっていくと予想されます。 
– なおNetBeansの方が完成度高いです。 
– Lunaはラムダ式のコードアシストが効かない、コンパイルできないバグがあります。 
というわけで、ここら辺でJava8の新機能をおさらいします。 
– 目玉となるラムダ式,Stream APIについて、オブジェクトとどのように組み合わせる 
かという事を中心に演習を実施します。
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 2 
前提事項 
 本日はJava8の変更点を体感するため、演習を行います。 
 演習を行うため事前に、jdk8, Eclipse4.4またはNetBeans8 の導入をお願いします 
– IntelliJ IDEAでもかまいませんが上記の2つほど念入りに動作検証を行っていません。 
 演習問題はmavenプロジェクトとして以下に公開しています。 
– https://github.com/enterprisegeeks/java8_study 
– 上記のページの指示に従って導入をお願いします。 
– 解答は上記ページのanswerブランチで、勉強会終了後に公開します。 
なお、現状NetBeans8/IntelliJ IDEAの方が使い勝手が良いです。 
– eclipseはコンパイラにバグがあります。 
– NetBeansで編集中のファイルのmainを実行するには、 
Shift + F6 です。
ULS 
for (String s : list) { 
if (s.equals(“100")) { 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 3 
Javaによくあるイメージ 
コードが長い・冗長 
– System.out.println とか 
– リストから何かを探すコードとか 
return s; 
} 
} 
– ファイルの入出力とか 
– Etc,,,, 
確かに、Javaのコードは堅苦しいと思うときがある。 
– rubyとかLL言語に手を出すと特にそう思う。 
– 一方で、Java SE5以降、static import・try-with-resource句、java NIO2な 
ど簡潔に書ける言語仕様が取り入れられつつある。 
Java8 ではラムダ式・Stream APIの導入により、更なるコードの簡潔さと平 
行性・(個人的に)楽しさを取り入れることが可能になる。
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 4 
Java8 更新機能一覧 
Java8の更新機能一覧は以下で見れます。 
– http://openjdk.java.net/projects/jdk8/features 
更新機能のサマリは以下を見てください。 
http://yoshio3.com/2014/03/21/congrats-javase8-launch/ 
本日はラムダ式、Stream APIなど文法や新APIに 
焦点を絞ります。 
 また、Stream APIについては、以下にも詳しい説明があります。 
– http://enterprisegeeks.hatenablog.com/category/Java8
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 5 
目次 
ラムダ式 
演習1 
Stream API 
演習2 
演習3 
Optional 
 インターフェース拡張 
– staticメソッド実装 
– デフォルトメソッド 
演習4 
その他トピック 
– 日付API 
– JVMまわり 
90分 
90分
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 6 
ラムダ式
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 7 
ラムダ式とは 
仕様 
– JEP126 Lambda Expressions & Virtual Extension Methods 
できるようになったこと 
– ラムダ式の文法追加による(限定的な)関数型プログラムのサポート 
影響 
– 関数型(ラムダ式)を使うと 
 特定の処理が、非常に簡単に書ける。 
 オブジェクト指向よりも、使い勝手の良いAPIを提供できる。 
– 一方で 
 Javaしかプログラム経験の無い人には、ラムダ式や関数型を理解するのは難しい。 
 コーディング規約でラムダ式禁止とかありえそう。
ラムダ式って? 関数型プログラムって? 
ULS 
var add2 = function(x){return x + 2;} 
add2(3) // 5 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 8 
関数って? 
– 何らかの値を取り、何らかの値を返すもの。 
ラムダ式って? 
– 関数の表現方法。数学由来で、関数をλx. x+2 のように書くから。 
– プログラムでは、匿名関数を生成するリテラルとして使用する。 
Javaにしかないの? 
– Javaは後発。Ruby, C#, C++11, javascript, Python なんでもござれ。 
関数型プログラムって? 
– 広義には、関数を値として扱えるプログラムスタイル。(他にも色々あるが割愛) 
 大雑把にいうと、関数を変数、メソッド引数や戻り値に指定できる事。 
Javascriptの以下のような書き方が、Javaでも可能になる。 
 C の関数ポインタも、関数型の一種と言えなくはない。。。
ULS 
(型引数1, 型引数2、、、) -> {メソッド本体} 
//文字列比較の例int copmareTo(String x, String y) 
(String x, String y) ->{return x.compareTo(y);} 
//省略形 
(x,y) -> x.compareTo(y) 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 9 
ラムダ式の文法と型 
文法 
– 基本書式 
– 省略形での記述も可能。というよりなるべく省略形を使ったほうが、良い。 
 引数の型は、省略可能で型は、その場合コンパイラが推測する(後述)。 
 引数リストは、引数が1つの場合はカッコが省略可能。(ただし引数なしは()とする) 
 メソッド本体はメソッドが1行の場合、{}とreturn,セミコロンを省略可能。 
 疑問 
– どうしてラムダ式の引数の型を書かなくても良いの?戻り値の型の宣言は?コンパ 
イルエラーや実行時エラーが起きるんじゃないの? 
– ラムダ式で作った関数(値)って結局何なの?
ULS 
インターフェースのメソッドが 
int compare(String, String) なので、x,yをStringと推測し、 
x,yが実行するメソッド、戻り値がintになるかをチェックする。 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 10 
ラムダ式の文法と型 
型と型推論 
– ラムダ式は、ラムダ式を受け取る変数や引数がセットで必要。 
– それらの型は、関数型インターフェースという特定の条件を満たしたインターフェー 
スである必要がある。 
 関数型インターフェースとは? 
– 実装するべきメソッドが1つのみのインターフェース 
(staticメソッド、デフォルトメソッドは幾つあってもよい。equals等Objectのメソッドも対象外) 
– Comparator(compare),Runnable(run)などが対象。 
– @FunctionalInterfaceアノテーションが追加。コンパイル時に関数型インターフェースの要件を 
満たすかチェック可能。(チェックだけなので、アノテーションはあってもなくてもよい。) 
– つまり、ラムダ式で生成されたオブジェクトは、関数型インターフェースを実装した匿 
名クラスのオブジェクト。 
– ラムダ式で省略した引数や戻り値の型は、変数・引数の型宣言からコンパイラが推 
測して、合わない場合はコンパイルエラーとする。 
このような仕組みを型推論と呼ぶ。 
Comparator<String> comp = (x,y) -> x.compareTo(y) 
comp.compare("aaa", "bbb"); //-1
ULS 
Comparator<String> comp = new Comparator<String>(){ 
public int compare(String x, String y) { 
return x.compareTo(y); 
Comparator<String> comp = (x,y) -> x.compareTo(y) 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 11 
ラムダ式の正体 
結局のところ、Java8のラムダ式はメソッドが1つしかないインターフェースの匿 
名クラスを作るシンタックスシュガー 
– 匿名クラスとラムダ式は(ほとんど※)同じ。→5行が1行に! 5倍の生産性! 
} 
}; 
– 匿名クラスと比較して、ラムダ式のほうが実際の処理のみを記述しておりノイズが少 
ない。 
 一方で、メソッド名などがないのでラムダ式に該当する変数名などの命名が重要となる。 
– ※匿名クラスはコンパイル時にクラスファイルが作られるが、ラムダ式ではクラス 
ファイルは作成されない。 
 Invoke dynamicという新しく追加されたJVM命令を使って、実行時にインスタンス生成 
が行われている。 
 ラムダ式は多用されるので、Invoke dynamicによる最適化の余地を残している。
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 12 
ラムダ式の利用箇所 
使いどころ 
– 処理の大枠が決まっていて一部の挙動を変えたいという場合、継承やインター 
フェース実装を使うよりもシンプルに実現できる。 
 イベントハンドラ、コールバック(Swingとか) 
 Stream API(後述) 
 Strategyパターン(Collections#sortとか) 
 Visitorパターン 
– 匿名クラスを受け取る前提だったAPIの引数は、ラムダ式に置き換えが可能。 
5倍の生産性は言いすぎだが、体感で2,3割コードが短くなる事もある。 
→ NetBeansはラムダ式に置換なコードを教えてくれるできたやつ。
ULS 
//Collections#sort, Comparator#compare((T,T)->int) 
List<Integer> list = Arrays.asList(5,4,3,2,1); 
Collections.sort(list, (x, y) -> x - y);// 1,2,3,4,5 
//Swing addEventListner for Button. ActionListener#actionPerformed() 
JButton b2 = new JButton("B"); 
b2.addActionListener(e -> textField.setText("B clicked.")); 
// CSVの1行をカンマで分割した配列を、任意のオブジェクトに変換する自作メソッド 
List<Person> list = CSVReader.read(new File("user.csv"), 
array -> new Person(array[0], array[1])); 
list.forEach(System.out::println);// ←何だこれ? 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 13 
ラムダ式利用サンプル 
既存APIや、ラムダを使う例 
個人的には3番目の例のような、リソース(ファイル,JDBC)の情報を任意のオ 
ブジェクトにマッピングする方法として、ラムダ式が多用されるのではと思う。 
– 引数ありのコンストラクタや、toString,equals,hashCodeがちゃんと定義されて 
いるとベター。 
– 最後の“System.out::println”は次で解説。
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 14 
メソッド参照 
前述の、”System.out::println”はメソッド参照と呼ばれる新しい記法。 
既存のメソッドを用いるだけのラムダ式を、関数オブジェクトとしてラムダ式の 
引数を省略する。 
– 関数プログラムでは、関数を引数に取る場所に、直接関数名を渡す事ができるので、 
それと似たようなものを実現している。 
– 以下のような場合に置き換える事ができる。 
 ラムダ式の引数をstaticメソッドに渡すだけの場合。 
– s -> System.out.println(s) => System.out::println 
 ラムダ式の引数のインスタンスメソッドを呼ぶだけの場合 
– s -> s.lengh() => String::length 
– u -> u.getName() => User::getName 
 (主に)引数なしのラムダ式でコンストラクタを呼ぶだけの場合 
(supplier,generatorと呼ばれる) 
– () -> new ArrayList() => ArrayList::new 
 メソッド参照を書ける必要は無いが、読める必要はある 
– Javadocを見ていると当たり前にメソッド参照のコードが出てくる 
 メソッド参照が書けるようになると、ラムダ一人前
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 15 
メソッド参照の例 
以下のラムダ式と同じ意味のメソッド参照の例を示す。 
– NetBeansはメソッド参照に置き換え可能なラムダ式を教えてくれるできたやつ。 
// 引数あり、戻り値なしの例 
list.forEach(e -> System.out.println(e)); 
list.forEach(System.out::println); 
// 引数なしの例。コンストラクタもメソッド参照可能 
Supplier<List<String>> s1 = () -> new ArrayList<>(); 
Supplier<List<String>> s2 = ArrayList::new; 
List<String> l = s2.get(); // ArrayList 
// 2引数の例。Integer.sumは加算メソッドだが、メソッド参照ために用意されたみたいだ。 
BinaryOperator<Integer> add1 = (a,b)-> Integer.sum(a, b); 
BinaryOperator<Integer> add2 = Integer::sum; 
add2.apply(5,6);// 11 
// オブジェクトのメソッドも実行可能。インスタンスメソッドなのに、Person::となるのは正直キ 
モイ 
Function<Person, String> p1 = p -> p.getName(); 
Function<Person, String> p2 = Person::getName;
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 16 
演習1(20分) 
パッケージpractice1 
– 対象 
 LambdaLession.java 
– ラムダ式の書き換え 
– オブジェクトとラムダ式の組み合わせ 
 LetsMakeHFO.java 
– ラムダ式を受け取るメソッドを作ろう。 
テストデータ 
– テストデータは、部署-課-社員の階層構造を持つオブジェクトです。 
 部署は課の一覧を取得できる。(総務部は、総務1課,総務2課などを取得可能) 
 課は所属する部署を取得できる。 
 課は課に所属する社員の一覧を取得できる。 
 社員は所属する課を取得できる。 
 TestDataは、全ての部署、全ての課、全ての社員を取得するユーティリティです。 
部署課社員 
総務総務1課 
総務2課 
田中 
営業山田
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 17 
標準の関数型インターフェース 
 既存の多くのインターフェースが関数型インターフェースになりえるが、 
java.util.functionパッケージに、標準的な関数型インターフェースが追加さ 
れた。 
– (むしろ、既存のインターフェースと関数型インターフェースを別物にできれば、本当 
の関数型が導入できたかもしれないが、下位互換のために諦めたような気がする) 
 ラムダ式を扱う前提のAPIを作成する場合に使うと良い。 
 Stream APIをはじめとして、標準APIにも関数型インターフェースを受け取 
るものが多くあるので、意味を知っておく必要がある。 
そうでないと、Stream APIのjavadocが理解できない。 
 抜粋 
関数型インターフェース引数戻り値用途 
Function<T,R> T R TからRへの変換を行う。 
Consumer<T> T void 任意の副作用を実行する。 
Supplier<T> void T 
値Tを生成する。(型パラメータはRの方が適 
切だが、JavadocではT) 
Predicate<T> T boolean Tから真偽値を判定する。 
BiFunction<T,U,R> T,U R 
2つの引数T,UからRへの変換・計算を行 
う。この他、Bixxxは2引数を取るという意味
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 18 
ラムダ式まとめ 
ラムダ式(関数型)は、オブジェクト指向よりもコンパクトに、コードの再利用を促 
す 
– オブジェクト指向は、フレームワークやモジュールのような大きな粒度に向いている 
– 関数型は、共通関数とか簡潔なコードのような小さい部分に向いている 
– 両者をバランスよく使っていきましょう。 
Java8のラムダ式は、後付けかつ機能が限定的なのでちぐはぐな部分が多い。 
– ラムダ式で作った関数オブジェクトの関数を呼ぶ場合に、“変数名.メソッド”とする必 
要があるのは微妙。 
(前述のadd2.apply(5,6) みたいな。Javascriptだとadd2(5,6)でいける) 
– 関数合成ができるが、カリー化、部分適用、遅延評価、多相、末尾再帰みたいな機 
能はない。 
Java8でのラムダ式の使いどころは、引数に関数を渡す時 
– 変数や戻り値にしたところで前述の問題があるので使いづらい 
– Java8で関数型プログラムにこだわりすぎると、逆に失敗する 
 ラムダ式導入の目的はStream APIのためで、関数型プログラムではありません 
 関数型プログラムをやりたいなら言語を変えましょう
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 19 
ラムダ式補足 
例外と相性が悪い 
– もしチェック例外を投げる必要があるなら、関数型インターフェースのメソッド宣言でthrows句 
を付ける必要があります。 
– Function等デフォルトの関数型インターフェースにはthrows句がありませんので、(Stream 
API)でチェック例外を扱う必要が出てくると、ラムダ式本体にtryとか書く必要があるので発狂 
する。 
– Java.io.UncheckedIOExceptionとか、Javaの基本スタンスを崩すようなものも出てきた。 
ラムダ式の外部の変数参照 
– 無名クラスではfinal変数に限り外部変数の参照ができた。 
– ラムダ式も同様に、final変数ならびに事実上のfinal変数(※)の参照が可能 
 ※ コンパイラが、参照が変わらない変数をfinalとしてみなすように変更された。 
 参照が変わらないなら、外部のListのaddなど実行できるが、行うべきでない。(後述) 
thisの扱い 
– ラムダ式中のthisは、ラムダ式を定義したメソッドのインスタンスのthis 
 ラムダ式でthisを使う事は余り無いが、一応注意。 
標準Functionは合成可能 
– Functionなど、標準関数インターフェースはandThenなど、関数合成に関するメ 
ソッドをdefaultメソッドとして定義している。
コレクションに追加されたメソッド(example.CollectionLambda.java) 
 コレクションにもラムダ式を取るメソッドが追加されています。 
ULS 
// Listの中身を出力 
Arrays.asList(1,2,3,4).forEach(System.out::println); 
// 演習1 ソートの別解 
List<Emp> list = TestData.allEmployees(); 
list.sort(Comparator.comparing(Emp::getName)); 
list.forEach(e -> System.out.println(e.getId() + ":" + e.getName())); 
// Mapの値更新、出力 
Map<Integer, Integer> map = new HashMap<>(); 
map.put(1, 2); 
map.put(2, 3); 
// キーが2の値を累乗する。 
map.compute(2, (k, v) -> v * v); 
map.forEach( 
(k,v)-> System.out.println(String.format("key=%d:value=%d", k,v))); 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 20 
- Iterable#forEach(Consumer) 
– List#sort(Comparator) 
– Map#forEach(BiConsumer) 
– Map#compute(key, Function) 
– これらのメソッドは、後述するデフォルトメソッドにてインターフェースに実装がある。
ULS 
Stream API 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 21
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 22 
Stream APIの概要 
仕様 
– JEP107 Bulk Data Operations for Collections 
– IOストリームとかあるのに、Stream APIとか言っちゃうんだ、、、 
できるようになったこと 
– コレクション等一連の要素の集まりに対して,ラムダ式を使用した抽出/演算/変換等 
の一括操作の提供、および、逐次処理・並列処理(※)の提供 
影響 
– コレクションに対する操作をfor/whileを使った方式から、Stream APIを使用した 
新しい方式で書けるようになる。 
– 利点 
 宣言的であり、読みやすく、間違いが少ない 
 並列処理への切り替えが容易 
 配列・リスト・入出力などが同じ方法で扱える 
– 欠点 
 Stream APIを使いこなすには覚える事が多い 
 実用するには色々と機能が足りてない
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 23 
例題 
例題 
– 文字列のリストから整数とみなせる文字列を抽出し、 
整数に変換し、 
正の整数のみを抽出し、 
3倍する。
従来の方法(example.StreamBasic.java) 
ULS 
Arrays.asList("A001", "100", "-200", "ABC", "92"); 
List<Integer> res = new ArrayList<>(); 
for (String s : list) { 
if (s.matches("[-+]?d+")) { 
int i = Integer.parseInt(s); 
if (i > 0) { 
res.add(i * 3); 
} 
System.out.println(res);//300, 276 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 24 
例題 
– 整数リストから偶数の要素のみ抽出し、数を2倍した要素を取得する。 
List<String> list = 
} 
} 
– このような手続き型のコードは、条件分岐がネストしだすと、コードをよく見ないと、要 
件に合致する処理が書いてあるかわからない。
Stream API による解法(example.StreamBasic.java) 
ULS 
Arrays.asList("A001", "100", "-200", "ABC", "92"); 
List<Integer> res2 = list.stream() // Streamを‚生成 
.filter(s -> s.matches(“[-+]?d+”))//整数のみ抽出 
.map(s -> Integer.parseInt(s)) //文字列→整数 
.filter(i -> i > 0) // 正の整数のみ抽出 
.map(i -> i * 3) // 3倍する 
.collect(Collectors.toList()); //結果をListとして取得 
System.out.println(res2); 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 25 
例題 
– 整数リストから偶数の要素のみ抽出し、数を2倍した要素を取得する。 
List<String> list = 
 解説 
– Streamという一連の要素の集まりに、 
抽出(filter)・演算(map)のような操作を連結して繰り返し処理の内容を組み立てる。 
最終的にcollectメソッドで、操作した要素をList等に変換する。 
よくわからなければ、SQLでイメージしてもらうといいかもしれません。 
– 操作の内容はラムダ式で何をするのかを書く。 
– なんとなく、例題の処理内容とラムダ式の内容が揃ってる感じがしませんか。 
– あと変数も少ないですよね。
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 26 
Stream APIとは 
大雑把にいうと 
– ものすごいイテレーター。 
 繰り返し処理に、条件抽出や変換、件数指定などの操作を幾らでも設定できる。 
– 繰り返し処理の方法はStream APIの中に隠蔽される。 
 今まで繰り返しは、for/while/拡張for文などを選んでいたが、その必要がない。 
– 繰り返し処理の最適化をStreamに任す。 
 プログラマはStreamにどのような操作を行うか中心に書く。(宣言的なプログラム) 
性質 
– コレクションとは異なるクラス 
 生成- Streamを使うには既存のコレクションや配列から、別途変換が必要 
– Stream の各種メソッドは大別して以下の2種類に分かれる。 
 中間操作– 生成で構築した集合に対する演算を適用する。 
 終端操作– ストリームの集合から、コレクション、配列等への変換を行う。 
– 逐次処理/並列処理 
 繰り返し処理の方法を簡単に並列処理にできる。 
(処理の仕方を、プログラマが書く必要がないため。) 
– 遅延処理 
 繰り返し処理は最後に一度だけ実行される。
ULS 
中間操作List 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 27 
生成・中間操作・終端操作 
生成で様々なオブジェクトからStreamを作る 
中間操作でStreamに設定を追加する 
終端操作でStreamを処理して結果を得る 
– 繰り返し処理や並列処理の詳細はStreamの中だけで完結する 
List 
配列 
IO 
生成Stream 終端操作 
int 
Etc..
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 28 
Stream の生成 
生成 
– 色々なデータからStreamを生成するメソッドが、多数追加された。 
 コレクションから– Collection#stream, parallelStreamメソッド 
 配列- Arrays#stream 
 IOストリーム、ファイル– BufferedReader#lines, Files#lines 
 任意の可変長引数で– Stream#of 
 文字列から文字のストリーム– String#codePoint 
 無限数列– Stream#iterate, Stream#repeat 
 範囲生成(1から100までとか) – IntStream#range 
 他多数 
– ストリームを構築するコードを書く必要はありますが、逆に、元がコレクション、配列、 
ファイル、その他、何であっても一旦ストリームにしてしまえば、後は同じ方法で扱う 
事ができる。
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 29 
Stream の中間操作 
中間操作(抜粋) 
– Streamの要素に対する何らかの演算の指定を行うメソッド。 
中間操作は必ずStreamが戻り値なので、メソッドチェーンで連結できる。 
 filter – 条件ラムダ式に一致する要素のみを抜き出す。 
 map – 要素をラムダ式に適用して計算・変換する。 
 flatMap - 要素をStreamを生成するラムダ式に適用し、要素の増減を行う。 
 parallel – 繰り返し処理を並列処理で行う指示をする。 
 limit – 繰り返し処理を行う件数を制限する。 
 skip - 繰り返し処理を件数分スキップする。 
 以下は状態がある中間操作と呼ばれ、全ての要素の評価が終わらないと実行できない。 
そのため、性能に影響を与える可能性がある。 
– sort - 要素を並べ替える。 
– distinct – 要素の重複を除外する。
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 30 
Stream の終端操作 
終端操作(抜粋) 
– Streamから結果を生成する操作。 
終端操作を行った時点でStreamに設定された中間操作が順次実行され、終端操 
作の内容で結果が作られる。 
1つのStreamには、1回だけ終端操作を行うことができる。 
 anyMatch – ラムダ式の条件に合致する要素があるかbooleanで返す。※ 
 allMatch – 全ての要素がラムダ式の条件に合致するかbooleanで返す。※ 
 max, min – Comparatorを渡し、要素の最大・最小値を返す。 
 reduce – 全ての要素の合計値を出すなど、1つにまとめた結果を返す。 
 forEach - コンソール出力等、任意の副作用を実行する。 
 count – 件数取得 
 findFirst – 最初の1件を返す※ 
 collect – 汎用的な集積操作。Collectorsユーティリティによく使う操作が定義済み。 
– Collectors#toList – 要素をListへ変換する。 
– Collectors#joining – 要素を1つの文字列にする。接続句を指定可能。 
– Collectors#partitionBy – 要素をラムダ式の条件を満たすものと満たさないものに分割する。 
– Collectors#groupingBy – 要素をラムダ式の条件にしたがって複数のグループに分割する。 
– ※ anyMath, allMath,findFirstなどはショートサーキット評価であり、条件が一 
致した時点で要素を全て評価せず処理を打ち切る。
Stream コードサンプル(example.StreamSample.java) 
今までこういう処理って、似たようなforループを何度も書いていましたよね。 
ULS 
boolean negative = Stream.of(1,2,23,-4,5,-6) 
.anyMatch(n -> n < 0); // true 
boolean startsWith_a = Stream.of("angel", "apple", "banana") 
.allMatch(s -> s.startsWith("a"));//false 
Files.lines(new File("log.txt").toPath()) 
.skip(100).limit(100) 
.forEach(System.out::println); 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 31 
– 負数があるか? 
– 全てaから始まるか? 
– ファイルの101行目から200行目だけを出す。 
– -文字列の間に”,”をつけて1つの文字列に。 
String[] sa = new String[]{"AA", "BB", "CC", "DD"}; 
String concat = Arrays.stream(sa) 
.collect(Collectors.joining(",")); 
String concat2 = String.join(“,”, sa);//別解
ULS 
int sum = Stream.of(1,2,3,4,5).reduce(1, (a, b) -> a * b);//120 
Reduce(折りたたみ演算)のイメージ 
1 2 3 4 5 
* * * * * 
1 1 2 6 24 120 
整数リストの要素(b) 
集積器(a) 
String[] word={"apple", "angel", "banana", "bush", "cross", "dart"}; 
Map<Character, List<String>> group = Arrays.stream(word) 
.collect(Collectors.groupingBy(w -> w.charAt(0))); 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 32 
Stream コードサンプル2 
– 整数リストの乗算(Java8 ではreduceよりcollectを推奨) 
– 単語リストを始まりの1文字でグループ化したい。 
 グループ化した要素はデフォルトはリストだが、任意の変換を適用する事も可能 
– ユーザーの平均年齢を得たい。 
double avg = userList.stream() 
.collect(Collectors.averagingDouble(u -> u.getAge()));
Stream コードサンプル3 (example.RangeSample) 
ULS 
// 1から10の合計 
int sum = IntStream.range(1, 11).sum(); 
// 0から9の数字のうち、乗算が25を超える数の組み合わせを求める。 
List<String> comb = IntStream.range(0, 10).boxed() 
.flatMap(x -> IntStream.range(x, 10).boxed() 
.filter(y -> x * y >= 25).map(y -> x + "," + y)) 
.collect(Collectors.toList()); 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 33 
– 範囲生成 
 IntStreamを用いて、1から10のような数の範囲を作成できる。 
– 無限ストリーム 
 Stream#iterateは初期値からラムダ式を適用し、無限に値を生成する。 
– そのままforEachなどとすると無限ループとなるが、有限のストリームと組み合わせる(zip)、件数 
制限を行う(limit等)によって、breakに相当する仕組みを作れる。 
// 無限数を用いて、自然数のうち3または5で割れる100番目の数を求める。 
Optional<Integer> num = Stream.iterate(1, i -> i + 1) //無限ループ? 
.filter(i -> i % 3 == 0 || i % 5 == 0) 
.skip(99).findFirst(); 
num.ifPresent(System.out::println);//215
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 34 
演習2(20分) 
オブジェクトを対象として、Stream APIの各種操作を行います。 
パッケージ: practice2 
– LetsStream 
 ポイント 
– filter, map, collect(Collectors.toList())が基本。 
– 包含判定は、anyMatch,allMatch,noneMatchが使える。 
– collect,CollectorsにはtoList以外に色々便利機能がある。 
 joinging – 文字列集合に接続句(オプションで接頭句、接尾句)もつけて1つの文字列に。 
 Sepalateby – 集合を2つに分ける。分け方はbooleanを返すラムダ式で指定 
 groupingBy - ↑を一般化。集合をラムダ式の演算結果によって分ける。 
 avaraging, sumarying, summing – 平均、サマリ、合計の算出。 
– flatMapが最初はわかりにくいと思います。これは2重ループに相当すると思ってく 
ださい。(TestData.javaのallSection()とflatMapの演習を比較してみてくださ 
い)
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 35 
休憩
ULS 
IntStream.range(1, 1000).boxed() 
.parallel() 
.peek(i -> System.out.println(“N=" + i)) 
.map(i -> i * 100 + i) 
.collect(Collectors.toList()); 
System.out.println(list); 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 36 
並列処理への対応 
繰り返し処理を並列で行うには? 
– forループをマルチスレッドにするには多大な労力が伴う。 
– Stream APIでは、parallelメソッドを呼ぶだけ 
 example.TryParalle.java 
List<Integer> list = 
– 並列処理でも要素の順番は保証される。(一部例外あり) 
 分割して処理した要素を、1つにまとめ、元の順番に復元する。 
 逐次並列・並列どちらで行っても同じ結果 
 ただし、以下の場合は例外 
– forEachメソッド(順序が必要ならforEachOrderedを使う) 
– 中間操作unordered(順序保証をなくす)を実行した場合。
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 37 
並列処理への対応2 
– 一部の中間操作や終端操作と併用する場合、非効率となる事があるので、注意が 
必要。更に、場合によっては無限ループになることがある。 
 skipは先頭N件の読み飛ばす、findFirstは先頭1件を取り出す、このような処理は並列 
処理の場合全ての要素の評価が終わって順序付けしないとどれが最初のN件だったかが 
わからない 
– 逐次処理だとforループの読み飛ばしなどで簡単にできるが、並列だと効率が悪くなってしまう例 
– 要素が無限の場合は評価が終わらないので、無限ループになってしまう! 
 並列をやめるか、unorderedを指定する。 
– 外部変数の状態に依存するラムダ式を書くと不正な結果になる。 
 forEachで、外部の変数に要素を追加するような処理は並列処理で順番がずれる。 
– 概ね、そのような処理は終端操作で実現できる。 
– 並列化のコストがかかるので、何でも並列にすれば良いわけではない。 
 効果が大きいのは以下が両立する場合 
– 繰り返し処理1回あたりの処理時間が長い 
– 要素数が多い
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 38 
遅延処理 
問題ファイルlog.txtがオープンするのはどこ? 
– ファイル”log.txt”の”error”が含まれる行に”Error = “を付けて10件まで表示す 
る。 
Files.lines(new File("log.txt").toPath()) 
.filter(line -> line.contains("error")) 
.map(line -> "Error = " + line) 
.limit(10) 
.forEach(line -> System.out.println(line));
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 39 
遅延処理2 
答– 終端操作(forEach)が実行されるとき。 
– 中間操作は操作の予約をするだけ。 
– 終端操作で、要素ごとに中間操作を適用していく。 
 以下のような処理が実行される。 
 繰り返し処理は1度だけ行われる。(中間操作ごとに繰り返し処理を行ったりしない) 
 そのため、無限のストリームも問題なく扱える。 
try(BufferedReader br = Files.newBufferedReader(new 
File("log.txt").toPath())) { 
String line; 
int i = 0; 
while((line = br.readLine()) != null) { 
if (i == 10) break; 
if (line.contains("error")) { 
String line2 = "Error= " + line; 
System.out.println(line2); 
} 
i++; 
} 
}
Stream APIと上手く付き合うコツ 
ULS 
Stream.of(1,2,3,4).forEach(i -> { 
if (i % 2 == 0) { 
System.out.println(i); 
List<Integer> list = new ArrayList<>(); 
Stream.of(1,2,3,4,5).map(i -> i * 2).parallel() 
.forEach(i -> list.add(i)); //listの順番がめちゃくちゃ 
List<Integer> list2 = Stream.of(1,2,3,4,5).map(i -> i * 2).parallel() 
.collect(Collectors.toList()); //OK 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 40 
 ラムダ式は複雑にしない。 
– filter, map等の操作を重ねる事で、ラムダ式自体は単純にする。 
 テストが簡単になる。操作の順番の入れ替えが容易。 
– Filterは要素の判定、mapは変換、forEachは順次処理という様に、決まった役割があるの 
で、それ以外の処理をラムダ式で行わないようにする。 
 以下は、filteで行うべき処理がforEachに全て書かれてしまっている悪い例。 
}}); 
 外部変数は参照だけする。決して状態を変更しない。 
– 参照の変わらない変数であれば、外部変数のメソッドは実行できるが、並列実行すると順序が 
変わるので行うべきでない。 
 Stream の処理結果を終端操作の戻り値以外の手段で取得するのは、悪手。 
– 外部状態に関わらず、同じ引数なら同じ結果を常に返す関数を、javaではステートレス操作と 
呼ぶ(純粋関数とも)。可能な限りステートレスなラムダ式を作成すること。
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 41 
Streamがいけてるところ 
 リストの詰め替えや、条件判定なんかはStreamの方が簡単に書けるし、どんどん使っ 
ていい。 
– 変数の状態を更新する処理が減るので、バグが少なくなる(かも) 
 中間操作の順序を変えることで、処理内容を変えることが簡単にできる。 
 普通のforループの方が性能が良いんじゃないかと思うかもしれません。 
多分事実ですが、そういうことは性能的な問題が出てから考えましょう。 
– forループとStreamの処理速度の違いは感じない。 
– コード1箇所での最適化なんで、全体から見れば微々たる物。 
– 最悪、並列処理にするという選択肢も取れる。 
 なおStreamのラムダ式を短く書くには以下を工夫すると良い。 
– 引数ありのコンストラクタやオブジェクト生成のstaticメソッドを作る。 
 mapでオブジェクト生成を1行で書ける。 
– equals,hashCode,toStringのオーバーライドや、判定メソッドなどの追加。 
 groupingByなどの集約条件や、filterの条件などが短く書ける。
Streamがいけてないところ(私見) 
正直何度も.stream(), .colletct(Collectros.,,,,) を書くのは飽きる。 
StreamのJavadocを読むにはかなりの修行がいる。 
終端操作で結果をファイル出力するには、どうするのが正解なのか。 
BufferedReader#lines,Files#linesから作ったStreamはcloseしないとリ 
ソースが解放されない(try-with-resource句も使える)。 
ULS 
– 下位互換と並列処理の境界を設ける為にしょうがないとは思うけど、 
anyMatchとか、groupingByとかぐらいは、Listにあってもいいじゃんとは思う。 
(そんな事言ったら、コレクションと配列に同じメソッド作らんといけないし無理なんだ 
ろうけど) 
– ついでに言うと、ラムダ式の変数名、変数宣言が必須なのもどうにかなりませんか。 
 map(i -> i * 3) を、map(i * 3) と書きたい! 
– 今の仕様なら、メソッド作ってメソッド参照にするしかない、、、、scalaなら。。。 
– 関数型インタフェースの種類と型の対応が理解しないと、どんなラムダ式が書ける 
か解らない。 
 ex) BiFunction<T,U,R> は、(T, U) -> R というラムダ式。 
– 説明に当然のように出てくるメソッド参照。 
– Stream全般もそうだが、Stream#collectの仕組みも複雑。 
– ついでに言うと、コンパイルエラーのメッセージもひどい。 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 42
Streamがいけてないところ(私見)2 
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 43 
デバッグは困難。 
– ブレークポイントと相性悪い。 
 中間操作にブレークポイント入れても、繰り返し処理中に止まるわけではない。 
 途中の結果を見るのが難しい。 
– 対策 
 Peekを上手く使う(デバッグ用途で使うなら、toStringを定義してあるとシンプルになるの 
で良い) 
 複雑なラムダ式を書くより、1行のラムダ式で中間操作を重ねるようにしよう。 
 ユニットテスト 
他の言語のStream API相当の機能には、zipと呼ばれる機能があるが、 
Stream APIにはなく、自作する必要がある。 
– インデックスアクセスとか、前後の要素をみたいというような処理を行うにはzipが 
必要。 
– zipを使うとなると、タプルのようなオブジェクトを組み合わせにできるものがリテラル 
として欲しくなる。 
– zipの概要はこちらをどうぞ。 
– http://enterprisegeeks.hatenablog.com/entry/2014/05/19/100422
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 44 
演習3(20分) 
Zipを使ってみよう 
パッケージ:practice3 
– ソース:ZipPractice.java 
Zipとは? 
– 2つの集合を組み合わせ、要素同士のペアを作る操作。 
– zipによって既存のforループで行う様々な処理を置き換え可能になる。 
– Stream API相当の機能を持つ他の言語には大抵あるが、javaには無い。 
 途中までありましたが、リリース時に消えました。。。 
 clojureにもrubyにもC#にもscalaにもあるのに。。。。 
1 2 3 4 5 
a b c d 
zip 1,a 2,b 3,c 4,d 
要素の数が合わな 
い場合は短い方に合 
わせる。
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 45 
演習3-補足 
前後の要素比較 
– 通常のリストと、1つ要素をずらしたリストを用意することで、前後の要素が比較可能 
となる。 
1 2 3 4 5 
2 3 4 5 
zip 1,2 2,3 3,4 4,5 
1 
Stream#skip(1)
ULS 
インターフェース拡張 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 46
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 47 
インターフェース拡張 
仕様 
– JEP126 Lambda Expressions & Virtual Extension Methods 
できるようになったこと 
– インターフェースに、staticメソッドが定義可能になった。 
– インターフェースに、実装が持てるようになった。(デフォルトメソッド) 
 部分的な多重継承の実現 
影響 
– Java8では、ラムダ式やStream APIが注目されているが、デフォルトメソッドの方 
がクラス設計に与える影響は大きい。 
– デザインパターン、フレームワークも再考されるのでは。
ULS 
public interface TestIF { 
static void print(){System.out.println("test");} 
static void main(String[] args){TestIF.print();}//testと表示 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 48 
インターフェースstatic メソッド 
 概要 
– インターフェースにstaticメソッドを書く事ができる。(そのまんま) 
– 呼び出す場合は、インタフェース.メソッド名で良い。 
– staticメソッドがあるインターフェースを継承したインターフェースや実装したクラス 
名で、インターフェースのstaticメソッドを呼ぶ事は当然できない。 
– mainメソッドも書けるし、実行できるよ!(だからどうした) 
 例 
 使いどころ 
– 正直あまり思い浮かばない。ユーティリティメソッドの置き場とか? 
 Java APIでの使用箇所 
– java.util.Comparator – ラムダ式を使ったComparator作成など色々増えた。 
 コンパレータの生成が簡単にできるものがある。 
}
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 49 
デフォルトメソッド 
 概要 
– インターフェースに内容有りのメソッドを定義可能。(default キーワード使用) 
– 実装したクラスは、デフォルトメソッドを実装しなくてもよい。(オーバーライド可能) 
– インターフェースなので複数実装可能。限定的な多重継承の実現。 
 メソッドが被ったら? →コンパイルエラー。オーバーライドして解決する。 
– 抽象クラスとは異なる点は以下の2つ。 
1. 抽象クラスは継承できるのは1つ。インターフェースは複数実装可能。 
2. 抽象クラスはフィールドを持てる。インターフェースは持てない。(thisを上手く使おう) 
 なぜ導入されたか? 
– ラムダ式、Stream APIの導入で、List等既存のAPIに相当数のメソッド追加があ 
り、実装クラスのメソッド追加が半端なかったため。デフォルトメソッドでインター 
フェースにメソッドを追加しても、実装クラスのソースを修正する必要がない。 
 使いどころ 
– 色々ありそう。ログ出力とか。 
– AOPとかDIとか、今までリフレクション、アノテーション、設定ファイル、黒魔術な手 
段で解消してきた事が簡単になりそうな気配はある。 
– が、これだ!というのは思いつかないですね。実例が揃うのを待ちたい。
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 50 
デフォルトメソッド– 使用例1 
 単純な例 
interface ConsoleLogger { 
default void log(String msg) { 
System.out.println("message = " + msg); 
} 
} 
public class DefaultTest implements ConsoleLogger { 
// ConsoleLoggerのlogメソッドは上書き不要 
public void test() { 
log("user"); 
} 
public static void main(String[] args) { 
new DefaultTest().test();// message = user 
} 
}
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 51 
デフォルトメソッド– 使用例2 
 デフォルトメソッドが重複する例 
interface Bar { 
default void print(){System.out.println("Bar");} 
default void p(){System.out.println("p");} 
} 
interface Foo { 
default void print(){System.out.println("Foo");} 
} 
// printが衝突 
public class DefaultTest2 implements Bar,Foo { 
@Override public void print() { 
// インターフェース.super.メソッドで参照可能 
Bar.super.print(); 
} 
}
デフォルトメソッド– 使用例3-1(紹介のみ) 
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 52 
 実践的な例 
– 参考: http://yojik.hatenablog.jp/entry/2013/11/02/172132 
– 実装するインターフェースを変えるだけで、エラーログの出力をコンソール/ファイル 
に切り替える。
ULS 
// エラーログをコンソールに出す場合。 
class ProcessImpl extends Process 
implements InfoConsoleLog, ErrorConsoleLog{} 
// こう定義するとエラーログはファイルに出る。 
class ProcessImpl extends Process 
implements InfoConsoleLog, ErrorFileLog{} 
public class DefaultExample { 
public static void main(String[] args) { 
Process p = new ProcessImple(); 
p.go(); 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 53 
デフォルトメソッド– 使用例3-2 
 (続き) 具象クラスの継承するときにデフォルトメソッド有りのインターフェース 
を選択する。具象クラスの実装は不要。 
– 欲を言うと、匿名クラス作成時にインターフェースも指定できると、具象クラスの宣言も不要でいいんだけ 
ど、、、 
例) Process p = new Process implemets InfoConsoleLog, ErrorConsoleLog(){}; 
} 
} 
 実装はこちら: 
– https://gist.github.com/kencharos/1518df9e660e2873b5fb
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 54 
Optional
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 55 
Optional 
Optional型って? 
– 失敗するかもしれない計算(nullを返すかもしれないメソッド)の結果を表す。 
– nullを扱えないHaskellでnullのような概念を表す型、 
Maybe a(Nothing | Just a) から由来。 
– Stream APIのmaxなど、Streamの一部のメソッドはOptionalを返す。 
(要素が0個のStreamから最大値なんて探せないから) 
利点 
– メソッドの戻り値が例えば、Stringだと、そのメソッドがnullを返すかどうかは、メソッ 
ド宣言からだけでは一切解らない。 
– もし戻り値が、Optional <String> なら、メソッドはStringの結果を返すかもし 
れないが、返さないかもしれないということが読み取れる。 
また、同時にOptionalから結果があるかを判定するコードを書かざるを得ないので、 
NullPointerExceptionの発生を抑制する。 
– というわけで、nullを返すようなメソッドを作るときには、代わりにOptionalを使う事 
を検討しても良いかもしれません。 
 DAOのfindByPkとか。
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 56 
サンプル 
Optional型のオブジェクトから、計算結果を取得する各種サンプル。 
他にも色々なメソッドがあるので、javadocを参照。 
// Optionalを返すメソッドを実行 
Optional<String> res = someMethod(); 
// isPresentは結果があるか判定。getは値がある場合のみ成功する。 
if(res.isPresent()) { 
System.out.println(res.get()); 
} 
// 値がある場合のみラムダ式を実行する。(上と同じ動作をする) 
res.ifPresent(r -> System.out.println(r)); 
// 値があれば取得し、なければ引数の値を使う。 
String s = res.orElse("nothing");
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 57 
演習4(25分) 
デフォルトメソッドを使って、Mapにキーから取得した値をOptionalでラップし 
た値を返す機能を追加します。 
パッケージ: practice4 
– OptionalMap(Mapを継承) 
 インターフェース。デフォルトメソッドgetByOptの中身を記述してください。 
– キーに紐づく値が無い場合空のOptional、そうでない場合値をOptionalに包んで返す。 
– OptionalHashMap 
 HashMapを継承し、OptionalMapを実装します。 
 継承クラスをHashMapからLinkedHashMapに変更する事も容易だということが解ると 
思います。 
– Test 
 OptionalHashMapを使用したテストです。
ULS 
//mapからの取得値をOptionalに包む 
private static <T> Optional<T> get(Map<T,T> map, T key) { 
return Optional.ofNullable(map.get(key)); 
// “A”を起点にmapから3度段階的に取得を行う。 
// どの時点でmapから取得できなくなっても、エラーにならない。 
get(map, "A") 
.flatMap(k -> get(map, k)) //kはmapから”A”で取得した値。 
.flatMap(k -> get(map, k)) 
.ifPresent(System.out::println);//値があれば表示。 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 58 
OptionalにもあるflatMap 
Optionalには、Stream同様、map, flatMapメソッドがあり、Optionalの中 
の結果に対して、演算が適用できる。 
– さらに、Optionalに結果がない場合は何もしないという性質がある。 
– この性質を生かすと、flatMapでは段階的な取得のような処理が簡単に書ける。 
例) Mapから取得した値をキーとしてMapから再度値を取得を3回行う。 
} 
– flatMapは”モナド”と言う計算パターンの一種。
ULS 
その他トピック 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 59
新日付API(java.time) -example.TimeTest 
 java.timeパッケージ(JEP150 Date&Time API)の主なクラスは以下の通り。 
 Date,Calendarよりも簡単・高機能。あとスレッドセーフ。 
使用例年,月,日,時間,分,秒を指定して日時を生成 
LocalDateTime may = LocalDateTime.of(2014, 5, 8, 13, 0, 0); 
LocalDateTime calcDate = may.minusMonths(1).plus(Period.ofYears(2)); 
System.out.println(calcDate.format(DateTimeFormatter.ofPattern("yyyy/MM/dd hh:mm:ss"))); 
Chronology jp = Chronology.of("Japanese"); 
ChronoLocalDate wareki = jp.date(may); 
System.out.printf( 
"%d年は%s %d年n",wareki.get(ChronoField.YEAR), wareki.getEra(), wareki.get(ChronoField.YEAR_OF_ERA)); 
 Date/Calendarの置き換えを狙っているため、Date/Calendarとの変換メソッドは提供されない。 
 その割には、JDBCでは新APIにまた対応していない。 
ULS 
– 日付・時間を表す- LocalDate(日付), LocalTime(時間), LocalDateTime/ZonedDataTime(日時) 
– 時間の量を表す- Duration(時間の量), Period(日付の量) 
– 日付・時間の計算メソッドに上記の量を渡して計算を行う。 
– 1つの日時オブジェクトで時間の表現、時間計算、文字列変換ができる。(Data/Calendar間の変換不要) 
– 日時オブジェクトを様々な方法で作成できる。 
– 月が1オリジン(1が1月)である。(Calendarは0が1月) 
– 和暦のようなロケールに応じた年代を表示できる。 
– 日時オブジェクトは不変。計算結果は別オブジェクトになる。 
– 新APIを使うのなら、Date/Calendarを一切使うなという意思表示。保守案件には無用の代物かもしれない。 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 60 
– 普及には時間がかかりそう。 
日付の計算は新しい日時を生成する 
和暦の出力例2014年はHeisei 26年と出力
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 61 
JVMまわり 
Java8には、JVMや周辺ツールの変更もある。 
例えば 
– Sun JVM(Hotspot)とOracle JVM(jRockit)の統合 
– パーマネント領域の廃止(-XX:PermSizeオプションが無効) 
 JVMオプションが色々と変更 
– Javascirptエンジンの変更(Rhino → Nashorn) 
– APTの廃止 
– Javadocツールの強化(コメントチェック、構文木生成) 
Java8へのアップデート案件では、プログラムの稼動確認だけでなく、JVMの 
起動パラメータやパフォーマンスなんかも確認しておきましょう。 
他にも 
– javacコマンドのバージョン指定(-source, -target)は3世代前までのみをサポー 
トするようになります。 
– 現在のJDK8でもjava1.5以前向けのコンパイルは可能ですが、将来削除されると 
いう警告が発生します。
ULS 
Copyright © 2011-2014 UL Systems, Inc. All rights reserved. 
Proprietary & Confidential Powered by 62 
まとめ 
Java8は、Java5のジェネリクス追加に匹敵するアップデート 
 インターフェース実装、ラムダ式、Stream API 全て役に立ちます。 
– 使いこなせる必要は無いですが、これらの要素はAPIのいたる所に出てくるので、 
概要や使い方くらいは知っておくべき。 
– 詳しく知るならJavadocを読むか、enterprisegeeksで。 
 是非、「何だかわからないからラムダ禁止」みたいな風潮と戦いましょう。 
Java8採用にむけて訴求できそうなポイント 
– Stream APIで並列処理による高速化が容易になる。 
– Stream APIを使って、省コードかつバグリにくく保守性が高いプログラムが作れる 
– Java7 のEOLは2015年4月

Java8勉強会

  • 1.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by Java8勉強会 ウルシステムズ株式会社 前多賢太郎 2014/10/25
  • 2.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 1 はじめに 今年3月にJava8がリリースされました。 Java8には、インターフェースデフォルト実装, ラムダ式, Stream APIという 設計・コーディングに大きな影響のあるアップデートが含まれます。 そのためか、まだ開発の現場で採用になったという声は聞かれません。 6/25にJava8対応版Eclipse4.4 Luna もリリースされ、Java8による開発 がいよいよ広がっていくと予想されます。 – なおNetBeansの方が完成度高いです。 – Lunaはラムダ式のコードアシストが効かない、コンパイルできないバグがあります。 というわけで、ここら辺でJava8の新機能をおさらいします。 – 目玉となるラムダ式,Stream APIについて、オブジェクトとどのように組み合わせる かという事を中心に演習を実施します。
  • 3.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 2 前提事項  本日はJava8の変更点を体感するため、演習を行います。  演習を行うため事前に、jdk8, Eclipse4.4またはNetBeans8 の導入をお願いします – IntelliJ IDEAでもかまいませんが上記の2つほど念入りに動作検証を行っていません。  演習問題はmavenプロジェクトとして以下に公開しています。 – https://github.com/enterprisegeeks/java8_study – 上記のページの指示に従って導入をお願いします。 – 解答は上記ページのanswerブランチで、勉強会終了後に公開します。 なお、現状NetBeans8/IntelliJ IDEAの方が使い勝手が良いです。 – eclipseはコンパイラにバグがあります。 – NetBeansで編集中のファイルのmainを実行するには、 Shift + F6 です。
  • 4.
    ULS for (Strings : list) { if (s.equals(“100")) { Copyright © 2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 3 Javaによくあるイメージ コードが長い・冗長 – System.out.println とか – リストから何かを探すコードとか return s; } } – ファイルの入出力とか – Etc,,,, 確かに、Javaのコードは堅苦しいと思うときがある。 – rubyとかLL言語に手を出すと特にそう思う。 – 一方で、Java SE5以降、static import・try-with-resource句、java NIO2な ど簡潔に書ける言語仕様が取り入れられつつある。 Java8 ではラムダ式・Stream APIの導入により、更なるコードの簡潔さと平 行性・(個人的に)楽しさを取り入れることが可能になる。
  • 5.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 4 Java8 更新機能一覧 Java8の更新機能一覧は以下で見れます。 – http://openjdk.java.net/projects/jdk8/features 更新機能のサマリは以下を見てください。 http://yoshio3.com/2014/03/21/congrats-javase8-launch/ 本日はラムダ式、Stream APIなど文法や新APIに 焦点を絞ります。  また、Stream APIについては、以下にも詳しい説明があります。 – http://enterprisegeeks.hatenablog.com/category/Java8
  • 6.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 5 目次 ラムダ式 演習1 Stream API 演習2 演習3 Optional  インターフェース拡張 – staticメソッド実装 – デフォルトメソッド 演習4 その他トピック – 日付API – JVMまわり 90分 90分
  • 7.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 6 ラムダ式
  • 8.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 7 ラムダ式とは 仕様 – JEP126 Lambda Expressions & Virtual Extension Methods できるようになったこと – ラムダ式の文法追加による(限定的な)関数型プログラムのサポート 影響 – 関数型(ラムダ式)を使うと  特定の処理が、非常に簡単に書ける。  オブジェクト指向よりも、使い勝手の良いAPIを提供できる。 – 一方で  Javaしかプログラム経験の無い人には、ラムダ式や関数型を理解するのは難しい。  コーディング規約でラムダ式禁止とかありえそう。
  • 9.
    ラムダ式って? 関数型プログラムって? ULS var add2 = function(x){return x + 2;} add2(3) // 5 Copyright © 2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 8 関数って? – 何らかの値を取り、何らかの値を返すもの。 ラムダ式って? – 関数の表現方法。数学由来で、関数をλx. x+2 のように書くから。 – プログラムでは、匿名関数を生成するリテラルとして使用する。 Javaにしかないの? – Javaは後発。Ruby, C#, C++11, javascript, Python なんでもござれ。 関数型プログラムって? – 広義には、関数を値として扱えるプログラムスタイル。(他にも色々あるが割愛)  大雑把にいうと、関数を変数、メソッド引数や戻り値に指定できる事。 Javascriptの以下のような書き方が、Javaでも可能になる。  C の関数ポインタも、関数型の一種と言えなくはない。。。
  • 10.
    ULS (型引数1, 型引数2、、、)-> {メソッド本体} //文字列比較の例int copmareTo(String x, String y) (String x, String y) ->{return x.compareTo(y);} //省略形 (x,y) -> x.compareTo(y) Copyright © 2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 9 ラムダ式の文法と型 文法 – 基本書式 – 省略形での記述も可能。というよりなるべく省略形を使ったほうが、良い。  引数の型は、省略可能で型は、その場合コンパイラが推測する(後述)。  引数リストは、引数が1つの場合はカッコが省略可能。(ただし引数なしは()とする)  メソッド本体はメソッドが1行の場合、{}とreturn,セミコロンを省略可能。  疑問 – どうしてラムダ式の引数の型を書かなくても良いの?戻り値の型の宣言は?コンパ イルエラーや実行時エラーが起きるんじゃないの? – ラムダ式で作った関数(値)って結局何なの?
  • 11.
    ULS インターフェースのメソッドが intcompare(String, String) なので、x,yをStringと推測し、 x,yが実行するメソッド、戻り値がintになるかをチェックする。 Copyright © 2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 10 ラムダ式の文法と型 型と型推論 – ラムダ式は、ラムダ式を受け取る変数や引数がセットで必要。 – それらの型は、関数型インターフェースという特定の条件を満たしたインターフェー スである必要がある。  関数型インターフェースとは? – 実装するべきメソッドが1つのみのインターフェース (staticメソッド、デフォルトメソッドは幾つあってもよい。equals等Objectのメソッドも対象外) – Comparator(compare),Runnable(run)などが対象。 – @FunctionalInterfaceアノテーションが追加。コンパイル時に関数型インターフェースの要件を 満たすかチェック可能。(チェックだけなので、アノテーションはあってもなくてもよい。) – つまり、ラムダ式で生成されたオブジェクトは、関数型インターフェースを実装した匿 名クラスのオブジェクト。 – ラムダ式で省略した引数や戻り値の型は、変数・引数の型宣言からコンパイラが推 測して、合わない場合はコンパイルエラーとする。 このような仕組みを型推論と呼ぶ。 Comparator<String> comp = (x,y) -> x.compareTo(y) comp.compare("aaa", "bbb"); //-1
  • 12.
    ULS Comparator<String> comp= new Comparator<String>(){ public int compare(String x, String y) { return x.compareTo(y); Comparator<String> comp = (x,y) -> x.compareTo(y) Copyright © 2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 11 ラムダ式の正体 結局のところ、Java8のラムダ式はメソッドが1つしかないインターフェースの匿 名クラスを作るシンタックスシュガー – 匿名クラスとラムダ式は(ほとんど※)同じ。→5行が1行に! 5倍の生産性! } }; – 匿名クラスと比較して、ラムダ式のほうが実際の処理のみを記述しておりノイズが少 ない。  一方で、メソッド名などがないのでラムダ式に該当する変数名などの命名が重要となる。 – ※匿名クラスはコンパイル時にクラスファイルが作られるが、ラムダ式ではクラス ファイルは作成されない。  Invoke dynamicという新しく追加されたJVM命令を使って、実行時にインスタンス生成 が行われている。  ラムダ式は多用されるので、Invoke dynamicによる最適化の余地を残している。
  • 13.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 12 ラムダ式の利用箇所 使いどころ – 処理の大枠が決まっていて一部の挙動を変えたいという場合、継承やインター フェース実装を使うよりもシンプルに実現できる。  イベントハンドラ、コールバック(Swingとか)  Stream API(後述)  Strategyパターン(Collections#sortとか)  Visitorパターン – 匿名クラスを受け取る前提だったAPIの引数は、ラムダ式に置き換えが可能。 5倍の生産性は言いすぎだが、体感で2,3割コードが短くなる事もある。 → NetBeansはラムダ式に置換なコードを教えてくれるできたやつ。
  • 14.
    ULS //Collections#sort, Comparator#compare((T,T)->int) List<Integer> list = Arrays.asList(5,4,3,2,1); Collections.sort(list, (x, y) -> x - y);// 1,2,3,4,5 //Swing addEventListner for Button. ActionListener#actionPerformed() JButton b2 = new JButton("B"); b2.addActionListener(e -> textField.setText("B clicked.")); // CSVの1行をカンマで分割した配列を、任意のオブジェクトに変換する自作メソッド List<Person> list = CSVReader.read(new File("user.csv"), array -> new Person(array[0], array[1])); list.forEach(System.out::println);// ←何だこれ? Copyright © 2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 13 ラムダ式利用サンプル 既存APIや、ラムダを使う例 個人的には3番目の例のような、リソース(ファイル,JDBC)の情報を任意のオ ブジェクトにマッピングする方法として、ラムダ式が多用されるのではと思う。 – 引数ありのコンストラクタや、toString,equals,hashCodeがちゃんと定義されて いるとベター。 – 最後の“System.out::println”は次で解説。
  • 15.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 14 メソッド参照 前述の、”System.out::println”はメソッド参照と呼ばれる新しい記法。 既存のメソッドを用いるだけのラムダ式を、関数オブジェクトとしてラムダ式の 引数を省略する。 – 関数プログラムでは、関数を引数に取る場所に、直接関数名を渡す事ができるので、 それと似たようなものを実現している。 – 以下のような場合に置き換える事ができる。  ラムダ式の引数をstaticメソッドに渡すだけの場合。 – s -> System.out.println(s) => System.out::println  ラムダ式の引数のインスタンスメソッドを呼ぶだけの場合 – s -> s.lengh() => String::length – u -> u.getName() => User::getName  (主に)引数なしのラムダ式でコンストラクタを呼ぶだけの場合 (supplier,generatorと呼ばれる) – () -> new ArrayList() => ArrayList::new  メソッド参照を書ける必要は無いが、読める必要はある – Javadocを見ていると当たり前にメソッド参照のコードが出てくる  メソッド参照が書けるようになると、ラムダ一人前
  • 16.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 15 メソッド参照の例 以下のラムダ式と同じ意味のメソッド参照の例を示す。 – NetBeansはメソッド参照に置き換え可能なラムダ式を教えてくれるできたやつ。 // 引数あり、戻り値なしの例 list.forEach(e -> System.out.println(e)); list.forEach(System.out::println); // 引数なしの例。コンストラクタもメソッド参照可能 Supplier<List<String>> s1 = () -> new ArrayList<>(); Supplier<List<String>> s2 = ArrayList::new; List<String> l = s2.get(); // ArrayList // 2引数の例。Integer.sumは加算メソッドだが、メソッド参照ために用意されたみたいだ。 BinaryOperator<Integer> add1 = (a,b)-> Integer.sum(a, b); BinaryOperator<Integer> add2 = Integer::sum; add2.apply(5,6);// 11 // オブジェクトのメソッドも実行可能。インスタンスメソッドなのに、Person::となるのは正直キ モイ Function<Person, String> p1 = p -> p.getName(); Function<Person, String> p2 = Person::getName;
  • 17.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 16 演習1(20分) パッケージpractice1 – 対象  LambdaLession.java – ラムダ式の書き換え – オブジェクトとラムダ式の組み合わせ  LetsMakeHFO.java – ラムダ式を受け取るメソッドを作ろう。 テストデータ – テストデータは、部署-課-社員の階層構造を持つオブジェクトです。  部署は課の一覧を取得できる。(総務部は、総務1課,総務2課などを取得可能)  課は所属する部署を取得できる。  課は課に所属する社員の一覧を取得できる。  社員は所属する課を取得できる。  TestDataは、全ての部署、全ての課、全ての社員を取得するユーティリティです。 部署課社員 総務総務1課 総務2課 田中 営業山田
  • 18.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 17 標準の関数型インターフェース  既存の多くのインターフェースが関数型インターフェースになりえるが、 java.util.functionパッケージに、標準的な関数型インターフェースが追加さ れた。 – (むしろ、既存のインターフェースと関数型インターフェースを別物にできれば、本当 の関数型が導入できたかもしれないが、下位互換のために諦めたような気がする)  ラムダ式を扱う前提のAPIを作成する場合に使うと良い。  Stream APIをはじめとして、標準APIにも関数型インターフェースを受け取 るものが多くあるので、意味を知っておく必要がある。 そうでないと、Stream APIのjavadocが理解できない。  抜粋 関数型インターフェース引数戻り値用途 Function<T,R> T R TからRへの変換を行う。 Consumer<T> T void 任意の副作用を実行する。 Supplier<T> void T 値Tを生成する。(型パラメータはRの方が適 切だが、JavadocではT) Predicate<T> T boolean Tから真偽値を判定する。 BiFunction<T,U,R> T,U R 2つの引数T,UからRへの変換・計算を行 う。この他、Bixxxは2引数を取るという意味
  • 19.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 18 ラムダ式まとめ ラムダ式(関数型)は、オブジェクト指向よりもコンパクトに、コードの再利用を促 す – オブジェクト指向は、フレームワークやモジュールのような大きな粒度に向いている – 関数型は、共通関数とか簡潔なコードのような小さい部分に向いている – 両者をバランスよく使っていきましょう。 Java8のラムダ式は、後付けかつ機能が限定的なのでちぐはぐな部分が多い。 – ラムダ式で作った関数オブジェクトの関数を呼ぶ場合に、“変数名.メソッド”とする必 要があるのは微妙。 (前述のadd2.apply(5,6) みたいな。Javascriptだとadd2(5,6)でいける) – 関数合成ができるが、カリー化、部分適用、遅延評価、多相、末尾再帰みたいな機 能はない。 Java8でのラムダ式の使いどころは、引数に関数を渡す時 – 変数や戻り値にしたところで前述の問題があるので使いづらい – Java8で関数型プログラムにこだわりすぎると、逆に失敗する  ラムダ式導入の目的はStream APIのためで、関数型プログラムではありません  関数型プログラムをやりたいなら言語を変えましょう
  • 20.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 19 ラムダ式補足 例外と相性が悪い – もしチェック例外を投げる必要があるなら、関数型インターフェースのメソッド宣言でthrows句 を付ける必要があります。 – Function等デフォルトの関数型インターフェースにはthrows句がありませんので、(Stream API)でチェック例外を扱う必要が出てくると、ラムダ式本体にtryとか書く必要があるので発狂 する。 – Java.io.UncheckedIOExceptionとか、Javaの基本スタンスを崩すようなものも出てきた。 ラムダ式の外部の変数参照 – 無名クラスではfinal変数に限り外部変数の参照ができた。 – ラムダ式も同様に、final変数ならびに事実上のfinal変数(※)の参照が可能  ※ コンパイラが、参照が変わらない変数をfinalとしてみなすように変更された。  参照が変わらないなら、外部のListのaddなど実行できるが、行うべきでない。(後述) thisの扱い – ラムダ式中のthisは、ラムダ式を定義したメソッドのインスタンスのthis  ラムダ式でthisを使う事は余り無いが、一応注意。 標準Functionは合成可能 – Functionなど、標準関数インターフェースはandThenなど、関数合成に関するメ ソッドをdefaultメソッドとして定義している。
  • 21.
    コレクションに追加されたメソッド(example.CollectionLambda.java)  コレクションにもラムダ式を取るメソッドが追加されています。 ULS // Listの中身を出力 Arrays.asList(1,2,3,4).forEach(System.out::println); // 演習1 ソートの別解 List<Emp> list = TestData.allEmployees(); list.sort(Comparator.comparing(Emp::getName)); list.forEach(e -> System.out.println(e.getId() + ":" + e.getName())); // Mapの値更新、出力 Map<Integer, Integer> map = new HashMap<>(); map.put(1, 2); map.put(2, 3); // キーが2の値を累乗する。 map.compute(2, (k, v) -> v * v); map.forEach( (k,v)-> System.out.println(String.format("key=%d:value=%d", k,v))); Copyright © 2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 20 - Iterable#forEach(Consumer) – List#sort(Comparator) – Map#forEach(BiConsumer) – Map#compute(key, Function) – これらのメソッドは、後述するデフォルトメソッドにてインターフェースに実装がある。
  • 22.
    ULS Stream API Copyright © 2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 21
  • 23.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 22 Stream APIの概要 仕様 – JEP107 Bulk Data Operations for Collections – IOストリームとかあるのに、Stream APIとか言っちゃうんだ、、、 できるようになったこと – コレクション等一連の要素の集まりに対して,ラムダ式を使用した抽出/演算/変換等 の一括操作の提供、および、逐次処理・並列処理(※)の提供 影響 – コレクションに対する操作をfor/whileを使った方式から、Stream APIを使用した 新しい方式で書けるようになる。 – 利点  宣言的であり、読みやすく、間違いが少ない  並列処理への切り替えが容易  配列・リスト・入出力などが同じ方法で扱える – 欠点  Stream APIを使いこなすには覚える事が多い  実用するには色々と機能が足りてない
  • 24.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 23 例題 例題 – 文字列のリストから整数とみなせる文字列を抽出し、 整数に変換し、 正の整数のみを抽出し、 3倍する。
  • 25.
    従来の方法(example.StreamBasic.java) ULS Arrays.asList("A001","100", "-200", "ABC", "92"); List<Integer> res = new ArrayList<>(); for (String s : list) { if (s.matches("[-+]?d+")) { int i = Integer.parseInt(s); if (i > 0) { res.add(i * 3); } System.out.println(res);//300, 276 Copyright © 2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 24 例題 – 整数リストから偶数の要素のみ抽出し、数を2倍した要素を取得する。 List<String> list = } } – このような手続き型のコードは、条件分岐がネストしだすと、コードをよく見ないと、要 件に合致する処理が書いてあるかわからない。
  • 26.
    Stream API による解法(example.StreamBasic.java) ULS Arrays.asList("A001", "100", "-200", "ABC", "92"); List<Integer> res2 = list.stream() // Streamを‚生成 .filter(s -> s.matches(“[-+]?d+”))//整数のみ抽出 .map(s -> Integer.parseInt(s)) //文字列→整数 .filter(i -> i > 0) // 正の整数のみ抽出 .map(i -> i * 3) // 3倍する .collect(Collectors.toList()); //結果をListとして取得 System.out.println(res2); Copyright © 2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 25 例題 – 整数リストから偶数の要素のみ抽出し、数を2倍した要素を取得する。 List<String> list =  解説 – Streamという一連の要素の集まりに、 抽出(filter)・演算(map)のような操作を連結して繰り返し処理の内容を組み立てる。 最終的にcollectメソッドで、操作した要素をList等に変換する。 よくわからなければ、SQLでイメージしてもらうといいかもしれません。 – 操作の内容はラムダ式で何をするのかを書く。 – なんとなく、例題の処理内容とラムダ式の内容が揃ってる感じがしませんか。 – あと変数も少ないですよね。
  • 27.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 26 Stream APIとは 大雑把にいうと – ものすごいイテレーター。  繰り返し処理に、条件抽出や変換、件数指定などの操作を幾らでも設定できる。 – 繰り返し処理の方法はStream APIの中に隠蔽される。  今まで繰り返しは、for/while/拡張for文などを選んでいたが、その必要がない。 – 繰り返し処理の最適化をStreamに任す。  プログラマはStreamにどのような操作を行うか中心に書く。(宣言的なプログラム) 性質 – コレクションとは異なるクラス  生成- Streamを使うには既存のコレクションや配列から、別途変換が必要 – Stream の各種メソッドは大別して以下の2種類に分かれる。  中間操作– 生成で構築した集合に対する演算を適用する。  終端操作– ストリームの集合から、コレクション、配列等への変換を行う。 – 逐次処理/並列処理  繰り返し処理の方法を簡単に並列処理にできる。 (処理の仕方を、プログラマが書く必要がないため。) – 遅延処理  繰り返し処理は最後に一度だけ実行される。
  • 28.
    ULS 中間操作List Copyright© 2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 27 生成・中間操作・終端操作 生成で様々なオブジェクトからStreamを作る 中間操作でStreamに設定を追加する 終端操作でStreamを処理して結果を得る – 繰り返し処理や並列処理の詳細はStreamの中だけで完結する List 配列 IO 生成Stream 終端操作 int Etc..
  • 29.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 28 Stream の生成 生成 – 色々なデータからStreamを生成するメソッドが、多数追加された。  コレクションから– Collection#stream, parallelStreamメソッド  配列- Arrays#stream  IOストリーム、ファイル– BufferedReader#lines, Files#lines  任意の可変長引数で– Stream#of  文字列から文字のストリーム– String#codePoint  無限数列– Stream#iterate, Stream#repeat  範囲生成(1から100までとか) – IntStream#range  他多数 – ストリームを構築するコードを書く必要はありますが、逆に、元がコレクション、配列、 ファイル、その他、何であっても一旦ストリームにしてしまえば、後は同じ方法で扱う 事ができる。
  • 30.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 29 Stream の中間操作 中間操作(抜粋) – Streamの要素に対する何らかの演算の指定を行うメソッド。 中間操作は必ずStreamが戻り値なので、メソッドチェーンで連結できる。  filter – 条件ラムダ式に一致する要素のみを抜き出す。  map – 要素をラムダ式に適用して計算・変換する。  flatMap - 要素をStreamを生成するラムダ式に適用し、要素の増減を行う。  parallel – 繰り返し処理を並列処理で行う指示をする。  limit – 繰り返し処理を行う件数を制限する。  skip - 繰り返し処理を件数分スキップする。  以下は状態がある中間操作と呼ばれ、全ての要素の評価が終わらないと実行できない。 そのため、性能に影響を与える可能性がある。 – sort - 要素を並べ替える。 – distinct – 要素の重複を除外する。
  • 31.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 30 Stream の終端操作 終端操作(抜粋) – Streamから結果を生成する操作。 終端操作を行った時点でStreamに設定された中間操作が順次実行され、終端操 作の内容で結果が作られる。 1つのStreamには、1回だけ終端操作を行うことができる。  anyMatch – ラムダ式の条件に合致する要素があるかbooleanで返す。※  allMatch – 全ての要素がラムダ式の条件に合致するかbooleanで返す。※  max, min – Comparatorを渡し、要素の最大・最小値を返す。  reduce – 全ての要素の合計値を出すなど、1つにまとめた結果を返す。  forEach - コンソール出力等、任意の副作用を実行する。  count – 件数取得  findFirst – 最初の1件を返す※  collect – 汎用的な集積操作。Collectorsユーティリティによく使う操作が定義済み。 – Collectors#toList – 要素をListへ変換する。 – Collectors#joining – 要素を1つの文字列にする。接続句を指定可能。 – Collectors#partitionBy – 要素をラムダ式の条件を満たすものと満たさないものに分割する。 – Collectors#groupingBy – 要素をラムダ式の条件にしたがって複数のグループに分割する。 – ※ anyMath, allMath,findFirstなどはショートサーキット評価であり、条件が一 致した時点で要素を全て評価せず処理を打ち切る。
  • 32.
    Stream コードサンプル(example.StreamSample.java) 今までこういう処理って、似たようなforループを何度も書いていましたよね。 ULS boolean negative = Stream.of(1,2,23,-4,5,-6) .anyMatch(n -> n < 0); // true boolean startsWith_a = Stream.of("angel", "apple", "banana") .allMatch(s -> s.startsWith("a"));//false Files.lines(new File("log.txt").toPath()) .skip(100).limit(100) .forEach(System.out::println); Copyright © 2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 31 – 負数があるか? – 全てaから始まるか? – ファイルの101行目から200行目だけを出す。 – -文字列の間に”,”をつけて1つの文字列に。 String[] sa = new String[]{"AA", "BB", "CC", "DD"}; String concat = Arrays.stream(sa) .collect(Collectors.joining(",")); String concat2 = String.join(“,”, sa);//別解
  • 33.
    ULS int sum= Stream.of(1,2,3,4,5).reduce(1, (a, b) -> a * b);//120 Reduce(折りたたみ演算)のイメージ 1 2 3 4 5 * * * * * 1 1 2 6 24 120 整数リストの要素(b) 集積器(a) String[] word={"apple", "angel", "banana", "bush", "cross", "dart"}; Map<Character, List<String>> group = Arrays.stream(word) .collect(Collectors.groupingBy(w -> w.charAt(0))); Copyright © 2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 32 Stream コードサンプル2 – 整数リストの乗算(Java8 ではreduceよりcollectを推奨) – 単語リストを始まりの1文字でグループ化したい。  グループ化した要素はデフォルトはリストだが、任意の変換を適用する事も可能 – ユーザーの平均年齢を得たい。 double avg = userList.stream() .collect(Collectors.averagingDouble(u -> u.getAge()));
  • 34.
    Stream コードサンプル3 (example.RangeSample) ULS // 1から10の合計 int sum = IntStream.range(1, 11).sum(); // 0から9の数字のうち、乗算が25を超える数の組み合わせを求める。 List<String> comb = IntStream.range(0, 10).boxed() .flatMap(x -> IntStream.range(x, 10).boxed() .filter(y -> x * y >= 25).map(y -> x + "," + y)) .collect(Collectors.toList()); Copyright © 2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 33 – 範囲生成  IntStreamを用いて、1から10のような数の範囲を作成できる。 – 無限ストリーム  Stream#iterateは初期値からラムダ式を適用し、無限に値を生成する。 – そのままforEachなどとすると無限ループとなるが、有限のストリームと組み合わせる(zip)、件数 制限を行う(limit等)によって、breakに相当する仕組みを作れる。 // 無限数を用いて、自然数のうち3または5で割れる100番目の数を求める。 Optional<Integer> num = Stream.iterate(1, i -> i + 1) //無限ループ? .filter(i -> i % 3 == 0 || i % 5 == 0) .skip(99).findFirst(); num.ifPresent(System.out::println);//215
  • 35.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 34 演習2(20分) オブジェクトを対象として、Stream APIの各種操作を行います。 パッケージ: practice2 – LetsStream  ポイント – filter, map, collect(Collectors.toList())が基本。 – 包含判定は、anyMatch,allMatch,noneMatchが使える。 – collect,CollectorsにはtoList以外に色々便利機能がある。  joinging – 文字列集合に接続句(オプションで接頭句、接尾句)もつけて1つの文字列に。  Sepalateby – 集合を2つに分ける。分け方はbooleanを返すラムダ式で指定  groupingBy - ↑を一般化。集合をラムダ式の演算結果によって分ける。  avaraging, sumarying, summing – 平均、サマリ、合計の算出。 – flatMapが最初はわかりにくいと思います。これは2重ループに相当すると思ってく ださい。(TestData.javaのallSection()とflatMapの演習を比較してみてくださ い)
  • 36.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 35 休憩
  • 37.
    ULS IntStream.range(1, 1000).boxed() .parallel() .peek(i -> System.out.println(“N=" + i)) .map(i -> i * 100 + i) .collect(Collectors.toList()); System.out.println(list); Copyright © 2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 36 並列処理への対応 繰り返し処理を並列で行うには? – forループをマルチスレッドにするには多大な労力が伴う。 – Stream APIでは、parallelメソッドを呼ぶだけ  example.TryParalle.java List<Integer> list = – 並列処理でも要素の順番は保証される。(一部例外あり)  分割して処理した要素を、1つにまとめ、元の順番に復元する。  逐次並列・並列どちらで行っても同じ結果  ただし、以下の場合は例外 – forEachメソッド(順序が必要ならforEachOrderedを使う) – 中間操作unordered(順序保証をなくす)を実行した場合。
  • 38.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 37 並列処理への対応2 – 一部の中間操作や終端操作と併用する場合、非効率となる事があるので、注意が 必要。更に、場合によっては無限ループになることがある。  skipは先頭N件の読み飛ばす、findFirstは先頭1件を取り出す、このような処理は並列 処理の場合全ての要素の評価が終わって順序付けしないとどれが最初のN件だったかが わからない – 逐次処理だとforループの読み飛ばしなどで簡単にできるが、並列だと効率が悪くなってしまう例 – 要素が無限の場合は評価が終わらないので、無限ループになってしまう!  並列をやめるか、unorderedを指定する。 – 外部変数の状態に依存するラムダ式を書くと不正な結果になる。  forEachで、外部の変数に要素を追加するような処理は並列処理で順番がずれる。 – 概ね、そのような処理は終端操作で実現できる。 – 並列化のコストがかかるので、何でも並列にすれば良いわけではない。  効果が大きいのは以下が両立する場合 – 繰り返し処理1回あたりの処理時間が長い – 要素数が多い
  • 39.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 38 遅延処理 問題ファイルlog.txtがオープンするのはどこ? – ファイル”log.txt”の”error”が含まれる行に”Error = “を付けて10件まで表示す る。 Files.lines(new File("log.txt").toPath()) .filter(line -> line.contains("error")) .map(line -> "Error = " + line) .limit(10) .forEach(line -> System.out.println(line));
  • 40.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 39 遅延処理2 答– 終端操作(forEach)が実行されるとき。 – 中間操作は操作の予約をするだけ。 – 終端操作で、要素ごとに中間操作を適用していく。  以下のような処理が実行される。  繰り返し処理は1度だけ行われる。(中間操作ごとに繰り返し処理を行ったりしない)  そのため、無限のストリームも問題なく扱える。 try(BufferedReader br = Files.newBufferedReader(new File("log.txt").toPath())) { String line; int i = 0; while((line = br.readLine()) != null) { if (i == 10) break; if (line.contains("error")) { String line2 = "Error= " + line; System.out.println(line2); } i++; } }
  • 41.
    Stream APIと上手く付き合うコツ ULS Stream.of(1,2,3,4).forEach(i -> { if (i % 2 == 0) { System.out.println(i); List<Integer> list = new ArrayList<>(); Stream.of(1,2,3,4,5).map(i -> i * 2).parallel() .forEach(i -> list.add(i)); //listの順番がめちゃくちゃ List<Integer> list2 = Stream.of(1,2,3,4,5).map(i -> i * 2).parallel() .collect(Collectors.toList()); //OK Copyright © 2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 40  ラムダ式は複雑にしない。 – filter, map等の操作を重ねる事で、ラムダ式自体は単純にする。  テストが簡単になる。操作の順番の入れ替えが容易。 – Filterは要素の判定、mapは変換、forEachは順次処理という様に、決まった役割があるの で、それ以外の処理をラムダ式で行わないようにする。  以下は、filteで行うべき処理がforEachに全て書かれてしまっている悪い例。 }});  外部変数は参照だけする。決して状態を変更しない。 – 参照の変わらない変数であれば、外部変数のメソッドは実行できるが、並列実行すると順序が 変わるので行うべきでない。  Stream の処理結果を終端操作の戻り値以外の手段で取得するのは、悪手。 – 外部状態に関わらず、同じ引数なら同じ結果を常に返す関数を、javaではステートレス操作と 呼ぶ(純粋関数とも)。可能な限りステートレスなラムダ式を作成すること。
  • 42.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 41 Streamがいけてるところ  リストの詰め替えや、条件判定なんかはStreamの方が簡単に書けるし、どんどん使っ ていい。 – 変数の状態を更新する処理が減るので、バグが少なくなる(かも)  中間操作の順序を変えることで、処理内容を変えることが簡単にできる。  普通のforループの方が性能が良いんじゃないかと思うかもしれません。 多分事実ですが、そういうことは性能的な問題が出てから考えましょう。 – forループとStreamの処理速度の違いは感じない。 – コード1箇所での最適化なんで、全体から見れば微々たる物。 – 最悪、並列処理にするという選択肢も取れる。  なおStreamのラムダ式を短く書くには以下を工夫すると良い。 – 引数ありのコンストラクタやオブジェクト生成のstaticメソッドを作る。  mapでオブジェクト生成を1行で書ける。 – equals,hashCode,toStringのオーバーライドや、判定メソッドなどの追加。  groupingByなどの集約条件や、filterの条件などが短く書ける。
  • 43.
    Streamがいけてないところ(私見) 正直何度も.stream(), .colletct(Collectros.,,,,)を書くのは飽きる。 StreamのJavadocを読むにはかなりの修行がいる。 終端操作で結果をファイル出力するには、どうするのが正解なのか。 BufferedReader#lines,Files#linesから作ったStreamはcloseしないとリ ソースが解放されない(try-with-resource句も使える)。 ULS – 下位互換と並列処理の境界を設ける為にしょうがないとは思うけど、 anyMatchとか、groupingByとかぐらいは、Listにあってもいいじゃんとは思う。 (そんな事言ったら、コレクションと配列に同じメソッド作らんといけないし無理なんだ ろうけど) – ついでに言うと、ラムダ式の変数名、変数宣言が必須なのもどうにかなりませんか。  map(i -> i * 3) を、map(i * 3) と書きたい! – 今の仕様なら、メソッド作ってメソッド参照にするしかない、、、、scalaなら。。。 – 関数型インタフェースの種類と型の対応が理解しないと、どんなラムダ式が書ける か解らない。  ex) BiFunction<T,U,R> は、(T, U) -> R というラムダ式。 – 説明に当然のように出てくるメソッド参照。 – Stream全般もそうだが、Stream#collectの仕組みも複雑。 – ついでに言うと、コンパイルエラーのメッセージもひどい。 Copyright © 2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 42
  • 44.
    Streamがいけてないところ(私見)2 ULS Copyright© 2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 43 デバッグは困難。 – ブレークポイントと相性悪い。  中間操作にブレークポイント入れても、繰り返し処理中に止まるわけではない。  途中の結果を見るのが難しい。 – 対策  Peekを上手く使う(デバッグ用途で使うなら、toStringを定義してあるとシンプルになるの で良い)  複雑なラムダ式を書くより、1行のラムダ式で中間操作を重ねるようにしよう。  ユニットテスト 他の言語のStream API相当の機能には、zipと呼ばれる機能があるが、 Stream APIにはなく、自作する必要がある。 – インデックスアクセスとか、前後の要素をみたいというような処理を行うにはzipが 必要。 – zipを使うとなると、タプルのようなオブジェクトを組み合わせにできるものがリテラル として欲しくなる。 – zipの概要はこちらをどうぞ。 – http://enterprisegeeks.hatenablog.com/entry/2014/05/19/100422
  • 45.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 44 演習3(20分) Zipを使ってみよう パッケージ:practice3 – ソース:ZipPractice.java Zipとは? – 2つの集合を組み合わせ、要素同士のペアを作る操作。 – zipによって既存のforループで行う様々な処理を置き換え可能になる。 – Stream API相当の機能を持つ他の言語には大抵あるが、javaには無い。  途中までありましたが、リリース時に消えました。。。  clojureにもrubyにもC#にもscalaにもあるのに。。。。 1 2 3 4 5 a b c d zip 1,a 2,b 3,c 4,d 要素の数が合わな い場合は短い方に合 わせる。
  • 46.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 45 演習3-補足 前後の要素比較 – 通常のリストと、1つ要素をずらしたリストを用意することで、前後の要素が比較可能 となる。 1 2 3 4 5 2 3 4 5 zip 1,2 2,3 3,4 4,5 1 Stream#skip(1)
  • 47.
    ULS インターフェース拡張 Copyright© 2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 46
  • 48.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 47 インターフェース拡張 仕様 – JEP126 Lambda Expressions & Virtual Extension Methods できるようになったこと – インターフェースに、staticメソッドが定義可能になった。 – インターフェースに、実装が持てるようになった。(デフォルトメソッド)  部分的な多重継承の実現 影響 – Java8では、ラムダ式やStream APIが注目されているが、デフォルトメソッドの方 がクラス設計に与える影響は大きい。 – デザインパターン、フレームワークも再考されるのでは。
  • 49.
    ULS public interfaceTestIF { static void print(){System.out.println("test");} static void main(String[] args){TestIF.print();}//testと表示 Copyright © 2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 48 インターフェースstatic メソッド  概要 – インターフェースにstaticメソッドを書く事ができる。(そのまんま) – 呼び出す場合は、インタフェース.メソッド名で良い。 – staticメソッドがあるインターフェースを継承したインターフェースや実装したクラス 名で、インターフェースのstaticメソッドを呼ぶ事は当然できない。 – mainメソッドも書けるし、実行できるよ!(だからどうした)  例  使いどころ – 正直あまり思い浮かばない。ユーティリティメソッドの置き場とか?  Java APIでの使用箇所 – java.util.Comparator – ラムダ式を使ったComparator作成など色々増えた。  コンパレータの生成が簡単にできるものがある。 }
  • 50.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 49 デフォルトメソッド  概要 – インターフェースに内容有りのメソッドを定義可能。(default キーワード使用) – 実装したクラスは、デフォルトメソッドを実装しなくてもよい。(オーバーライド可能) – インターフェースなので複数実装可能。限定的な多重継承の実現。  メソッドが被ったら? →コンパイルエラー。オーバーライドして解決する。 – 抽象クラスとは異なる点は以下の2つ。 1. 抽象クラスは継承できるのは1つ。インターフェースは複数実装可能。 2. 抽象クラスはフィールドを持てる。インターフェースは持てない。(thisを上手く使おう)  なぜ導入されたか? – ラムダ式、Stream APIの導入で、List等既存のAPIに相当数のメソッド追加があ り、実装クラスのメソッド追加が半端なかったため。デフォルトメソッドでインター フェースにメソッドを追加しても、実装クラスのソースを修正する必要がない。  使いどころ – 色々ありそう。ログ出力とか。 – AOPとかDIとか、今までリフレクション、アノテーション、設定ファイル、黒魔術な手 段で解消してきた事が簡単になりそうな気配はある。 – が、これだ!というのは思いつかないですね。実例が揃うのを待ちたい。
  • 51.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 50 デフォルトメソッド– 使用例1  単純な例 interface ConsoleLogger { default void log(String msg) { System.out.println("message = " + msg); } } public class DefaultTest implements ConsoleLogger { // ConsoleLoggerのlogメソッドは上書き不要 public void test() { log("user"); } public static void main(String[] args) { new DefaultTest().test();// message = user } }
  • 52.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 51 デフォルトメソッド– 使用例2  デフォルトメソッドが重複する例 interface Bar { default void print(){System.out.println("Bar");} default void p(){System.out.println("p");} } interface Foo { default void print(){System.out.println("Foo");} } // printが衝突 public class DefaultTest2 implements Bar,Foo { @Override public void print() { // インターフェース.super.メソッドで参照可能 Bar.super.print(); } }
  • 53.
    デフォルトメソッド– 使用例3-1(紹介のみ) ULS Copyright © 2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 52  実践的な例 – 参考: http://yojik.hatenablog.jp/entry/2013/11/02/172132 – 実装するインターフェースを変えるだけで、エラーログの出力をコンソール/ファイル に切り替える。
  • 54.
    ULS // エラーログをコンソールに出す場合。 class ProcessImpl extends Process implements InfoConsoleLog, ErrorConsoleLog{} // こう定義するとエラーログはファイルに出る。 class ProcessImpl extends Process implements InfoConsoleLog, ErrorFileLog{} public class DefaultExample { public static void main(String[] args) { Process p = new ProcessImple(); p.go(); Copyright © 2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 53 デフォルトメソッド– 使用例3-2  (続き) 具象クラスの継承するときにデフォルトメソッド有りのインターフェース を選択する。具象クラスの実装は不要。 – 欲を言うと、匿名クラス作成時にインターフェースも指定できると、具象クラスの宣言も不要でいいんだけ ど、、、 例) Process p = new Process implemets InfoConsoleLog, ErrorConsoleLog(){}; } }  実装はこちら: – https://gist.github.com/kencharos/1518df9e660e2873b5fb
  • 55.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 54 Optional
  • 56.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 55 Optional Optional型って? – 失敗するかもしれない計算(nullを返すかもしれないメソッド)の結果を表す。 – nullを扱えないHaskellでnullのような概念を表す型、 Maybe a(Nothing | Just a) から由来。 – Stream APIのmaxなど、Streamの一部のメソッドはOptionalを返す。 (要素が0個のStreamから最大値なんて探せないから) 利点 – メソッドの戻り値が例えば、Stringだと、そのメソッドがnullを返すかどうかは、メソッ ド宣言からだけでは一切解らない。 – もし戻り値が、Optional <String> なら、メソッドはStringの結果を返すかもし れないが、返さないかもしれないということが読み取れる。 また、同時にOptionalから結果があるかを判定するコードを書かざるを得ないので、 NullPointerExceptionの発生を抑制する。 – というわけで、nullを返すようなメソッドを作るときには、代わりにOptionalを使う事 を検討しても良いかもしれません。  DAOのfindByPkとか。
  • 57.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 56 サンプル Optional型のオブジェクトから、計算結果を取得する各種サンプル。 他にも色々なメソッドがあるので、javadocを参照。 // Optionalを返すメソッドを実行 Optional<String> res = someMethod(); // isPresentは結果があるか判定。getは値がある場合のみ成功する。 if(res.isPresent()) { System.out.println(res.get()); } // 値がある場合のみラムダ式を実行する。(上と同じ動作をする) res.ifPresent(r -> System.out.println(r)); // 値があれば取得し、なければ引数の値を使う。 String s = res.orElse("nothing");
  • 58.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 57 演習4(25分) デフォルトメソッドを使って、Mapにキーから取得した値をOptionalでラップし た値を返す機能を追加します。 パッケージ: practice4 – OptionalMap(Mapを継承)  インターフェース。デフォルトメソッドgetByOptの中身を記述してください。 – キーに紐づく値が無い場合空のOptional、そうでない場合値をOptionalに包んで返す。 – OptionalHashMap  HashMapを継承し、OptionalMapを実装します。  継承クラスをHashMapからLinkedHashMapに変更する事も容易だということが解ると 思います。 – Test  OptionalHashMapを使用したテストです。
  • 59.
    ULS //mapからの取得値をOptionalに包む privatestatic <T> Optional<T> get(Map<T,T> map, T key) { return Optional.ofNullable(map.get(key)); // “A”を起点にmapから3度段階的に取得を行う。 // どの時点でmapから取得できなくなっても、エラーにならない。 get(map, "A") .flatMap(k -> get(map, k)) //kはmapから”A”で取得した値。 .flatMap(k -> get(map, k)) .ifPresent(System.out::println);//値があれば表示。 Copyright © 2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 58 OptionalにもあるflatMap Optionalには、Stream同様、map, flatMapメソッドがあり、Optionalの中 の結果に対して、演算が適用できる。 – さらに、Optionalに結果がない場合は何もしないという性質がある。 – この性質を生かすと、flatMapでは段階的な取得のような処理が簡単に書ける。 例) Mapから取得した値をキーとしてMapから再度値を取得を3回行う。 } – flatMapは”モナド”と言う計算パターンの一種。
  • 60.
    ULS その他トピック Copyright© 2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 59
  • 61.
    新日付API(java.time) -example.TimeTest java.timeパッケージ(JEP150 Date&Time API)の主なクラスは以下の通り。  Date,Calendarよりも簡単・高機能。あとスレッドセーフ。 使用例年,月,日,時間,分,秒を指定して日時を生成 LocalDateTime may = LocalDateTime.of(2014, 5, 8, 13, 0, 0); LocalDateTime calcDate = may.minusMonths(1).plus(Period.ofYears(2)); System.out.println(calcDate.format(DateTimeFormatter.ofPattern("yyyy/MM/dd hh:mm:ss"))); Chronology jp = Chronology.of("Japanese"); ChronoLocalDate wareki = jp.date(may); System.out.printf( "%d年は%s %d年n",wareki.get(ChronoField.YEAR), wareki.getEra(), wareki.get(ChronoField.YEAR_OF_ERA));  Date/Calendarの置き換えを狙っているため、Date/Calendarとの変換メソッドは提供されない。  その割には、JDBCでは新APIにまた対応していない。 ULS – 日付・時間を表す- LocalDate(日付), LocalTime(時間), LocalDateTime/ZonedDataTime(日時) – 時間の量を表す- Duration(時間の量), Period(日付の量) – 日付・時間の計算メソッドに上記の量を渡して計算を行う。 – 1つの日時オブジェクトで時間の表現、時間計算、文字列変換ができる。(Data/Calendar間の変換不要) – 日時オブジェクトを様々な方法で作成できる。 – 月が1オリジン(1が1月)である。(Calendarは0が1月) – 和暦のようなロケールに応じた年代を表示できる。 – 日時オブジェクトは不変。計算結果は別オブジェクトになる。 – 新APIを使うのなら、Date/Calendarを一切使うなという意思表示。保守案件には無用の代物かもしれない。 Copyright © 2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 60 – 普及には時間がかかりそう。 日付の計算は新しい日時を生成する 和暦の出力例2014年はHeisei 26年と出力
  • 62.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 61 JVMまわり Java8には、JVMや周辺ツールの変更もある。 例えば – Sun JVM(Hotspot)とOracle JVM(jRockit)の統合 – パーマネント領域の廃止(-XX:PermSizeオプションが無効)  JVMオプションが色々と変更 – Javascirptエンジンの変更(Rhino → Nashorn) – APTの廃止 – Javadocツールの強化(コメントチェック、構文木生成) Java8へのアップデート案件では、プログラムの稼動確認だけでなく、JVMの 起動パラメータやパフォーマンスなんかも確認しておきましょう。 他にも – javacコマンドのバージョン指定(-source, -target)は3世代前までのみをサポー トするようになります。 – 現在のJDK8でもjava1.5以前向けのコンパイルは可能ですが、将来削除されると いう警告が発生します。
  • 63.
    ULS Copyright ©2011-2014 UL Systems, Inc. All rights reserved. Proprietary & Confidential Powered by 62 まとめ Java8は、Java5のジェネリクス追加に匹敵するアップデート  インターフェース実装、ラムダ式、Stream API 全て役に立ちます。 – 使いこなせる必要は無いですが、これらの要素はAPIのいたる所に出てくるので、 概要や使い方くらいは知っておくべき。 – 詳しく知るならJavadocを読むか、enterprisegeeksで。  是非、「何だかわからないからラムダ禁止」みたいな風潮と戦いましょう。 Java8採用にむけて訴求できそうなポイント – Stream APIで並列処理による高速化が容易になる。 – Stream APIを使って、省コードかつバグリにくく保守性が高いプログラムが作れる – Java7 のEOLは2015年4月

Editor's Notes

  • #32 ショートサーキットは使えるなら使う事。例えば集合が空かどうかを判定したいなら、findFirstで取得できるかでよい。Count > 0 は非効率。
  • #34 reduceは関数型プログラムの集合演算における基本テクニックの1つだが、java8ではcollectを使った方が見やすい。