狠狠撸

狠狠撸Share a Scribd company logo
きつねさんと学ぶ
Lambda式&StreamAPIハンズオン
2015/7/11 @ 関ジャバ
2
Who are you?
吉田真也(@bitter_fox, @shinyafox)
●
立命館大学 情報理工学部 情報システム学科
– 高性能計算機ソフトウェアシステム研究室
● 立命館コンピュータクラブ(RCC)
● http://www.rcc.ritsumei.ac.jp/
●
OpenJDKコミッタ
– Project Kulla
3
Project Kulla
ハンズオンの诸注意
1.わからないことがあったら
TAさんを呼んでください
きつねさんと学ぶ Lambda式&StreamAPIハンズオン[関ジャバ2015/7/11] #kanjava
2.滨顿贰の自动変换机能禁止
3.本ハンズオンでは
メソッド参照は使用しません
Main1
ラムダ式導入
匿名クラスで書かれたコードを
ラムダ式で置き換えてみましょう
ラムダ式
● 関数型インターフェースを実装&インスタンス化
する
– メソッドが一つのインターフェース
– Runnable, Function<T>, etc...
● (引数) -> {文}
● (引数) -> 式
Main2
関数型インターフェース
自分で関数型インターフェースを定義してみよう
関数型インターフェース
●
メソッドが一つのインターフェース
interface F {
void exec0();
}
●
@FunctionalInterfaceアノテーション
– コンパイル時に関数型インターフェースかを検査
Any question?
Main3
内部イテレーションへ
(拡張)for文をIterable#forEachで書き換えよう
Main3
List<Integer>の要素を
一行ずつ出力
for (Integer n : list) {
System.out.println(n);
}
外部イテレーション?
内部イテレーション?
●
外部イテレーション
– イテレーションをユーザコードが行う
– for文,while文
– 並列化が困難
●
ユーザコードの大幅な変更が必要
●
内部イテレーション
– イテレーションをライブラリが行う
– イテレーション以外の処理を受け取る
– 并列化が容易
●
イテレーションの方法を簡単に切り替えられる
●
ユーザコードの変更は最小限
Iterable#forEach
list.forEach(n ->
System.out.println(n));
Main4
StreamAPI導入
複雑なイテレーションをStreamAPIで書いてみよう
Main4
List<Integer>の
2で割り切れる
要素だけを一行ずつ出力
StreamAPI
● 内部イテレーション&パイプライン化
●
汎用性高い
– あらゆる形式のデータ列に対応可
● Collection
●
値の範囲
●
任意の値
– データ列自体は保持していない
●
データへのアクセス手段を保持
21
StreamAPI
java.util.stream.
Stream<T>
IntStream
LongStream
DoubleStream
– ソースから生成される
– 中間操作と终端操作でデータを弄る
– 并列化が容易
22
Collection
配列
BufferReader
etc...
Stream
IntStream
LongStream
DoubleStream
中間操作
终端操作
j.u.stream.*Source
23
中間操作?
● Stream#filterやmapなど
– Streamを返すメソッド
●
终端操作が行われるまで処理されない
– 遅延される
24
终端操作?
● Stream#forEachやreduceやcollectなど
– Streamを返さないメソッド
●
遅延されていた中間操作を確定
– 1回のループで済む
25
StreamAPIで書くポイント
●
ソース,中間操作,终端操作を意識する
● forEachで副作用を与えて何でも書こうとしない
– forEachを使わずに実現する方法が存在する(はず)
– 出力などの副作用は翱碍
Main4(再掲)
List<Integer>の
2で割り切れる
要素だけを一行ずつ出力
Main4
List<Integer>の ソース
2で割り切れる filter[中間操作]
要素だけを一行ずつ出力 蹿辞谤贰补肠丑摆终端操作闭
Collection<T>からStream<T>
● Collection<T>#stream()
– parallelStream()で並列Streamも取得可
29
filter[中間]
● filter(T -> boolean)
– フィルタリング
– 各要素を引数に適用しtrueを返したもののみ残す
– filterの引数には欲しい値の条件を書く
– s.filter(Objects::nonNull) // nullを除外
Stream<T>
IntStream
LongStream
DoubleStream
Main5
値の変換を行う中間操作をしてみよう
Main5
List<Person>から
Personの名前を
一行ずつ出力
Main5
List<Person>から ソース
Personの名前を map[中間操作]
一行ずつ出力 蹿辞谤贰补肠丑摆终端操作闭
33
map[中間操作]
● map(T -> R)
– 写像?変換
– 各要素を引数に適用した結果のStreamを作る
– personStream.map(p -> p.getName())
– seq.map(n -> n * 2)
Stream<T>
IntStream
LongStream
DoubleStream
34
Streamを横断するmap
Stream<T> IntStream
LongStream DoubleStream
#mapToObj
#mapToInt
#mapToLong
#mapToDouble
#mapToDouble
#mapToLong
#mapToInt
Main6
複数の要素から一つの値へ
Main6
ある数値の範囲の
総和を求める
乱数生成器Randomから
指定された個数の数値の
平均を求める
Main6
ある数値の範囲の ソース
総和を求める 终端操作
乱数生成器Randomから ソース
指定された個数の数値の 中間操作
平均を求める 终端操作
値の範囲からStream
● IntStream.range(start, end)
– start?end(end含まない)のIntStream
– end含める場合はrangeClosed
39
reduce[終端]
● Optional<T> reduce((T, T) -> T)
● T reduce(T, (T, T) -> T)
● U reduce(U, (U, T) -> U, (U, U) -> U)
– 集約
– s.reduce((n, m) -> n < m ? n : m)
● Optional
– 値が無いという状態を表すことができる
Stream<T>
IntStream
LongStream
DoubleStream
40
reduce[終端]
41
reduce[終端]
42
reduce[終端]
43
reduce[終端]
44
reduce[終端]
45
reduce[終端]
46
並列reduce
47
並列reduce
48
並列reduce
49
並列reduce
50
並列reduce
51
並列reduce
6
52
並列reduce
6
53
sum[終端]
● int sum()
● long sum()
● double sum()
– 総和を求める
●
そのものズバリ
– s.sum()
Stream<T>
IntStream
LongStream
DoubleStream
54
summaryStatistics[終端]
● XxxSummaryStatistics
summaryStatistics()
– 統計処理
●
合計,平均,最大,最小,個数
– stream.summaryStatistics().getSum()
– 複数の統計的な値を求める場合
Stream<T>
IntStream
LongStream
DoubleStream
Main6
ある数値の範囲の ソース
総和を求める 终端操作
乱数生成器Randomから ソース
指定された個数の数値の 中間操作
平均を求める 终端操作
56
RandomからStream
● Random#doubles()
– DoubleStream
– 無限のStream
– limitと併用
● Random#doubles(n)
– n個の要素のDoubleStream
57
Ave, max, min[終端]
● average(), max(), min()
– Optional系を返す
– 平均,最大,最小値を求める
Stream<T>
IntStream
LongStream
DoubleStream
Main6_1
Streamと並列処理
59
Change the type of Stream
Sequential Stream
Parallel Stream
parallel() sequential()
60
Streamと並列処理
●
並列化したら早くなるのか
– 一概には言えない???
●
データ数依存
● CPU依存
●
操作依存
– 早くなるものもある
– 並列化に際してはベンチマーク必須
Any question?
Main7
ファイルからの読み出しと
リストへの集約
Main7
ファイルから
“{“か”}”で終わる行を
出力する
ファイルから
“{“か”}”で終わる行を
リストに入れる
Main7
ファイルから
“{“か”}”で終わる行を
出力する
ファイルから
“{“か”}”で終わる行を
リストに入れる
Main7
ファイルから ソース
“{“か”}”で終わる行を 中間操作
出力する 终端操作
ファイルから ソース
“{“か”}”で終わる行を 中間操作
リストに入れる 终端操作
ファイルからStream<String>
● BufferedReader#lines()
● j.nio.file.Files#lines(Path)
– 一行ずつのStream
– Closeしなければいけない
●
twr利用可
try (Stream<String> lines = Files.lines(path)) {
}
Main7
ファイルから ソース
“{“か”}”で終わる行を 中間操作
出力する 终端操作
ファイルから ソース
“{“か”}”で終わる行を 中間操作
リストに入れる 终端操作
68
collect
● R collect(() -> R, (R, T) -> R, (R, R) -> void)
● R collect(Collector<T, ?, R>)
– 集約処理
– R:集約先のオブジェクト
– () -> R:集約先のオブジェクトの生成
– (R, T) -> R:集約先のオブジェクトRに要素Tを集約
– (R, R) -> void:集約先のオブジェクトR同士のcombine
●
並列処理用
69
Collectors#toXxx
● toCollection()
● toList()
● toSet()
– リストなどへの集約をするCollectorの生成
Main8
Streamを返す変換を平坦化する
Main8
List<Campany>から
List<Car>を取得し
すべての車のうちの
軽自動車のみの
車名の
リストを作る
Main8
List<Campany>から ソース
List<Car>を取得し 中間操作
すべての車のうちの
軽自動車のみの filter
車名の map
リストを作る collect(toList())
Streamを返すmap
H e l l
H e l l o
H e l l o , W
H e l
Stream<Stream<R>>Stream<T>
flatMap
H e l l
H e l l o
H e l l o , W
H e l
Stream<R>Stream<T>
flatMap
● flatMap(T -> Stream<R>)
– 写像?変換 + 平坦化
– 平坦化されたStream<R>
– companieStream.flatMap(c → c.getList().stream())
Main9
文字列の連結
Main9
List<Person>から
Personの名前を
,区切りで連結する
Main9
List<Person>から ソース
Personの名前を 中間操作
,区切りで連結する 终端操作
79
Collectors#joining
● joining()
● joining(delimiter)
● joining(delimiter, prefix, suffix)
– 文字列の連結をするCollectorを返す
– 単なる連結だけでなく,デリミタなども指定可
Main10
同じ値でグループ化
Main10
List<People>から
同じ性別でPeopleをグループ化
List<People>から
同じ名字でPeopleの名前をグループ化
82
Collectors#groupingBy
● groupingBy(T -> K)
– Kの同じ値でグループ化
– Map<K, List<T>>にする
83
Collectors#groupingBy
● groupingBy(T -> K, Collector)
– 第二引数はMapの値へのCollector
– groupingBy(..., toSet()) : Map<K, Set<T>>
84
Collectors#mapping
● mapping(T -> U, Collector)
– 値の変換を行って集約するCollector
Main10_1
並列グループ化
groupingBy vs.
groupingByConcurrent
● groupingByでも並列化できる
– 分割統治法
– Map<K, List<V>>同士の連結が起きる
●
逐次よりも遅くなる可能性
● groupingByConcurrent
– 一つのMap<K, List<V>>にマルチスレッドでアクセス
– 中間操作は並列
●
中間操作があれば逐次よりも高速に
●
どちらが良いかは,場合による
87
Parallel
groupingBy
H e l l o , W o r l d !
88
Parallel
groupingBy
Split!!
89
Parallel
groupingBy
Map Map Map Map
90
Parallel
groupingBy
Map Map Map MapMap Map
91
Parallel
groupingBy
Map MapMap Map
92
Parallel
groupingBy
Map Map
93
H e l o , W o r l d !
Map
parallel
groupingByConcurrent
Any question?

More Related Content

きつねさんと学ぶ Lambda式&StreamAPIハンズオン[関ジャバ2015/7/11] #kanjava