Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
1
徹
底
解
説
!
Project Lambdaのすべて
2014/6/14 14:10-15:00
福岡Java8勉強会
吉田 真也(@bitter_fox)
InFuku
2
Who are you?
● 吉田真也(@bitter_fox)
● 職業: 学生
– 立命館大学 情報理工学部 情報システム学科
– 二回生
– 立命館コンピュータクラブ(RCC) 執行委員長(代表)
● http://www.rcc.r...
3
HashTag
#j8fk
4
JavaSE8
5
JavaSE8
Revolution
6
JavaSE8
Revolution
JavaSE5以来
(2004年)
7
JavaSE8
Revolution
JavaSE5以来
(2004年)
10年
ぶり
8
JavaSE8
Project Lambda
Revolution
JavaSE5以来
(2004年)
10年
ぶり
9
Project Lambda
● 並列処理を容易に書ける様に増強
– ライブラリ
– 言語
● StreamAPI(!=IOStream)の導入
● ラムダ式の導入
10
Why Project Lambda?
11
マルチコアCPU
12
マルチコアCPU
● CPU(ハード)のパラダイムシフト
– クロック数はそのまま
コア(数)を増やす
– 並列処理
● ソフトウェアにもパラダイムシフト
● 並列プログラミングにしないと性能をフルに利用で
きない
– アムダールの法則
13
アムダールの法則
90% 10%
90%
80% 20%
80%
5
%
1コア
1コア
∞コア
4コア
逐次処理 並列処理
14
現代的なアーキテクチャ
少しでも多くの部分で並列処理
15
並列処理ライブラリの歴史
java.lang.Thread
扱いが難しかった/大きな粒度
JavaSE5(J2SE 5.0)
Concurrency Utilities(java.util.concurrent.*)
簡単化/大きな粒度
...
16
ProjectLambda発足当時(JavaSE6〜JavaSE7)
小さな粒度向けのライブラリが無かった
JavaSE7後
小さな粒度向けのライブラリがあるものの使いづらい
17
マルチコアCPUの
台頭
マルチコアCPUコアライブラリ
18
ライブラリでは不十分
new Runnable(){
public void run(){
// proc
}
}
● 処理を分けるだけで5行
● いくらライブラリが良くても・・・
● 言語的に解決する必要がある
19
マルチコアCPUコアライブラリ
ラムダ式・メソッド参照
20
マルチコアCPUコアライブラリ
ラムダ式・メソッド参照
実質的にfinal
型推論の強化
交差型キャスト
21
ライブラリの増強
● 一度公開されたインターフェース
– 変更を加えにくい
– メソッド追加
● 具象クラスが追随する必要がある
– 実装の提供
22
マルチコアCPUコアライブラリ
ラムダ式・メソッド参照
実質的にfinal
型推論の強化
交差型キャスト
defaultメソッド
23
マルチコアCPUコアライブラリ
ラムダ式・メソッド参照
実質的にfinal
型推論の強化
交差型キャスト
defaultメソッド
stat. intf. メソッド
24
マルチコアCPUコアライブラリ
ラムダ式・メソッド参照
実質的にfinal
型推論の強化
交差型キャスト
defaultメソッド
stat. intf. メソッド
ラムダ式・メソッド参照
25
処理の分離のイディオム
new Runnable() {
public void run() {
//
}
}
26
処理の分離のイディオム
new Runnable() {
public void run() {
//
}
}
実装するべきメソッドが一つ
インターフェース
27
● 実装するべきメソッド(抽象メソッド)が一つ
● インターフェース
– java.lang.Runnable
– java.lang.Callable
– java.nio.file.PathMatcher
– java.awt.eve...
28
関数型インターフェース
● 実装するべきメソッド(抽象メソッド)が一つ
● インターフェース
– java.lang.Runnable
– java.lang.Callable
– java.nio.file.PathMatcher
– ...
29
関数型インターフェース
● 処理を分けるのに十分
● ライブラリの多くで利用されている
● 実装&インスタンス化する構文としてラムダ式
– 匿名クラスに代わる構文
30
関数型インターフェース?
interface F {
void f();
}
31
関数型インターフェース?
interface F {
void f();
}
● Yes!
32
関数型インターフェース?
interface F {
boolean equals(Object o);
}
33
関数型インターフェース?
interface F {
boolean equals(Object o);
}
● No!
● equalsはObjectクラスで定義されている
– インターフェースにおいて暗黙的なメソッド
抽象メソッドは0個
34
関数型インターフェース?
interface F {
Object clone();
}
35
関数型インターフェース?
interface F {
Object clone();
}
● Yes!
● cloneもObjectクラスで宣言されているが
protected
– Fではpublicで再宣言されている
36
関数型インターフェース(JLS9.8)
A functional interface is an interface that has just one abstract method, and thus represents a sin...
37
関数型インターフェース(JLS9.8)
A functional interface is an interface that has just one abstract method, and thus represents a sin...
38
@FunctionalInterface
● 関数型インターフェースかどうか検査する
– コンパイル時
@FunctionalInterface
interface F {
boolean equals(Object o);
}
39
@FunctionalInterface
● 関数型インターフェースかどうか検査する
– コンパイル時
@FunctionalInterface
interface F {
boolean equals(Object o);
} @Fun...
40
java.util.function.*
名前 第一引数 第二引数 戻り値
Consumer<T> T - void
Function<T, R> T - R
Predicate<T> T - boolean
Supplier<T> - ...
41
匿名クラスからラムダ式へ
this.addActionListener(
new ActionListener(){
public void actionPerformed(
ActionEvent ae) {
//
}
})
42
匿名クラスからラムダ式へ
this.addActionListener(
new ActionListener(){
public void actionPerformed(
ActionEvent ae) {
//
}
})
addAc...
43
匿名クラスからラムダ式へ
this.addActionListener(
new ActionListener(){
public void actionPerformed(
ActionEvent ae) {
//
}
})
実装するべ...
44
ラムダ式
this.addActionListener(
(ActionEvent ae) -> {
//
})
● (仮引数) -> {メソッド本体}
● (int n1, int n2) -> {return n1+n2;}
45
ラムダ式
● 関数型インターフェースをインスタンス化
● (仮引数) -> {メソッド本体}
– 型推論で型が決まる
● 関数型インターフェースのインスタンスが
予期される場面で利用可
– ターゲット型
46
ターゲット型が曖昧な場合
Object o = () -> {};
● () -> {}の型として
– Objectが予期される
– 関数型インターフェースが予期されない
– 何を実装したらいいのかわからない
47
ターゲット型が曖昧な場合
Object o = (Runnable)() -> {};
– キャストを用いる
– Runnableが予期される
– 実装するべきインターフェースが分かる
48
ラムダ式の引数
this.addActionListener(
(ActionEvent ae) -> {
//
})
49
ラムダ式の引数
this.addActionListener(
(ActionEvent ae) -> {
//
})
引数の型も一意に定ま
る
50
ラムダ式の引数
this.addActionListener(
(ae) -> {
//
})
● 引数の型も省略可
● (n1, n2) -> {return n1+n2;}
51
ラムダ式の引数
this.addActionListener(
(ae) -> {
//
})
引数が一つで型が推論される
場合の()は不要
52
ラムダ式の引数
this.addActionListener(
ae -> {
//
})
● 引数が一つで型が省略される場合()不要
● n1 -> {return n1+5;}
53
ラムダ式の引数と_
● ラムダ式の引数としての_はコンパイルエラー
this.addActionListener( _ -> {/**/} );
– 他の言語での_は特殊な意味
– 混乱を招かないように利用不可に
– 将来の利用を見据え予...
54
ラムダ式のメソッド本体
(int n) -> {return n + 5;}
(n) -> {return n + 5;}
n -> {return n + 5;}
55
ラムダ式のメソッド本体
(int n) -> {return n + 5;}
(n) -> {return n + 5;}
n -> {return n + 5;}
● return文のみ場合,return等を省略できる
(int n) ...
56
ラムダ式のメソッド本体
(ActionEvent ae) -> {apply(ae);}
(ae) -> {apply(ae);}
ae -> {apply(ae);}
57
ラムダ式のメソッド本体
(ActionEvent ae) -> {apply(ae);}
(ae) -> {apply(ae);}
ae -> {apply(ae);}
● 戻り値がvoidでも,{;}を省略できる場合がある
(Actio...
58
ラムダ式.equals(匿名クラス)?
● 違います!
– 匿名クラスのシンタックスシュガーではない
● 意味論も実装方法(OpenJDKの場合)も異なる
– 主にスコーピング規則
– 同じ部分もある
59
ラムダ式のスコーピング規則
1.ラムダ式内では外のスコープを引き継ぐ
2.常にアウタークラスのインスタンスを保持しない
– 匿名クラスなどとは大きく違う
3.ローカル変数の参照はfinalな変数のみ
– 匿名クラスと同様
– 注:実質的に...
60
1.外のスコープを引き継ぐ
class Main {
void method() {
Runnable r = () ->
System.out.println(this);
}
}
61
1.外のスコープを引き継ぐ
class Main {
void method() {
Runnable r = () ->
System.out.println(this);
}
}
● ラムダ式内のthis=エンクロージングクラス
62
1.外のスコープを引き継ぐ
class Main {
void method(int n) {
Runnable r = () -> {int n;};
}
}
63
1.外のスコープを引き継ぐ
class Main {
void method(int n) {
Runnable r = () -> {int n;};
}
}
● 多重定義
● コンパイルエラー
64
1.外のスコープを引き継ぐ
class Main {
void method(int n) {
Function<Integer, Integer> f =
n -> n + 5;
}
}
● 多重定義
● コンパイルエラー
65
2.アウタークラスへの参照
● 匿名クラス
– 常に保持
– メモリリークの危険性高
● ラムダ式
– 必要に応じて保持
66
2.アウタークラスへの参照
class Register {
void register(Processer p) {
p.add(new Func() {
public int f(int n) {return n * n;}
});
...
67
2.アウタークラスへの参照
class Register {
void register(Processer p) {
p.add(new Func() {
public int f(int n) {return n * n;}
});
...
68
2.アウタークラスへの参照
class Register {
void register(Processer p) {
p.add(n -> n * n);
}
}
69
2.アウタークラスへの参照
class Register {
void register(Processer p) {
p.add(n -> n * n);
}
}
Registerのインスタンスは保持しない
70
3.ローカル変数の参照
● 匿名クラスと同様
– finalな変数(実質的にfinal(後述)含む)
– 値の変更不可
71
ラムダ式の利用例
p -> p.getName()
s -> Integer.parseInt(s)
o -> list.add(o)
init -> new MyClass(init)
n -> new int[n]
● 引数を受け流す...
72
ラムダ式の利用例
p -> p.getName()
s -> Integer.parseInt(s)
o -> list.add(o)
init -> new MyClass(init)
n -> new int[n]
● 引数を受け流す...
73
メソッド・コンストラクタ参照
p -> p.getName()
s -> Integer.parseInt(s)
o -> list.add(o)
init -> new MyClass(init)
n -> new int[n]
● ク...
74
マルチコアCPUコアライブラリ
ラムダ式・メソッド参照
実質的にfinal
型推論の強化
交差型キャスト
defaultメソッド
stat. intf. メソッド
75
実質的にfinal(Effectively final)
● 匿名クラスやラムダ式で
実質的にfinalな変数への参照が可能に
– コンパイラがfinal性を推論
● 実質的にfinalな変数
– final修飾されていない変数
– fi...
76
実質的にfinalの例
void method(final int n) {
final String str = “HelloFinal”
Runnable r = new Runnable() {
public void run() ...
77
実質的にfinalの例
void method(int n) {
String str = “HelloEffectivelyFinal”
Runnable r = new Runnable() {
public void run() {...
78
実質的にfinalの例
void method(int n) {
String str = “HelloEffectivelyFinal”
Runnable r = () ->
System.out.println(str + n);
}
79
実質的にfinalでない例
void method(int n) {
Runnable r = () ->
System.out.println(n);
n = 5;
}
ラムダ式から参照されるローカル変数は、
finalまたは事実上のf...
80
実質的にfinalでない例
void method(int n) {
Runnable r = () -> n++;
}
ラムダ式から参照されるローカル変数は、
finalまたは事実上のfinalである必要があります
Runnable r...
81
マルチコアCPUコアライブラリ
ラムダ式・メソッド参照
実質的にfinal
型推論の強化
複合型キャスト
defaultメソッド
stat. intf. メソッド
82
型推論の強化
● ターゲット型推論の強化
1.適用可能箇所の拡大
2.より正確な推論
83
ターゲット型推論?
● ターゲット型に基づく型推論
● JavaSE5(5.0)から存在
– メソッドジェネリクスの実型引数
– ダイアモンド演算子(JavaSE7)
84
ターゲット型
● ある式の型として予期される型のこと
● List<Integer> l = new ArrayList<>();
– “new ArrayList<>()”のターゲット型はList<Integer>
85
ターゲット型が存在する文脈
● 変数宣言・・・ int n = …
● 割り当て・・・ n = …
● return文・・・ return …
● 配列初期化子・・・new String[]{...}
● 実引数・・・method(......
86
JavaSE7における適用可能箇所
メソッドジェネリクスの
実型引数
ダイアモンド演算子
変数宣言 ○ ○
割り当て ○ ○
return文 ○ ○
配列初期化子 ○ -
実引数 × ×
条件式 × ×
キャスト式 ○ ×
ラムダ式の本体
87
適用可能箇所の例(JavaSE7)
List<Integer> l = new ArrayList<>();
new ArrayList<T>()
new ArrayList<Integer>()
●
ArrayList<T> <: Li...
88
適用不可能箇所の例(JavaSE7)
● 実引数におけるターゲット型推論
printStrings(new ArrayList<>());
– void printStrings(List<String> l)
89
適用不可能箇所の例(JavaSE7)
● 実引数におけるターゲット型推論
printStrings(new ArrayList<Object>());
– void printStrings(List<String> l)
● コンパイル...
90
適用不可能箇所の例(JavaSE7)
● 条件式におけるターゲット型推論
List<Integer> list = bool ?
Collections.emptyList() :
new ArrayList<>();
91
適用不可能箇所の例(JavaSE7)
● 条件式におけるターゲット型推論
List<Integer> list = bool ?
Collections.<Object>emptyList() :
new ArrayList<Object...
92
JavaSE8における適用可能箇所
メソッドジェネリクスの
実型引数
ダイアモンド演算子
変数宣言 ○ ○
割り当て ○ ○
return文 ○ ○
配列初期化子 ○ -
実引数 ○ ○
条件式 ○ ○
キャスト式 ○ ×?bug?(3/...
93
適用可能になった例(JavaSE8)
● 実引数におけるターゲット型推論
printStrings(new ArrayList<>());
– void printStrings(List<String> l)
94
適用可能になった例(JavaSE8)
● 実引数におけるターゲット型推論
printStrings(new ArrayList<String>());
– void printStrings(List<String> l)
● 推論器が正...
95
適用可能になった例(JavaSE8)
● 条件式におけるターゲット型推論
List<Integer> list = bool ?
Collections.emptyList() :
new ArrayList<>();
96
適用可能になった例(JavaSE8)
● 条件式におけるターゲット型推論
List<Integer> list = bool ?
Collections.<Integer>emptyList() :
new ArrayList<Integ...
97
JavaSE8における適用可能箇所
ラムダ式・メソッド参照
変数宣言 ○
割り当て ○
return文 ○
配列初期化子 ○
実引数 ○
条件式 ○
キャスト式 ○
ラムダ式の本体 ○
98
2.より正確な推論
● 今までは簡易的な推論
● しばしば不正確な推論によりコンパイルエラー
– 複雑な場合
99
JavaSE7以前の推論
1.実引数の式の型を優先
2.実引数がない場合はターゲット型
100
ターゲット型推論が働く例
List<Number> list =
Arrays.asList();
java.util.Arrays#<T> List<T> asList(T...)
●
List<Number> =:= List<T>...
101
不正確な推論の例(JavaSE7)
List<Number> list =
Arrays.asList(2, 5.5);
java.util.Arrays#<T> List<T> asList(T...)
102
不正確な推論の例(JavaSE7)
List<Number> list =
Arrays.<T>asList(2, 5.5);
●
T<:Object, T :>Integer,T:>Double(実引数より)
– T=:=Number...
103
不正確な推論の例(JavaSE7)
List<Number> list =
Arrays.<Number & Comparable<...>>asList(2, 5.5);
● コンパイルエラー
– Number & Comparabl...
104
JavaSE8以降の推論
● 実引数の型とターゲット型を加味
– グラフ推論
– より正確な型推論へ
105
先の例(JavaSE8の場合)
List<Number> list =
Arrays.asList(2, 5.5);
106
先の例(JavaSE8の場合)
List<Number> list =
Arrays.<T>asList(2, 5.5);
●
T<:Object, T :>Integer,T:>Double(実引数より)
●
T=Number(ターゲ...
107
先の例(JavaSE8の場合)
List<Number> list =
Arrays.<Number>asList(2, 5.5);
● 正しく推論器が働く
– Numberと推論される
108
マルチコアCPUコアライブラリ
ラムダ式・メソッド参照
実質的にfinal
型推論の強化
交差型キャスト
defaultメソッド
stat. intf. メソッド
109
型キャスト
キャスト式に交差型を
110
交差型?
● Intersection Type
● JavaSE5(5.0)から存在
– ジェネリクスの型境界(@型仮引数)
– <T extends Runnable & Cloneable>
● RunnableとCloneabl...
111
交差型キャスト
● (型 & 型 & … & 型)式
● 主にラムダ式・メソッド参照と使用する
112
もしも交差型キャストがなかったら
● SerializableでRunnableなインターフェース
– 関数型インターフェース
– ラムダ式でインスタンス化したい
– インターフェースを定義する必要がある
113
もしも交差型キャストがなかったら
interface SRunnable implements
Runnable, Serializeable {}
sendRunnable((SRunnable) () -> {/* */});
114
もしも交差型キャストがなかったら
interface SRunnable implements
Runnable, Serializeable {}
sendRunnable((SRunnable) () -> {/* */});
115
交差型キャスト+ラムダ式
sendRunnable((Runnable & Serializable)
() -> {/* */});
● 型合成される
116
マルチコアCPUコアライブラリ
ラムダ式・メソッド参照
実質的にfinal
型推論の強化
交差型キャスト
defaultメソッド
stat. intf. メソッド
117
<interface>
PublishedInterface
+already()
+exist()
+methods()
118
<interface>
PublishedInterface
+already()
+exist()
+methods()
ReferenceImpl
+already()
+exist()
+methods()
AnotherImpl...
119
<interface>
PublishedInterface
+already()
+exist()
+methods()
+newMethod()
ReferenceImpl
+already()
+exist()
+methods(...
120
<interface>
PublishedInterface
+already()
+exist()
+methods()
+newMethod()
ReferenceImpl
+already()
+exist()
+methods(...
121
インターフェースに拡張性を
● 新しいメソッドを加えても互換性を保つ
● デフォルトメソッド
– デフォルトの実装を提供する
– インターフェースに実装
– 実装が提供されない場合に使用される
122
デフォルトメソッド
interface Person {
Sex getSex();
default boolean isMan() {
return getSex() == Sex.MAN;
}
}
123
デフォルトメソッド
class PersonImpl implements Person {
public Sex getSex() {/*...*/}
// isManへの実装はなくてもOK
// Person#isManが使われる
}
124
デフォルトメソッド
class PersonImpl implements Person {
public Sex getSex() {/*...*/}
public boolean isMan() {/*...*/}
}
● オーバー...
125
デフォルトメソッド
● default修飾子
● publicメソッドとなる
– 既存のインターフェースメソッドと同様
● strictfp修飾のみ可
● 具象クラスで実装が提供されなくても無問題
● 拡張性を実現できた
– 新たな問題...
126
実装の多重継承問題
127
多重継承
class BasicPerson {
public boolean isMan() {/*...*/}
}
class ComplexPerson extends BasicPerson
implements Person ...
128
多重継承
BasicPerson
#isMan
Person
#isMan
ComplexPerson
#isMan
129
“Class always win”
130
クラスで定義された実装が
常に勝つ
131
Class always win
class BasicPerson {
public boolean isMan() {/*...*/}
}
class ComplexPerson extends BasicPerson implem...
132
親インターフェースの呼び出し
class ComplexPerson extends BasicPerson
implements Person {
public Sex getSex() {/*...*/}
public boolea...
133
クラスを介さない多重継承
interface Base1 {default void m() {}}
134
クラスを介さない多重継承
interface Base1 {default void m() {}}
interface Base2 {default void m() {}}
135
クラスを介さない多重継承
interface Base1 {default void m() {}}
interface Base2 {default void m() {}}
interface ExBase extends Base...
136
多重継承
Base1#m Base2#m
ExBase#m
137
クラスを介さない多重継承
interface ExBase extends
Base1, Base2 {}
● コンパイルエラー
– オーバーライドして選択
138
クラスを介さない多重継承
interface ExBase extends
Base1, Base2 {
default void m() {
Base1.super.m();
}
}
139
多重継承は怖くない!!
● 大原則1:Class always win
– クラスで定義された実装が常に勝つ
● 大原則2:いつでもオーバーライドできる
– 親クラスでfinal修飾されてたら別
– インターフェースの実装を呼べる
140
Objectメソッドのデフォルトメソッド
● Objectで定義されたpublicメソッド
– そもそもデフォルトの実装
● Objectのpublicメソッドのデフォルトメソッドは不可
– interface I {default S...
141
マルチコアCPUコアライブラリ
ラムダ式・メソッド参照
実質的にfinal
型推論の強化
交差型キャスト
defaultメソッド
stat. intf. メソッド
142
staticインターフェースメソッド
● staticなインターフェースメソッド
● 常にpublic修飾
– 他のインターフェースのメソッドと同様
● strictfp修飾可
– デフォルト実装と同様
143
staticインターフェースメソッドの例
interface Example {
static void method() {/* */}
}
144
staticインターフェースメソッドの例
interface Example {
static strictfp void method() {/* */}
}
● strictfp修飾可
145
staticインターフェースメソッドの継承
● 継承されない
– クラスメソッドと大きく違う
interface Example2 extends Example {}
Example2.method()はコンパイルエラー
146
Interesting Example
● publicでstaticなメソッド
– 人生で最初に書いたメソッド
147
Interesting Example
● publicでstaticなメソッド
– 人生で最初に書いたメソッド
public static void main(
String[] args)
148
main in Interface
interface EntryPoint {
public static void main(String[] args) {
/* ... */
}
}
● 正しく動く
149
マルチコアCPUコアライブラリ
ラムダ式・メソッド参照
実質的にfinal
型推論の強化
交差型キャスト
defaultメソッド
stat. intf. メソッド
150
Library Enhancements
StreamAPI
IO/NIOJCF
Optional
And
More...
151
Library Enhancements
StreamAPI
IO/NIOJCF
Optional
And
More...
152
No more 外部イテレーション
● 外部イテレーションは並列化困難
● 内部イテレーションベースのライブラリへ
– 並列化が容易に
153
外部イテレーション
● イテレーションが外にさらされている
– for,while文
for (Student s : students) {
}
154
内部イテレーションライブラリ
StreamAPI
155
StreamAPI
java.util.stream.
● Stream
● IntStream
● LongStream
● DoubleStream
– ソースから生成される
– 中間操作と終端操作でデータを弄る
– 並列化が容易
156
Collection
配列
BufferReader
etc...
Stream
IntStream
LongStream
DoubleStream
中間操作
終端操作
j.u.stream.*Source
157
Collection
配列
BufferReader
etc...
Stream
IntStream
LongStream
DoubleStream
中間操作
終端操作
j.u.stream.*Source
158
Make Streams
ソース メソッド 使用例
Collection Collection#stream list.stream()
配列 Arrays#stream Arrays.stream(args)
BufferedRead...
159
Collection
配列
BufferReader
etc...
Stream
IntStream
LongStream
DoubleStream
中間操作
終端操作
j.u.stream.*Source
160
java.util.stream.
StreamAPI 要素の型
Stream<T> T(参照型)
IntStream int(プリミティブ型)
LongStream long(プリミティブ型)
DoubleStream double(...
161
2 types of Stream
Sequential Stream
Parallel Stream
162
Change the type of Stream
Sequential Stream
Parallel Stream
parallel() sequential()
163
Collection
配列
BufferReader
etc...
Stream
IntStream
LongStream
DoubleStream
中間操作
終端操作
j.u.stream.*Source
164
中間操作?
● filterやmapなど
– Streamを返すメソッド
● 終端操作が行われるまで処理されない
– 遅延される
165
主要な中間操作
メソッド名 概要 使用例
filter フィルタリング s.filter(n -> n % 2 == 0)
map 写像・変換 s.map(p -> p.getName())
flatMap 写像・変換&平坦化 s.fl...
166
Collection
配列
BufferReader
etc...
Stream
IntStream
LongStream
DoubleStream
非終端操作
終端操作
j.u.stream.*Source
167
終端操作?
● forEachやreduceやcollectなど
– Streamを返さないメソッド
● 遅延されていた中間操作を確定
168
主要な終端操作
メソッド名 概要 使用例
forEach 反復処理 s.forEach(e -> System.out.println(e))
reduce 畳み込み演算 s.reduce(1, (n1, n2) -> n1 * n2)...
169
0から10まで出力したい
for (int i = 0; i <= 10; i++) {
System.out.println(i);
}
170
forEach[終端操作]
T->void[j.u.function.Consumer<T>#void accept(T)]
● forEach(T -> void)
– 各要素に引数で渡した処理を行なう
– s.forEach(t -...
171
0から10まで出力したい
for (int i = 0; i <= 10; i++) {
System.out.println(i);
}
IntStream.rangeClose(0, 10)
.forEach(i -> System...
172
0から10まで出力したい
for (int i = 0; i <= 10; i++) {
System.out.println(i);
}
IntStream.rangeClose(0, 10)
.forEach(System.out:...
173
0から10までの偶数を出力したい
for (int i = 0; i <= 10; i++) {
if (i % 2 == 0) {
System.out.println(i);
}
}
174
filter[中間操作]
● filter(T -> boolean)
– フィルタリング
– 各要素を引数に適用しtrueを返したもののみ残す
– s.filter(Objects::nonNull) // nullを除外
175
filter[中間操作]
T->boolean[j.u.function.Predicate<T>#boolean test(T)]
176
0から10までの偶数を出力したい
IntStream.rangeClose(0, 10)
.filter(i -> i % 2 == 0)
.forEach(System.out::println);
177
Personのリストから名前を出力
for (Person p : persons) {
System.out.println(p.getName());
}
178
map[中間操作]
● map(T -> R)
– 写像・変換
– 各要素を引数に適用した結果のStreamを作る
– personStream.map(p -> p.getName())
179
map[中間操作]
T -> R[java.util.function.Function<T, R>#R map(T)]
R
180
Personのリストから名前を出力
persons.stream()
.map(p -> p.getName())
.forEach(n -> System.out.println(n));
181
Personのリストから名前を出力
persons.stream()
.map(Person::getName)
.forEach(System.out::println);
182
Streamを横断するmap
Stream<T> IntStream
LongStream DoubleStream
#mapToObj
#mapToInt
#mapToLong
#mapToDouble
#mapToDouble
#m...
183
Personのリストから名前のリスト
List<String> names = new ArrayList<>();
for (Person p : persons) {
names.add(p.getName());
}
184
collect[終端処理]
● collect(Collector<T, R>)
● collect(() -> R, (R, T) -> void, (R, R) -> void)
– 集約処理を行なう
– stream.collec...
185
Personのリストから名前のリスト
persons.stream()
.map(Person::getName)
.collect(Collectors.toList())
186
Sequential
collect(SB::new, SB::append, SB::append)
H e l l o , W o r l d !
187
H e l l o , W o r l d !
SB
Sequential
collect(SB::new, SB::append, SB::append)
188
H e l l o , W o r l d !
SB
Sequential
collect(SB::new, SB::append, SB::append)
189
H e l l o , W o r l d !
SB
Sequential
collect(SB::new, SB::append, SB::append)
190
Parallel
collect(SB::new, SB::append, SB::append)
H e l l o , W o r l d !
191
Parallel
collect(SB::new, SB::append, SB::append)
H e l l o , W o r l d !
Split!!
192
Parallel
collect(SB::new, SB::append, SB::append)
H e l l o , W o r l d !
193
Parallel
collect(SB::new, SB::append, SB::append)
H e l l o , W o r l d !
He Wo
194
Parallel
collect(SB::new, SB::append, SB::append)
H e l l o , W o r l d !
He Wo
195
Parallel
collect(SB::new, SB::append, SB::append)
H e l l o , W o r l d !
He Wo
196
Parallel
collect(SB::new, SB::append, SB::append)
H e l l o , W o r l d !
He WoSBll SBd!
197
Parallel
collect(SB::new, SB::append, SB::append)
H e l l o , W o r l d !
He WoSBll SBd!
198
Parallel
collect(SB::new, SB::append, SB::append)
H e l l o , W o r l d !
Hell Wo SBd!
199
Parallel
collect(SB::new, SB::append, SB::append)
H e l l o , W o r l d !
Hell Wo SBd!
200
Parallel
collect(SB::new, SB::append, SB::append)
H e l l o , W o r l d !
Hell Wo SBd!SBo, SBrl
201
Parallel
collect(SB::new, SB::append, SB::append)
H e l l o , W o r l d !
Hell Wo SBd!SBo, SBrl
202
Parallel
collect(SB::new, SB::append, SB::append)
H e l l o , W o r l d !
Hello, Worl SBd!
203
Parallel
collect(SB::new, SB::append, SB::append)
H e l l o , W o r l d !
Hello, Worl SBd!
204
Parallel
collect(SB::new, SB::append, SB::append)
H e l l o , W o r l d !
Hello,Worl SBd!
205
Parallel
collect(SB::new, SB::append, SB::append)
H e l l o , W o r l d !
Hello,Worl SBd!
206
Parallel
collect(SB::new, SB::append, SB::append)
H e l l o , W o r l d !
Hello,World!
207
Putting it together
学生のリスト(students)の内
2年生で
GPAが3.5以上ある学生の
学籍番号の
リストを生成する
208
Putting it together
List<StudentID> list = new ArrayList<>();
for (Student s : students) {
if (s.getGrade() == 2 &&
s....
209
Putting it together
学生のリスト(students)の内
2年生で
GPAが3.5以上ある学生の
学籍番号の
リストを生成する
210
Putting it together
students.stream()
2年生で
GPAが3.5以上ある学生の
学籍番号の
リストを生成する
211
Putting it together
students.stream()
.filter(s -> s.getGrade() == 2)
GPAが3.5以上ある学生の
学籍番号の
リストを生成する
212
Putting it together
students.stream()
.filter(s -> s.getGrade() == 2)
.filter(s -> s.getGPA() >= 3.5)
学籍番号の
リストを生成する
213
Putting it together
students.stream()
.filter(s -> s.getGrade() == 2)
.filter(s -> s.getGPA() >= 3.5)
.map(Student::ge...
214
Putting it together
students.stream()
.filter(s -> s.getGrade() == 2)
.filter(s -> s.getGPA() >= 3.5)
.map(Student::ge...
215
Putting it together
students.stream().parallel()
.filter(s -> s.getGrade() == 2)
.filter(s -> s.getGPA() >= 3.5)
.map(...
216
Project Lambdaまとめ
● もともとはマルチコア対応
● 結果としては汎用的な仕様に
– ラムダ式等
– コアライブラリ
● よりスマートなコードへ
217
Thank you for your listening
Enjoy JavaSE8
Upcoming SlideShare
Loading in …5
×
Upcoming SlideShare
from old java to java8 - KanJava Edition
Next
Download to read offline and view in fullscreen.

13

Share

Download to read offline

徹底解説!Project Lambdaのすべて in Fukuoka #j8fk

Download to read offline

福岡Java8勉強会で発表させていただいた時の資料です.

Related Books

Free with a 30 day trial from Scribd

See all

徹底解説!Project Lambdaのすべて in Fukuoka #j8fk

  1. 1. 1 徹 底 解 説 ! Project Lambdaのすべて 2014/6/14 14:10-15:00 福岡Java8勉強会 吉田 真也(@bitter_fox) InFuku
  2. 2. 2 Who are you? ● 吉田真也(@bitter_fox) ● 職業: 学生 – 立命館大学 情報理工学部 情報システム学科 – 二回生 – 立命館コンピュータクラブ(RCC) 執行委員長(代表) ● http://www.rcc.ritsumei.ac.jp/
  3. 3. 3 HashTag #j8fk
  4. 4. 4 JavaSE8
  5. 5. 5 JavaSE8 Revolution
  6. 6. 6 JavaSE8 Revolution JavaSE5以来 (2004年)
  7. 7. 7 JavaSE8 Revolution JavaSE5以来 (2004年) 10年 ぶり
  8. 8. 8 JavaSE8 Project Lambda Revolution JavaSE5以来 (2004年) 10年 ぶり
  9. 9. 9 Project Lambda ● 並列処理を容易に書ける様に増強 – ライブラリ – 言語 ● StreamAPI(!=IOStream)の導入 ● ラムダ式の導入
  10. 10. 10 Why Project Lambda?
  11. 11. 11 マルチコアCPU
  12. 12. 12 マルチコアCPU ● CPU(ハード)のパラダイムシフト – クロック数はそのまま コア(数)を増やす – 並列処理 ● ソフトウェアにもパラダイムシフト ● 並列プログラミングにしないと性能をフルに利用で きない – アムダールの法則
  13. 13. 13 アムダールの法則 90% 10% 90% 80% 20% 80% 5 % 1コア 1コア ∞コア 4コア 逐次処理 並列処理
  14. 14. 14 現代的なアーキテクチャ 少しでも多くの部分で並列処理
  15. 15. 15 並列処理ライブラリの歴史 java.lang.Thread 扱いが難しかった/大きな粒度 JavaSE5(J2SE 5.0) Concurrency Utilities(java.util.concurrent.*) 簡単化/大きな粒度 JavaSE7 Fork/Join Framework 小さな粒度/やや難
  16. 16. 16 ProjectLambda発足当時(JavaSE6〜JavaSE7) 小さな粒度向けのライブラリが無かった JavaSE7後 小さな粒度向けのライブラリがあるものの使いづらい
  17. 17. 17 マルチコアCPUの 台頭 マルチコアCPUコアライブラリ
  18. 18. 18 ライブラリでは不十分 new Runnable(){ public void run(){ // proc } } ● 処理を分けるだけで5行 ● いくらライブラリが良くても・・・ ● 言語的に解決する必要がある
  19. 19. 19 マルチコアCPUコアライブラリ ラムダ式・メソッド参照
  20. 20. 20 マルチコアCPUコアライブラリ ラムダ式・メソッド参照 実質的にfinal 型推論の強化 交差型キャスト
  21. 21. 21 ライブラリの増強 ● 一度公開されたインターフェース – 変更を加えにくい – メソッド追加 ● 具象クラスが追随する必要がある – 実装の提供
  22. 22. 22 マルチコアCPUコアライブラリ ラムダ式・メソッド参照 実質的にfinal 型推論の強化 交差型キャスト defaultメソッド
  23. 23. 23 マルチコアCPUコアライブラリ ラムダ式・メソッド参照 実質的にfinal 型推論の強化 交差型キャスト defaultメソッド stat. intf. メソッド
  24. 24. 24 マルチコアCPUコアライブラリ ラムダ式・メソッド参照 実質的にfinal 型推論の強化 交差型キャスト defaultメソッド stat. intf. メソッド ラムダ式・メソッド参照
  25. 25. 25 処理の分離のイディオム new Runnable() { public void run() { // } }
  26. 26. 26 処理の分離のイディオム new Runnable() { public void run() { // } } 実装するべきメソッドが一つ インターフェース
  27. 27. 27 ● 実装するべきメソッド(抽象メソッド)が一つ ● インターフェース – java.lang.Runnable – java.lang.Callable – java.nio.file.PathMatcher – java.awt.event.ActionListener – java.swing.event.ChangeListner – ...
  28. 28. 28 関数型インターフェース ● 実装するべきメソッド(抽象メソッド)が一つ ● インターフェース – java.lang.Runnable – java.lang.Callable – java.nio.file.PathMatcher – java.awt.event.ActionListener – java.swing.event.ChangeListner – ...
  29. 29. 29 関数型インターフェース ● 処理を分けるのに十分 ● ライブラリの多くで利用されている ● 実装&インスタンス化する構文としてラムダ式 – 匿名クラスに代わる構文
  30. 30. 30 関数型インターフェース? interface F { void f(); }
  31. 31. 31 関数型インターフェース? interface F { void f(); } ● Yes!
  32. 32. 32 関数型インターフェース? interface F { boolean equals(Object o); }
  33. 33. 33 関数型インターフェース? interface F { boolean equals(Object o); } ● No! ● equalsはObjectクラスで定義されている – インターフェースにおいて暗黙的なメソッド 抽象メソッドは0個
  34. 34. 34 関数型インターフェース? interface F { Object clone(); }
  35. 35. 35 関数型インターフェース? interface F { Object clone(); } ● Yes! ● cloneもObjectクラスで宣言されているが protected – Fではpublicで再宣言されている
  36. 36. 36 関数型インターフェース(JLS9.8) A functional interface is an interface that has just one abstract method, and thus represents a single function contract. (In some cases, this "single" method may take the form of multiple abstract methods with override-equivalent signatures (8.4.2) inherited from superinterfaces; in this case, the inherited methods logically represent a single method.) More precisely, for interface I, let M be the set of abstract methods that are members of I but that do not have the same signature as any public instance method of the class Object. Then I is a functional interface if there exists a method m in M for which the following conditions hold: The signature of m is a subsignature (8.4.2) of every method's signature in M. m is return-type-substitutable (8.4.5) for every method in M. In addition to the usual process of creating an interface instance by declaring (8.1) and instantiating (15.9) a class, instances of functional interfaces can be created with lambda expressions (15.27), method references (15.28), or constructor references. The function descriptor of a functional interface I is a method type (8.2) that can be used to legally override (8.4.8) the abstract method(s) of I. Let M be the set of abstract methods defined above for I. The descriptor of I consists of the following: Type parameters, formal parameters, and return types: Let m be a method in M with i) a signature that is a subsignature of every method's signature in M and ii) a return type that is a subtype of every method's return type in M (after adapting for any type parameters (8.4.4)); if no such method exists, then let m be a method in M that i) has a signature that is a subsignature of every method's signature in M and ii) is return-type-substitutable for every method in M. Then the descriptor's type parameters, formal parameter types, and return type are as given by m. Thrown types: The descriptor's thrown types are derived from the throws clauses of the methods in M. If the descriptor is generic, these clauses are first adapted to the type parameters of the descriptor (8.4.4); if the descriptor is not generic but at least one method in M is, these clauses are first erased. Then the descriptor's thrown types include every type, E, satisfying the following constraints: E is mentioned in one of the throws clauses. For each throws clause, E is a subtype of some type named in that clause. A functional interface type is one of the following: A functional interface A parameterization (4.5) of a functional interface An intersection (4.9) of interface types that meets the following criteria: Exactly one element of the intersection is a functional interface, or a parameterization of a functional interface. Let F be this interface. A notional interface, I, that extends all the interfaces in the intersection would be a functional interface. If any of the intersection elements is a parameterized type, then I is generic: for each element of the intersection that is a parameterized type J<A1...An>, let P1...Pn be the type parameters of J; then P1...Pn are also type parameters of I, and I extends the type J<P1...Pn>. The function descriptor of I is the same as the function descriptor of F. The function descriptor of a parameterized functional interface, F<A1...An>, where A1...An are type arguments (4.5.1), is derived as follows. Let P1...Pn be the type parameters of F; types T1...Tn are derived from the type arguments according to the following rules (for 1 ≤ i ≤ n): If Ai is a type, then Ti = Ai. If Ai is a upper-bounded wildcard ? extends Ui, then Ti = Ui. If Ai is a lower-bounded wildcard ? super Li, then Ti = Li. If Ai is an unbound wildcard ?, then if Pi has upper bound Bi that mentions none of P1...Pn, then Ti = Bi; otherwise, Ti = Object. If F<T1...Tn> is a well-formed type, then the descriptor of F<A1...An> is the result of applying substitution [P1:=T1, ..., Pn:=Tn] to the descriptor of interface F. Otherwise, the descriptor of F<A1...An> is undefined. The function descriptor of an intersection that is a functional interface type is the same as the function descriptor of the functional interface or parameterization of a functional interface that is an element of the intersection.
  37. 37. 37 関数型インターフェース(JLS9.8) A functional interface is an interface that has just one abstract method, and thus represents a single function contract. (In some cases, this "single" method may take the form of multiple abstract methods with override-equivalent signatures (8.4.2) inherited from superinterfaces; in this case, the inherited methods logically represent a single method.) More precisely, for interface I, let M be the set of abstract methods that are members of I but that do not have the same signature as any public instance method of the class Object. Then I is a functional interface if there exists a method m in M for which the following conditions hold: The signature of m is a subsignature (8.4.2) of every method's signature in M. m is return-type-substitutable (8.4.5) for every method in M. In addition to the usual process of creating an interface instance by declaring (8.1) and instantiating (15.9) a class, instances of functional interfaces can be created with lambda expressions (15.27), method references (15.28), or constructor references. The function descriptor of a functional interface I is a method type (8.2) that can be used to legally override (8.4.8) the abstract method(s) of I. Let M be the set of abstract methods defined above for I. The descriptor of I consists of the following: Type parameters, formal parameters, and return types: Let m be a method in M with i) a signature that is a subsignature of every method's signature in M and ii) a return type that is a subtype of every method's return type in M (after adapting for any type parameters (8.4.4)); if no such method exists, then let m be a method in M that i) has a signature that is a subsignature of every method's signature in M and ii) is return-type-substitutable for every method in M. Then the descriptor's type parameters, formal parameter types, and return type are as given by m. Thrown types: The descriptor's thrown types are derived from the throws clauses of the methods in M. If the descriptor is generic, these clauses are first adapted to the type parameters of the descriptor (8.4.4); if the descriptor is not generic but at least one method in M is, these clauses are first erased. Then the descriptor's thrown types include every type, E, satisfying the following constraints: E is mentioned in one of the throws clauses. For each throws clause, E is a subtype of some type named in that clause. A functional interface type is one of the following: A functional interface A parameterization (4.5) of a functional interface An intersection (4.9) of interface types that meets the following criteria: Exactly one element of the intersection is a functional interface, or a parameterization of a functional interface. Let F be this interface. A notional interface, I, that extends all the interfaces in the intersection would be a functional interface. If any of the intersection elements is a parameterized type, then I is generic: for each element of the intersection that is a parameterized type J<A1...An>, let P1...Pn be the type parameters of J; then P1...Pn are also type parameters of I, and I extends the type J<P1...Pn>. The function descriptor of I is the same as the function descriptor of F. The function descriptor of a parameterized functional interface, F<A1...An>, where A1...An are type arguments (4.5.1), is derived as follows. Let P1...Pn be the type parameters of F; types T1...Tn are derived from the type arguments according to the following rules (for 1 ≤ i ≤ n): If Ai is a type, then Ti = Ai. If Ai is a upper-bounded wildcard ? extends Ui, then Ti = Ui. If Ai is a lower-bounded wildcard ? super Li, then Ti = Li. If Ai is an unbound wildcard ?, then if Pi has upper bound Bi that mentions none of P1...Pn, then Ti = Bi; otherwise, Ti = Object. If F<T1...Tn> is a well-formed type, then the descriptor of F<A1...An> is the result of applying substitution [P1:=T1, ..., Pn:=Tn] to the descriptor of interface F. Otherwise, the descriptor of F<A1...An> is undefined. The function descriptor of an intersection that is a functional interface type is the same as the function descriptor of the functional interface or parameterization of a functional interface that is an element of the intersection. @ FunctionalInterface
  38. 38. 38 @FunctionalInterface ● 関数型インターフェースかどうか検査する – コンパイル時 @FunctionalInterface interface F { boolean equals(Object o); }
  39. 39. 39 @FunctionalInterface ● 関数型インターフェースかどうか検査する – コンパイル時 @FunctionalInterface interface F { boolean equals(Object o); } @FunctionalInterface ^ Fは機能インタフェースではありません インタフェース Fで抽象メソッドが見つかりません エラー1個
  40. 40. 40 java.util.function.* 名前 第一引数 第二引数 戻り値 Consumer<T> T - void Function<T, R> T - R Predicate<T> T - boolean Supplier<T> - - T BiConsumer<T, U> T U void BiFunction<T, U, R> T U R BiPredicate<T, R> T U boolean
  41. 41. 41 匿名クラスからラムダ式へ this.addActionListener( new ActionListener(){ public void actionPerformed( ActionEvent ae) { // } })
  42. 42. 42 匿名クラスからラムダ式へ this.addActionListener( new ActionListener(){ public void actionPerformed( ActionEvent ae) { // } }) addActionListenerの引 数から推論できる
  43. 43. 43 匿名クラスからラムダ式へ this.addActionListener( new ActionListener(){ public void actionPerformed( ActionEvent ae) { // } }) 実装するべきメソッド も一意に定まる
  44. 44. 44 ラムダ式 this.addActionListener( (ActionEvent ae) -> { // }) ● (仮引数) -> {メソッド本体} ● (int n1, int n2) -> {return n1+n2;}
  45. 45. 45 ラムダ式 ● 関数型インターフェースをインスタンス化 ● (仮引数) -> {メソッド本体} – 型推論で型が決まる ● 関数型インターフェースのインスタンスが 予期される場面で利用可 – ターゲット型
  46. 46. 46 ターゲット型が曖昧な場合 Object o = () -> {}; ● () -> {}の型として – Objectが予期される – 関数型インターフェースが予期されない – 何を実装したらいいのかわからない
  47. 47. 47 ターゲット型が曖昧な場合 Object o = (Runnable)() -> {}; – キャストを用いる – Runnableが予期される – 実装するべきインターフェースが分かる
  48. 48. 48 ラムダ式の引数 this.addActionListener( (ActionEvent ae) -> { // })
  49. 49. 49 ラムダ式の引数 this.addActionListener( (ActionEvent ae) -> { // }) 引数の型も一意に定ま る
  50. 50. 50 ラムダ式の引数 this.addActionListener( (ae) -> { // }) ● 引数の型も省略可 ● (n1, n2) -> {return n1+n2;}
  51. 51. 51 ラムダ式の引数 this.addActionListener( (ae) -> { // }) 引数が一つで型が推論される 場合の()は不要
  52. 52. 52 ラムダ式の引数 this.addActionListener( ae -> { // }) ● 引数が一つで型が省略される場合()不要 ● n1 -> {return n1+5;}
  53. 53. 53 ラムダ式の引数と_ ● ラムダ式の引数としての_はコンパイルエラー this.addActionListener( _ -> {/**/} ); – 他の言語での_は特殊な意味 – 混乱を招かないように利用不可に – 将来の利用を見据え予約語に ● それ以外の_は警告に
  54. 54. 54 ラムダ式のメソッド本体 (int n) -> {return n + 5;} (n) -> {return n + 5;} n -> {return n + 5;}
  55. 55. 55 ラムダ式のメソッド本体 (int n) -> {return n + 5;} (n) -> {return n + 5;} n -> {return n + 5;} ● return文のみ場合,return等を省略できる (int n) -> n + 5 (n) -> n + 5 n -> n + 5
  56. 56. 56 ラムダ式のメソッド本体 (ActionEvent ae) -> {apply(ae);} (ae) -> {apply(ae);} ae -> {apply(ae);}
  57. 57. 57 ラムダ式のメソッド本体 (ActionEvent ae) -> {apply(ae);} (ae) -> {apply(ae);} ae -> {apply(ae);} ● 戻り値がvoidでも,{;}を省略できる場合がある (ActionEvent ae) -> apply(ae) (ae) -> apply(ae) ae -> apply(ae)
  58. 58. 58 ラムダ式.equals(匿名クラス)? ● 違います! – 匿名クラスのシンタックスシュガーではない ● 意味論も実装方法(OpenJDKの場合)も異なる – 主にスコーピング規則 – 同じ部分もある
  59. 59. 59 ラムダ式のスコーピング規則 1.ラムダ式内では外のスコープを引き継ぐ 2.常にアウタークラスのインスタンスを保持しない – 匿名クラスなどとは大きく違う 3.ローカル変数の参照はfinalな変数のみ – 匿名クラスと同様 – 注:実質的にfinal(後ほど説明)
  60. 60. 60 1.外のスコープを引き継ぐ class Main { void method() { Runnable r = () -> System.out.println(this); } }
  61. 61. 61 1.外のスコープを引き継ぐ class Main { void method() { Runnable r = () -> System.out.println(this); } } ● ラムダ式内のthis=エンクロージングクラス
  62. 62. 62 1.外のスコープを引き継ぐ class Main { void method(int n) { Runnable r = () -> {int n;}; } }
  63. 63. 63 1.外のスコープを引き継ぐ class Main { void method(int n) { Runnable r = () -> {int n;}; } } ● 多重定義 ● コンパイルエラー
  64. 64. 64 1.外のスコープを引き継ぐ class Main { void method(int n) { Function<Integer, Integer> f = n -> n + 5; } } ● 多重定義 ● コンパイルエラー
  65. 65. 65 2.アウタークラスへの参照 ● 匿名クラス – 常に保持 – メモリリークの危険性高 ● ラムダ式 – 必要に応じて保持
  66. 66. 66 2.アウタークラスへの参照 class Register { void register(Processer p) { p.add(new Func() { public int f(int n) {return n * n;} }); } }
  67. 67. 67 2.アウタークラスへの参照 class Register { void register(Processer p) { p.add(new Func() { public int f(int n) {return n * n;} }); } } Registerのインスタンスへの参照が残るRegisterのインスタンスへの参照が残る
  68. 68. 68 2.アウタークラスへの参照 class Register { void register(Processer p) { p.add(n -> n * n); } }
  69. 69. 69 2.アウタークラスへの参照 class Register { void register(Processer p) { p.add(n -> n * n); } } Registerのインスタンスは保持しない
  70. 70. 70 3.ローカル変数の参照 ● 匿名クラスと同様 – finalな変数(実質的にfinal(後述)含む) – 値の変更不可
  71. 71. 71 ラムダ式の利用例 p -> p.getName() s -> Integer.parseInt(s) o -> list.add(o) init -> new MyClass(init) n -> new int[n] ● 引数を受け流すパターン
  72. 72. 72 ラムダ式の利用例 p -> p.getName() s -> Integer.parseInt(s) o -> list.add(o) init -> new MyClass(init) n -> new int[n] ● 引数を受け流すパターン ● メソッド・コンストラクタ参照
  73. 73. 73 メソッド・コンストラクタ参照 p -> p.getName() s -> Integer.parseInt(s) o -> list.add(o) init -> new MyClass(init) n -> new int[n] ● クラス名等::メソッド or new Person::getName Integer::perseInt list::add MyClass::new int[]::new
  74. 74. 74 マルチコアCPUコアライブラリ ラムダ式・メソッド参照 実質的にfinal 型推論の強化 交差型キャスト defaultメソッド stat. intf. メソッド
  75. 75. 75 実質的にfinal(Effectively final) ● 匿名クラスやラムダ式で 実質的にfinalな変数への参照が可能に – コンパイラがfinal性を推論 ● 実質的にfinalな変数 – final修飾されていない変数 – final修飾されてもエラーにならない変数
  76. 76. 76 実質的にfinalの例 void method(final int n) { final String str = “HelloFinal” Runnable r = new Runnable() { public void run() { System.out.println(str + n); }}; }
  77. 77. 77 実質的にfinalの例 void method(int n) { String str = “HelloEffectivelyFinal” Runnable r = new Runnable() { public void run() { System.out.println(str + n); }}; }
  78. 78. 78 実質的にfinalの例 void method(int n) { String str = “HelloEffectivelyFinal” Runnable r = () -> System.out.println(str + n); }
  79. 79. 79 実質的にfinalでない例 void method(int n) { Runnable r = () -> System.out.println(n); n = 5; } ラムダ式から参照されるローカル変数は、 finalまたは事実上のfinalである必要があります Runnable r = () -> System.out.println(n);
  80. 80. 80 実質的にfinalでない例 void method(int n) { Runnable r = () -> n++; } ラムダ式から参照されるローカル変数は、 finalまたは事実上のfinalである必要があります Runnable r = () -> n++;
  81. 81. 81 マルチコアCPUコアライブラリ ラムダ式・メソッド参照 実質的にfinal 型推論の強化 複合型キャスト defaultメソッド stat. intf. メソッド
  82. 82. 82 型推論の強化 ● ターゲット型推論の強化 1.適用可能箇所の拡大 2.より正確な推論
  83. 83. 83 ターゲット型推論? ● ターゲット型に基づく型推論 ● JavaSE5(5.0)から存在 – メソッドジェネリクスの実型引数 – ダイアモンド演算子(JavaSE7)
  84. 84. 84 ターゲット型 ● ある式の型として予期される型のこと ● List<Integer> l = new ArrayList<>(); – “new ArrayList<>()”のターゲット型はList<Integer>
  85. 85. 85 ターゲット型が存在する文脈 ● 変数宣言・・・ int n = … ● 割り当て・・・ n = … ● return文・・・ return … ● 配列初期化子・・・new String[]{...} ● 実引数・・・method(...) ● 条件式 ?:・・・bool ? … : … ● キャスト式 ・・・(Target)... ● ラムダ式の本体・・・() -> … 例 exprのターゲット型 変数宣言 int n = expr 変数の型(int) 割り当て n = expr 変数の型(nの型) return文 return expr 戻り値の型 配列初期化子 new String[]{expr, ...} 配列の型(String) 実引数 m(expr, ...) 仮引数の型 条件式 cond ? expr : expr 透過された型 キャスト式 (String)expr String ラムダ式の本体 () -> expr 戻り値の型
  86. 86. 86 JavaSE7における適用可能箇所 メソッドジェネリクスの 実型引数 ダイアモンド演算子 変数宣言 ○ ○ 割り当て ○ ○ return文 ○ ○ 配列初期化子 ○ - 実引数 × × 条件式 × × キャスト式 ○ × ラムダ式の本体
  87. 87. 87 適用可能箇所の例(JavaSE7) List<Integer> l = new ArrayList<>(); new ArrayList<T>() new ArrayList<Integer>() ● ArrayList<T> <: List<Integer> – T =:= Integer
  88. 88. 88 適用不可能箇所の例(JavaSE7) ● 実引数におけるターゲット型推論 printStrings(new ArrayList<>()); – void printStrings(List<String> l)
  89. 89. 89 適用不可能箇所の例(JavaSE7) ● 実引数におけるターゲット型推論 printStrings(new ArrayList<Object>()); – void printStrings(List<String> l) ● コンパイルエラー – Objectと推論される
  90. 90. 90 適用不可能箇所の例(JavaSE7) ● 条件式におけるターゲット型推論 List<Integer> list = bool ? Collections.emptyList() : new ArrayList<>();
  91. 91. 91 適用不可能箇所の例(JavaSE7) ● 条件式におけるターゲット型推論 List<Integer> list = bool ? Collections.<Object>emptyList() : new ArrayList<Object>(); ● コンパイルエラー – Objectと推論される
  92. 92. 92 JavaSE8における適用可能箇所 メソッドジェネリクスの 実型引数 ダイアモンド演算子 変数宣言 ○ ○ 割り当て ○ ○ return文 ○ ○ 配列初期化子 ○ - 実引数 ○ ○ 条件式 ○ ○ キャスト式 ○ ×?bug?(3/19現在) ラムダ式の本体 ○ ○
  93. 93. 93 適用可能になった例(JavaSE8) ● 実引数におけるターゲット型推論 printStrings(new ArrayList<>()); – void printStrings(List<String> l)
  94. 94. 94 適用可能になった例(JavaSE8) ● 実引数におけるターゲット型推論 printStrings(new ArrayList<String>()); – void printStrings(List<String> l) ● 推論器が正しく働く – ターゲット型よりStringと推論される
  95. 95. 95 適用可能になった例(JavaSE8) ● 条件式におけるターゲット型推論 List<Integer> list = bool ? Collections.emptyList() : new ArrayList<>();
  96. 96. 96 適用可能になった例(JavaSE8) ● 条件式におけるターゲット型推論 List<Integer> list = bool ? Collections.<Integer>emptyList() : new ArrayList<Integer>(); ● 推論器が正しく働く – ターゲット型よりIntegerと推論される
  97. 97. 97 JavaSE8における適用可能箇所 ラムダ式・メソッド参照 変数宣言 ○ 割り当て ○ return文 ○ 配列初期化子 ○ 実引数 ○ 条件式 ○ キャスト式 ○ ラムダ式の本体 ○
  98. 98. 98 2.より正確な推論 ● 今までは簡易的な推論 ● しばしば不正確な推論によりコンパイルエラー – 複雑な場合
  99. 99. 99 JavaSE7以前の推論 1.実引数の式の型を優先 2.実引数がない場合はターゲット型
  100. 100. 100 ターゲット型推論が働く例 List<Number> list = Arrays.asList(); java.util.Arrays#<T> List<T> asList(T...) ● List<Number> =:= List<T> – T =:= Number
  101. 101. 101 不正確な推論の例(JavaSE7) List<Number> list = Arrays.asList(2, 5.5); java.util.Arrays#<T> List<T> asList(T...)
  102. 102. 102 不正確な推論の例(JavaSE7) List<Number> list = Arrays.<T>asList(2, 5.5); ● T<:Object, T :>Integer,T:>Double(実引数より) – T=:=Number & Comparable<...>
  103. 103. 103 不正確な推論の例(JavaSE7) List<Number> list = Arrays.<Number & Comparable<...>>asList(2, 5.5); ● コンパイルエラー – Number & Comparable<? extends Number & Comparable<?>>と推論される – List<Number & Comparable<...>>を List<Number>として代入
  104. 104. 104 JavaSE8以降の推論 ● 実引数の型とターゲット型を加味 – グラフ推論 – より正確な型推論へ
  105. 105. 105 先の例(JavaSE8の場合) List<Number> list = Arrays.asList(2, 5.5);
  106. 106. 106 先の例(JavaSE8の場合) List<Number> list = Arrays.<T>asList(2, 5.5); ● T<:Object, T :>Integer,T:>Double(実引数より) ● T=Number(ターゲット型より) – T=Number
  107. 107. 107 先の例(JavaSE8の場合) List<Number> list = Arrays.<Number>asList(2, 5.5); ● 正しく推論器が働く – Numberと推論される
  108. 108. 108 マルチコアCPUコアライブラリ ラムダ式・メソッド参照 実質的にfinal 型推論の強化 交差型キャスト defaultメソッド stat. intf. メソッド
  109. 109. 109 型キャスト キャスト式に交差型を
  110. 110. 110 交差型? ● Intersection Type ● JavaSE5(5.0)から存在 – ジェネリクスの型境界(@型仮引数) – <T extends Runnable & Cloneable> ● RunnableとCloneableを継承する任意の型T ● 型 & 型 & … & 型 – 一つ目は参照型 – 二つ目以降はインターフェース
  111. 111. 111 交差型キャスト ● (型 & 型 & … & 型)式 ● 主にラムダ式・メソッド参照と使用する
  112. 112. 112 もしも交差型キャストがなかったら ● SerializableでRunnableなインターフェース – 関数型インターフェース – ラムダ式でインスタンス化したい – インターフェースを定義する必要がある
  113. 113. 113 もしも交差型キャストがなかったら interface SRunnable implements Runnable, Serializeable {} sendRunnable((SRunnable) () -> {/* */});
  114. 114. 114 もしも交差型キャストがなかったら interface SRunnable implements Runnable, Serializeable {} sendRunnable((SRunnable) () -> {/* */});
  115. 115. 115 交差型キャスト+ラムダ式 sendRunnable((Runnable & Serializable) () -> {/* */}); ● 型合成される
  116. 116. 116 マルチコアCPUコアライブラリ ラムダ式・メソッド参照 実質的にfinal 型推論の強化 交差型キャスト defaultメソッド stat. intf. メソッド
  117. 117. 117 <interface> PublishedInterface +already() +exist() +methods()
  118. 118. 118 <interface> PublishedInterface +already() +exist() +methods() ReferenceImpl +already() +exist() +methods() AnotherImpl +already() +exist() +methods() UserImpl +already() +exist() +methods()
  119. 119. 119 <interface> PublishedInterface +already() +exist() +methods() +newMethod() ReferenceImpl +already() +exist() +methods() AnotherImpl +already() +exist() +methods() UserImpl +already() +exist() +methods()
  120. 120. 120 <interface> PublishedInterface +already() +exist() +methods() +newMethod() ReferenceImpl +already() +exist() +methods() AnotherImpl +already() +exist() +methods() UserImpl +already() +exist() +methods()
  121. 121. 121 インターフェースに拡張性を ● 新しいメソッドを加えても互換性を保つ ● デフォルトメソッド – デフォルトの実装を提供する – インターフェースに実装 – 実装が提供されない場合に使用される
  122. 122. 122 デフォルトメソッド interface Person { Sex getSex(); default boolean isMan() { return getSex() == Sex.MAN; } }
  123. 123. 123 デフォルトメソッド class PersonImpl implements Person { public Sex getSex() {/*...*/} // isManへの実装はなくてもOK // Person#isManが使われる }
  124. 124. 124 デフォルトメソッド class PersonImpl implements Person { public Sex getSex() {/*...*/} public boolean isMan() {/*...*/} } ● オーバーライド可
  125. 125. 125 デフォルトメソッド ● default修飾子 ● publicメソッドとなる – 既存のインターフェースメソッドと同様 ● strictfp修飾のみ可 ● 具象クラスで実装が提供されなくても無問題 ● 拡張性を実現できた – 新たな問題が・・・
  126. 126. 126 実装の多重継承問題
  127. 127. 127 多重継承 class BasicPerson { public boolean isMan() {/*...*/} } class ComplexPerson extends BasicPerson implements Person { public Sex getSex() {/*...*/} }
  128. 128. 128 多重継承 BasicPerson #isMan Person #isMan ComplexPerson #isMan
  129. 129. 129 “Class always win”
  130. 130. 130 クラスで定義された実装が 常に勝つ
  131. 131. 131 Class always win class BasicPerson { public boolean isMan() {/*...*/} } class ComplexPerson extends BasicPerson implements Person { public Sex getSex() {/*...*/} } ● BasicPerson#isManが使われる – “Class always win”
  132. 132. 132 親インターフェースの呼び出し class ComplexPerson extends BasicPerson implements Person { public Sex getSex() {/*...*/} public boolean isMan() { return Person.super.isMan(); } } ● インターフェース名.super.メソッド名(...)
  133. 133. 133 クラスを介さない多重継承 interface Base1 {default void m() {}}
  134. 134. 134 クラスを介さない多重継承 interface Base1 {default void m() {}} interface Base2 {default void m() {}}
  135. 135. 135 クラスを介さない多重継承 interface Base1 {default void m() {}} interface Base2 {default void m() {}} interface ExBase extends Base1, Base2 {}
  136. 136. 136 多重継承 Base1#m Base2#m ExBase#m
  137. 137. 137 クラスを介さない多重継承 interface ExBase extends Base1, Base2 {} ● コンパイルエラー – オーバーライドして選択
  138. 138. 138 クラスを介さない多重継承 interface ExBase extends Base1, Base2 { default void m() { Base1.super.m(); } }
  139. 139. 139 多重継承は怖くない!! ● 大原則1:Class always win – クラスで定義された実装が常に勝つ ● 大原則2:いつでもオーバーライドできる – 親クラスでfinal修飾されてたら別 – インターフェースの実装を呼べる
  140. 140. 140 Objectメソッドのデフォルトメソッド ● Objectで定義されたpublicメソッド – そもそもデフォルトの実装 ● Objectのpublicメソッドのデフォルトメソッドは不可 – interface I {default String toString() {/* */}} – コンパイルエラー
  141. 141. 141 マルチコアCPUコアライブラリ ラムダ式・メソッド参照 実質的にfinal 型推論の強化 交差型キャスト defaultメソッド stat. intf. メソッド
  142. 142. 142 staticインターフェースメソッド ● staticなインターフェースメソッド ● 常にpublic修飾 – 他のインターフェースのメソッドと同様 ● strictfp修飾可 – デフォルト実装と同様
  143. 143. 143 staticインターフェースメソッドの例 interface Example { static void method() {/* */} }
  144. 144. 144 staticインターフェースメソッドの例 interface Example { static strictfp void method() {/* */} } ● strictfp修飾可
  145. 145. 145 staticインターフェースメソッドの継承 ● 継承されない – クラスメソッドと大きく違う interface Example2 extends Example {} Example2.method()はコンパイルエラー
  146. 146. 146 Interesting Example ● publicでstaticなメソッド – 人生で最初に書いたメソッド
  147. 147. 147 Interesting Example ● publicでstaticなメソッド – 人生で最初に書いたメソッド public static void main( String[] args)
  148. 148. 148 main in Interface interface EntryPoint { public static void main(String[] args) { /* ... */ } } ● 正しく動く
  149. 149. 149 マルチコアCPUコアライブラリ ラムダ式・メソッド参照 実質的にfinal 型推論の強化 交差型キャスト defaultメソッド stat. intf. メソッド
  150. 150. 150 Library Enhancements StreamAPI IO/NIOJCF Optional And More...
  151. 151. 151 Library Enhancements StreamAPI IO/NIOJCF Optional And More...
  152. 152. 152 No more 外部イテレーション ● 外部イテレーションは並列化困難 ● 内部イテレーションベースのライブラリへ – 並列化が容易に
  153. 153. 153 外部イテレーション ● イテレーションが外にさらされている – for,while文 for (Student s : students) { }
  154. 154. 154 内部イテレーションライブラリ StreamAPI
  155. 155. 155 StreamAPI java.util.stream. ● Stream ● IntStream ● LongStream ● DoubleStream – ソースから生成される – 中間操作と終端操作でデータを弄る – 並列化が容易
  156. 156. 156 Collection 配列 BufferReader etc... Stream IntStream LongStream DoubleStream 中間操作 終端操作 j.u.stream.*Source
  157. 157. 157 Collection 配列 BufferReader etc... Stream IntStream LongStream DoubleStream 中間操作 終端操作 j.u.stream.*Source
  158. 158. 158 Make Streams ソース メソッド 使用例 Collection Collection#stream list.stream() 配列 Arrays#stream Arrays.stream(args) BufferedReader BufferedReader#lines br.lines() n〜m-1までの数値 IntStream#range IntStream.range(n, m) n〜mまでの数値 IntStream#rangeClosed IntStream.rangeClosed(n, m) 任意の要素 Stream#of Stream.of(“J”, “a”, “v”, “a”)
  159. 159. 159 Collection 配列 BufferReader etc... Stream IntStream LongStream DoubleStream 中間操作 終端操作 j.u.stream.*Source
  160. 160. 160 java.util.stream. StreamAPI 要素の型 Stream<T> T(参照型) IntStream int(プリミティブ型) LongStream long(プリミティブ型) DoubleStream double(プリミティブ型)
  161. 161. 161 2 types of Stream Sequential Stream Parallel Stream
  162. 162. 162 Change the type of Stream Sequential Stream Parallel Stream parallel() sequential()
  163. 163. 163 Collection 配列 BufferReader etc... Stream IntStream LongStream DoubleStream 中間操作 終端操作 j.u.stream.*Source
  164. 164. 164 中間操作? ● filterやmapなど – Streamを返すメソッド ● 終端操作が行われるまで処理されない – 遅延される
  165. 165. 165 主要な中間操作 メソッド名 概要 使用例 filter フィルタリング s.filter(n -> n % 2 == 0) map 写像・変換 s.map(p -> p.getName()) flatMap 写像・変換&平坦化 s.flatMap(room -> room.getPersons().stream()) distinct 同一の要素を除外 s.distinct() sorted 並び替え s.sorted((p1, p2) -> compare(p1.age, p2.age)) peek デバッグ向け forEach s.peek(e -> System.out.println(e)) limit 要素数制限 s.limit(5) skip 読み飛ばす s.skip(5)
  166. 166. 166 Collection 配列 BufferReader etc... Stream IntStream LongStream DoubleStream 非終端操作 終端操作 j.u.stream.*Source
  167. 167. 167 終端操作? ● forEachやreduceやcollectなど – Streamを返さないメソッド ● 遅延されていた中間操作を確定
  168. 168. 168 主要な終端操作 メソッド名 概要 使用例 forEach 反復処理 s.forEach(e -> System.out.println(e)) reduce 畳み込み演算 s.reduce(1, (n1, n2) -> n1 * n2) collect 集約化 s.collect(Collectors.toList()) toArray 配列化 s.toArray(String[]::new) min/max 最小値/最大値 s.min(String::compareToIgnoreCase) count 要素数 s.count()
  169. 169. 169 0から10まで出力したい for (int i = 0; i <= 10; i++) { System.out.println(i); }
  170. 170. 170 forEach[終端操作] T->void[j.u.function.Consumer<T>#void accept(T)] ● forEach(T -> void) – 各要素に引数で渡した処理を行なう – s.forEach(t -> {/**/});
  171. 171. 171 0から10まで出力したい for (int i = 0; i <= 10; i++) { System.out.println(i); } IntStream.rangeClose(0, 10) .forEach(i -> System.out.println(i));
  172. 172. 172 0から10まで出力したい for (int i = 0; i <= 10; i++) { System.out.println(i); } IntStream.rangeClose(0, 10) .forEach(System.out::println);
  173. 173. 173 0から10までの偶数を出力したい for (int i = 0; i <= 10; i++) { if (i % 2 == 0) { System.out.println(i); } }
  174. 174. 174 filter[中間操作] ● filter(T -> boolean) – フィルタリング – 各要素を引数に適用しtrueを返したもののみ残す – s.filter(Objects::nonNull) // nullを除外
  175. 175. 175 filter[中間操作] T->boolean[j.u.function.Predicate<T>#boolean test(T)]
  176. 176. 176 0から10までの偶数を出力したい IntStream.rangeClose(0, 10) .filter(i -> i % 2 == 0) .forEach(System.out::println);
  177. 177. 177 Personのリストから名前を出力 for (Person p : persons) { System.out.println(p.getName()); }
  178. 178. 178 map[中間操作] ● map(T -> R) – 写像・変換 – 各要素を引数に適用した結果のStreamを作る – personStream.map(p -> p.getName())
  179. 179. 179 map[中間操作] T -> R[java.util.function.Function<T, R>#R map(T)] R
  180. 180. 180 Personのリストから名前を出力 persons.stream() .map(p -> p.getName()) .forEach(n -> System.out.println(n));
  181. 181. 181 Personのリストから名前を出力 persons.stream() .map(Person::getName) .forEach(System.out::println);
  182. 182. 182 Streamを横断するmap Stream<T> IntStream LongStream DoubleStream #mapToObj #mapToInt #mapToLong #mapToDouble #mapToDouble #mapToLong #mapToInt
  183. 183. 183 Personのリストから名前のリスト List<String> names = new ArrayList<>(); for (Person p : persons) { names.add(p.getName()); }
  184. 184. 184 collect[終端処理] ● collect(Collector<T, R>) ● collect(() -> R, (R, T) -> void, (R, R) -> void) – 集約処理を行なう – stream.collect(Collectors.toList()) – strings.collect(StringBuilder::new, StringBuilder::apped, StringBuilder::apped)
  185. 185. 185 Personのリストから名前のリスト persons.stream() .map(Person::getName) .collect(Collectors.toList())
  186. 186. 186 Sequential collect(SB::new, SB::append, SB::append) H e l l o , W o r l d !
  187. 187. 187 H e l l o , W o r l d ! SB Sequential collect(SB::new, SB::append, SB::append)
  188. 188. 188 H e l l o , W o r l d ! SB Sequential collect(SB::new, SB::append, SB::append)
  189. 189. 189 H e l l o , W o r l d ! SB Sequential collect(SB::new, SB::append, SB::append)
  190. 190. 190 Parallel collect(SB::new, SB::append, SB::append) H e l l o , W o r l d !
  191. 191. 191 Parallel collect(SB::new, SB::append, SB::append) H e l l o , W o r l d ! Split!!
  192. 192. 192 Parallel collect(SB::new, SB::append, SB::append) H e l l o , W o r l d !
  193. 193. 193 Parallel collect(SB::new, SB::append, SB::append) H e l l o , W o r l d ! He Wo
  194. 194. 194 Parallel collect(SB::new, SB::append, SB::append) H e l l o , W o r l d ! He Wo
  195. 195. 195 Parallel collect(SB::new, SB::append, SB::append) H e l l o , W o r l d ! He Wo
  196. 196. 196 Parallel collect(SB::new, SB::append, SB::append) H e l l o , W o r l d ! He WoSBll SBd!
  197. 197. 197 Parallel collect(SB::new, SB::append, SB::append) H e l l o , W o r l d ! He WoSBll SBd!
  198. 198. 198 Parallel collect(SB::new, SB::append, SB::append) H e l l o , W o r l d ! Hell Wo SBd!
  199. 199. 199 Parallel collect(SB::new, SB::append, SB::append) H e l l o , W o r l d ! Hell Wo SBd!
  200. 200. 200 Parallel collect(SB::new, SB::append, SB::append) H e l l o , W o r l d ! Hell Wo SBd!SBo, SBrl
  201. 201. 201 Parallel collect(SB::new, SB::append, SB::append) H e l l o , W o r l d ! Hell Wo SBd!SBo, SBrl
  202. 202. 202 Parallel collect(SB::new, SB::append, SB::append) H e l l o , W o r l d ! Hello, Worl SBd!
  203. 203. 203 Parallel collect(SB::new, SB::append, SB::append) H e l l o , W o r l d ! Hello, Worl SBd!
  204. 204. 204 Parallel collect(SB::new, SB::append, SB::append) H e l l o , W o r l d ! Hello,Worl SBd!
  205. 205. 205 Parallel collect(SB::new, SB::append, SB::append) H e l l o , W o r l d ! Hello,Worl SBd!
  206. 206. 206 Parallel collect(SB::new, SB::append, SB::append) H e l l o , W o r l d ! Hello,World!
  207. 207. 207 Putting it together 学生のリスト(students)の内 2年生で GPAが3.5以上ある学生の 学籍番号の リストを生成する
  208. 208. 208 Putting it together List<StudentID> list = new ArrayList<>(); for (Student s : students) { if (s.getGrade() == 2 && s.getGPA() >= 3.5) { list.add(s.getID()); } }
  209. 209. 209 Putting it together 学生のリスト(students)の内 2年生で GPAが3.5以上ある学生の 学籍番号の リストを生成する
  210. 210. 210 Putting it together students.stream() 2年生で GPAが3.5以上ある学生の 学籍番号の リストを生成する
  211. 211. 211 Putting it together students.stream() .filter(s -> s.getGrade() == 2) GPAが3.5以上ある学生の 学籍番号の リストを生成する
  212. 212. 212 Putting it together students.stream() .filter(s -> s.getGrade() == 2) .filter(s -> s.getGPA() >= 3.5) 学籍番号の リストを生成する
  213. 213. 213 Putting it together students.stream() .filter(s -> s.getGrade() == 2) .filter(s -> s.getGPA() >= 3.5) .map(Student::getID) リストを生成する
  214. 214. 214 Putting it together students.stream() .filter(s -> s.getGrade() == 2) .filter(s -> s.getGPA() >= 3.5) .map(Student::getID) .collect(Collectors.toList())
  215. 215. 215 Putting it together students.stream().parallel() .filter(s -> s.getGrade() == 2) .filter(s -> s.getGPA() >= 3.5) .map(Student::getID) .collect(Collectors.toList())
  216. 216. 216 Project Lambdaまとめ ● もともとはマルチコア対応 ● 結果としては汎用的な仕様に – ラムダ式等 – コアライブラリ ● よりスマートなコードへ
  217. 217. 217 Thank you for your listening Enjoy JavaSE8
  • kyamane13

    Sep. 4, 2016
  • YuzoKonishi

    Aug. 12, 2015
  • leinaotsuka

    Aug. 12, 2015
  • yk256

    May. 4, 2015
  • tchofu

    Mar. 13, 2015
  • ohtsuchi

    Aug. 8, 2014
  • gishi

    Jul. 12, 2014
  • carme264pp

    Jun. 19, 2014
  • kodamatic

    Jun. 17, 2014
  • itokami1123

    Jun. 17, 2014
  • youhei

    Jun. 15, 2014
  • matsumana0101

    Jun. 15, 2014
  • raydive

    Jun. 15, 2014

福岡Java8勉強会で発表させていただいた時の資料です.

Views

Total views

1,627

On Slideshare

0

From embeds

0

Number of embeds

15

Actions

Downloads

13

Shares

0

Comments

0

Likes

13

×