SlideShare a Scribd company logo
1 of 95
Download to read offline
1
ステップ・バイ・ステップで学ぶ
ラムダ式・Stream API入門
多田真敏 @suke_masa
#ccc_h2
JJUG CCC 2014 Fall
自己紹介
多田真敏(ただまさとし)
某中堅SIerの人材子会社で研修講師
Java(SE 8・EE 7含む)、.NET、ネットワークなど
JJUG CCC登壇は2回連続2回目
前回はJPAネタ→「JPA ロック」で検索
2
Java SE 8 リリースから8か月。
皆さん、お使いですか?
ご自身の学習はいかが
ですか?
部下・後輩への指導は
いかがですか?
このセッションでは、ラム
ダ式・Stream APIの理解
のポイントを解説します
3
本セッションの対象者
ラムダ式・Stream APIをはじめて学習される方
学習したことはあるものの、今ひとつ腑に落ちな
いという方
ご自身は理解しているものの、同僚・部下・後輩
にどうやって教えたらよいか悩んでいる方
4
Java SE 8の超重要情報
Java SE 8 ローンチイベントの動画
徹底解説!Project Lambdaのすべて リターンズ
(@bitter_foxさん)
https://www.youtube.com/watch?v=gAMYhTl7t70
from old Java to modern Java - reloaded
(@cero_tさん)
https://www.youtube.com/watch?v=aLRonTjIeFI
Web記事
詳解 Java SE 8(@skrbさん)
http://itpro.nikkeibp.co.jp/article/COLUMN/20140212/536246/
書籍
Java SE 8実践プログラミング(以下「実践本」)
Javaによる関数型プログラミング(以下「関数本」)
Javaエンジニア養成読本(以下「養成本」)
5
こんなコードが出てくる
6
public static Map<Character, Integer> countByInitial() {
return EMP_LIST.stream()
.collect(Collector.of(
() -> IntStream.rangeClosed('A', 'Z')
.mapToObj(i -> (char) i)
.collect(Collectors.toMap(c -> c, c -> 0)),
(map, emp) -> map.compute(emp.getName().charAt(0),
(initial, count) -> ++count),
(map1, map2) -> {
map1.forEach((initial, count) ->
map1.put(initial, count + map2.get(initial));
return map1;
},
map -> Collections.unmodifiableMap(map)));
}
階段が高すぎては登れない
7
超
え
ら
れ
な
い
壁
1段ずつ登りましょう!
8
理解するためのステップ
① ラムダ式を読み書きできる
② Streamの生成を理解する
③ 中間操作でデータ操作ができる
④ 終端操作で好きな値に変換できる
⑤ 何でもかんでもラムダ式・Stream APIで書ける
9
10
ステップ1:
ラムダ式を読み書きしよう!
Java SE 8は「関数型言語」?
ラムダ式・Stream APIの登場
関数型言語Scalaと比較された記事あり
Java SE 8の書籍には「遅延実行」「高階関数」な
ど、関数型言語の用語がズラリ・・・
11
Javaは「オブジェクト指向言語」
ラムダ式は、オブジェクト指向言語の範囲を
超えないように設計されている
12
今までのJavaを理解していれば、
必ず理解できる!
無名クラス
13
interface Calculator {
int calc(int a, int b);
}
Calculator c = new Calculator() {
public int calc(int a, int b) {
return a + b;
}
};
int result = c.calc(1, 2);
無名クラス
ポイント① コンパイラの推論強化
コンパイラが、いろんな部分を推論してくれる
「Enhancements in Java SE 8」では、
ラムダ式に続いて2番目に挙げられている
https://docs.oracle.com/javase/8/docs/technotes/guid
es/language/enhancements.html#javase8
今まで書いていた冗長な部分を省略可能
→ラムダ式!
14
推論による省略
15
interface Calculator {
int calc(int a, int b);
}
Calculator c = new Calculator() {
public int calc(int a, int b) {
return a + b;
}
};
int result = c.calc(1, 2);
左辺から推論可能
抽象メソッドが1つのみ
(=関数型インターフェイス)
ならば推論可能
ラムダ式による記述
16
interface Calculator {
int calc(int a, int b);
}
Calculator c = (a, b) -> { return a + b; };
int result = c.calc(1, 2);
アロー記号でつなぐ
更なる省略
17
interface Calculator {
int calc(int a, int b);
}
Calculator c = (a, b) -> a + b;
int result = c.calc(1, 2);
メソッド本文が1文のみならば、return、{}、; が
省略可能
戻り値の有無によらない
引数が1つの場合、() が省略可能
引数無しの場合は省略不可
メソッドの引数にラムダ式を指定
18
interface Calculator {
int calc(int a, int b);
}
void print(int n1, int n2, Calculator c) {
System.out.println(“result = ” + c.calc(n1, n2))
}
print(1, 2, (a, b) -> a + b);
ラムダ式をメソッドの引数に渡すことも可能
引数の型から推論する
ジェネリクスに関する型推論強化
19
List<String> list = new ArrayList<>();
list.add("hoge");
list.addAll(Arrays.asList());
Arrays.asList(T… a)の戻り値はList<T>
Tは通常、asList()の引数の型から推論する
addAll()の引数はCollection<? extends String>
コンパイラが「T=String」と推論してくれる
Java SE 7だとコンパイルエラー
(Tに関する情報が無いので、T=Objectと推論される)
ジェネリクスに関する型推論強化
20
interface Function<T, R> {
R apply(T t);
}
void print(A a, Function<A, B> func) {
B b = func.apply(a);
System.out.println(b)
}
print("hoge", str -> str.length()); // 「4」と表示
ラムダ式の戻り値から推論
B = IntegerA = String
ポイント② ラムダはインスタンス
処理を書いているように見えるが、
実はそのようなメソッドを持つ無名クラスの
インスタンスを生成しているだけ
21
※さらに詳しく知りたい方は@bitter_foxさんの動画をご覧ください
(匿名クラスとの違い 13:30~、ターゲット型 19:40~)
なぜラムダ式は「難しい」のか?
ラムダ式の引数の型を省略した場合、
「この変数ってどこで宣言されているの!?」
となってしまう
22
doSomething(a -> a + 10);
aはどこで宣言されてるんだ!?
→宣言を探しても見つからない
→「ラムダ式難しい」
// 実はコレの省略形
doSomething((int a) -> {return a + 10;});
Javaプログラマの頭の中(Java 7以前)
23
クラス メソッド
変数の
宣言
変数の
利用
名前の頭文字
が大文字
後ろに()が
ついている
先頭に
データ型が
書いてある
名前を見つける
Javaプログラマの頭の中(Java 8以降)
24
クラス メソッド
変数の
宣言
変数の
利用
名前の頭文字
が大文字
後ろに()が
ついている
先頭に
データ型が
書いてある
後ろに ->
がついている
ラムダの
仮引数
名前を見つける
頭の中のフローチャートを
書き換える必要がある!
ポイント③ 脳内フローチャート変更
データ型が付いていない変数は、ラムダの引数
である可能性がある
アロー記号の有無を必ずチェック
脳内でデータ型を追加しよう
25
コード a -> a + 10;
↓
脳内 (int a) -> { return a + 10; };
なぜラムダ式は「難しい」のか?
ラムダ式が値を返しているのかどうかが読み取
れない
26
StringBuilder builder = new StringBuilder();
doSomething(builder, sb -> sb.append("hoge"));
append()してるだけ?
それとも戻り値を返しているの?
→分からない
→「ラムダ式難しい」
ポイント④ ラムダ省略禁止
慣れていないうちは、仮引数の型、()、{}、
returnは省略せずに書く
「ラムダ禁止」ではありません
慣れてきたら、徐々に省略すればよい
27
× a -> a + 10;
○ (int a) -> { return a + 10; };
なぜラムダ式は「難しい」のか?
自分の書いたラムダが、どんな目的で、
どんなタイミングで実行されるかが分からない
ラムダの引数に、具体的にどんな値が入ってくる
のかが分からない
28
Map<String, Integer> map = new HashMap<>();
map.put(“apple”, 20);
map.put(“orange”, 30);
int value = map.compute(“apple”, (k, v) -> v + 10);
k、vには何が入るの!? このラムダは何に使われるの!?
なぜラムダ式は「難しい」のか?
汎用関数型インターフェイスがよく分からない
ジェネリクスが多すぎてよく分からない
29
BiFunctionって何!? ジェネリクス大杉!!
→分からない→「ラムダ式難しい」
※super、extendsの意味について知りたい方は、
「実践本」のP.74~P.76をご覧ください
ポイント⑤ 汎用関数型インターフェイス
BiFunction<T, U, R>は、
TとUを引数とし、Rを戻り値とするメソッドを持つ
関数型インターフェイス
30
public interface BiFunction<T, U, R> {
R apply(T t, U u);
}
※本当はもう1つデフォルトメソッドがありますが、省略しています
ポイント⑤ 汎用関数型インターフェイス
ジェネリクスについても、コンパイラの推論が
強化されている
31
Map<String, Integer> map = new HashMap<>();
・・・
String s = map.compute(“apple”, (k, v) -> v + 10);
K V
String Integer Integer
第1引数 第2引数 戻り値
汎用関数型インターフェイス一覧
32
関数型インターフェイス メソッド
Runnable void run()
Supplier<T> T get()
Consumer<T> void accept(T t)
BiConsumer<T, U> void accept(T t, U u)
Function<T, R> R apply(T t)
BiFunction<T, U, R> R apply(T t, U u)
UnaryOperator<T> T apply(T t)
BinaryOperator<T> T apply(T t1, T t2)
Predicate<T> boolean test(T t)
BiPredicate<T, U> boolean test(T t, U u)
※Runnable以外は、すべてjava.util.functionパッケージ
基本データ型用の関数型インターフェイス
33
関数型インターフェイス メソッド
BooleanSupplier boolean getAsBoolean()
P Supplier p getAsP ()
P Consumer void accept(p p)
ObjP Consumer<T> void accept(T t, p p)
P Function<T> T apply(p p)
P ToQ Function q applyAsQ (p p)
ToP Function<T> p applyAsP (T t)
ToP BiFunction<T, U> p applyAsP (T t, U u)
P UnaryOperator p applyAsP (p p)
P BinaryOperator p applyAsP (p p1, p p2)
P Predicate boolean test(p p)
※「実践本」より抜粋
※p とq は、int、long、double。P とQ は、Int、Long、Double
ポイント⑥ ソースコードを読む
ラムダ式を引数に取るメソッドのソースコードを
読んで、どのように実行されているかを見る
34
default V compute(K key, Function<K, V> remappingFunction) {
V oldValue = get(key);
V newValue = remappingFunction.apply(key, oldValue);
put(key, newValue);
return newValue;
}
Map#compute()のソース(単純化しています)
Map<String, Integer> map = new HashMap<>();
・・・
int value = map.compute(“apple”, (k, v) -> v + 10);
ポイント⑦ デバッグプリント
ラムダ式内にデバッグプリントを入れて、引数に
何が入っているかを確認する
35
String s = map.compute(“apple”, (String k, Integer v) -> {
System.out.println(“k = ” + k + “, v = ” + v);
return v + 10;
});
36
ステップ2:
Streamを生成しよう!
Stream APIとは?
コレクションを操作するためのAPI
データの抽出・加工・集計などを行う
Stream内には基本的にデータは持たない
元のコレクションは変えない
37
Stream<T>
元のコレクション コレクション
合計
・平均
Collection<T>、T[]
生成・中間操作・終端操作
38
public static List<Emp> sortBySalaryAsc() {
// Streamの生成
return EMP_LIST.stream()
// 中間操作
.sorted((Emp e1, Emp e2)
-> { return e1.getSalary() - e2.getSalary(); })
// 終端操作
.collect(Collectors.toList());
}
Streamの生成
コレクションなどのソースからStreamを生成する
中間操作
ソート・フィルタリング・変換などを行い、Streamを返す。
複数回実行可能
終端操作
結果をコレクションなどに集約する。1回のみ実行可能
Streamの生成
コレクションから生成
39
List<String> list = Arrays.asList("hoge", "fuga", "foo");
Stream<String> stream = list.stream();
可変長引数で生成
Stream<String> stream = Stream.of("hoge", "fuga", "foo");
配列から生成
String[] strings = {"hoge", "fuga", "foo"};
Stream<String> stream = Arrays.stream(strings);
その他
Stream.generate()、Stream.iterate()、Files.lines()、・・・
パラレルStreamの生成
parallelStream()メソッドを利用
40
List<String> list = Arrays.asList("hoge", "fuga", "foo");
Stream<String> stream = list.paralellStream();
parallel()メソッドを利用
Stream<String> stream = Stream.of("hoge", "fuga", "foo");
Stream<String> paraStream = stream.parallel();
基本データ型用のStream
IntStream
LongStream
DoubleStream
中間操作でStream<T>などと相互変換可能
(後述)
41
IntStreamの生成
1~9まで
42
IntStream intStream = IntStream.range(1, 10);
配列から生成
int[] ints = {1, 2, 3, 4, 5};
IntStream intStream = Arrays.stream(ints);
その他
IntStream.generate()、IntStream.iterate()、・・・
1~10まで
IntStream intStream = IntStream.rangeClosed(1, 10);
charのStream
用意されていないので、Stream<Character>を
利用する
43
// A~ZまでのIntStreamを生成
IntStream intStream = IntStream.rangeClosed('A', 'Z');
// 中間操作でStreamに変換
Stream<Character> charStream
= intStream.mapToObj((int i) -> { return (char) i; });
44
ステップ3:
中間操作でデータを操作しよう!
サンプルプログラム
社員クラス
45
public class Emp {
private int id; // 社員番号
private String name; // 社員名
private int salary; // 給与
private Dept dept; // 部署を表すEnum
// setter/getter、コンストラクタ、toString()は省略
}
public enum Dept {
ADMIN, PLANNING, SALES, OPERATIONS, NONE;
}
サンプルプログラム
46
public class EmpDB {
private static final List<Emp> EMP_LIST = Arrays.asList(
new Emp(101, "Nishida", 500000, Dept.ADMIN),
new Emp(102, “Nohira”, 285000, Dept.SALES),
new Emp(103, "Kiyama", 245000, Dept.ADMIN),
new Emp(104, "Ohkawa", 297500, Dept.PLANNING),
new Emp(105, "Kajiyama", 125000, Dept.SALES),
new Emp(106, "Kohsaka", 160000, Dept.SALES),
new Emp(107, "Nishikawa", 150000, Dept.SALES),
new Emp(108, "Sasaki", 95000, Dept.SALES),
new Emp(109, "Ichikawa", 125000, Dept.SALES),
new Emp(110, "Yamamoto", 300000, Dept.PLANNING),
new Emp(111, "Komatsu", 80000, Dept.PLANNING),
new Emp(112, "Aizawa", 300000, Dept.PLANNING),
new Emp(113, "Saitoh", 110000, Dept.NONE),
new Emp(114, "Inoue", 130000, Dept.ADMIN));
// ここにメソッドを書く
}
Stream#filter()メソッド
Stream<T> filter(Predicate<T> predicate)
Stream内の全要素(T)に条件predicateを指定し、
それがtrueとなる要素のみ抽出する
47
public interface Predicate<T> {
boolean test(T t);
}
※本当の引数は「Predicate<? super T>」ですが、読みづらいため省略しています。
<? super T>の意味が知りたい方は実践本P.74~P.76をご覧ください
特定の部署で抽出する
48
public static List<Emp> filterByDept() {
// Streamを生成
Stream<Emp> stream = EMP_LIST.stream();
// 部署がSALESの社員のみ抽出(中間操作)
Stream<Emp> filteredStream
= stream.filter(
(Emp emp) -> { return emp.getDept() == Dept.SALES; });
// 結果をリストに集約(終端操作)
List<Emp> result = filteredStream.collect(Collectors.toList());
}
Emp{id=102, name=Nohira, salary=285000, dept=SALES}
Emp{id=105, name=Kajiyama, salary=125000, dept=SALES}
Emp{id=106, name=Kohsaka, salary=160000, dept=SALES}
Emp{id=107, name=Nishikawa, salary=150000, dept=SALES}
Emp{id=108, name=Sasaki, salary=95000, dept=SALES}
Emp{id=109, name=Ichikawa, salary=125000, dept=SALES}
メソッドチェーン&ラムダ省略で書く
49
public static List<Emp> filterByDept() {
return EMP_LIST.stream()
.filter(emp -> emp.getDept() == Dept.SALES)
.collect(Collectors.toList());
}
下記のように記述することが一般的
型の変換が見えにくいため、慣れないうちはあ
まりおススメできない
ポイント⑧ メソッドチェーン禁止
50
1行1行ていねいに書く!
慣れてきたらメソッドチェーンで書けばよい
Stream#map()メソッド
Stream<R> map(Function<T, R> mapper)
Stream内の全要素をapply()メソッドの引数に渡し、
その戻り値から成るStreamを返す
apply()でreturnした値の型がRとなる
51
public interface Function<T, R> {
R apply(T t);
}
名前だけのリストに変換する
52
public static List<String> getNameList() {
Stream<Emp> stream = EMP_LIST.stream();
Stream<String> nameStream
= stream.map((Emp emp) -> { return emp.getName();});
List<String> result = nameStream.collect(Collectors.toList());
return result;
}
Nishida
Nohira
Kiyama
Ohkawa
Kajiyama
Kohsaka
Nishikawa
・・・
map()による型変換
53
Stream<Emp> stream = EMP_LIST.stream();
Stream<String> nameStream
= stream.map((Emp emp) -> { return emp.getName();});
戻り値の型が
String
型引数(R)が
Stringに決まる
public class EmpNameMapper implements Function<Emp, String> {
public String apply(Emp emp) {
return emp.getName();
}
}
こんなイメージ
ポイント⑨ 「R」は自分で決められる型
54
「T」のような自動的に決まる型と、
「R」のような自分で決められる型がある!
IntStreamとの相互変換
55
Stream<T>
IntStream
mapToInt() mapToObj()
IntStreamとの相互変換
56
Stream<Emp> stream = EMP_LIST.stream();
IntStream salaryStream
= stream.mapToInt((Emp emp) -> { return emp.getSalary();})
IntStream idStream = IntStream.rangeClosed(101, 110);
Stream<Emp> empStream
= idStream.mapToObj((int id) -> { return new Emp(id);})
IntStream mapToInt(ToIntFunction<T> mapper)
Streamの要素(T)が引数、戻り値がintであるラムダを指定
Stream<T> mapToObj(IntFunction<T> mapper)
IntStreamの要素(int)が引数、戻り値がTであるラムダを指定
intを返すように指定
オブジェクトを返すように指定
中間操作と終端操作が分かれている理由
繰り返しの回数を減らすため
filter()する度に繰り返しを行っていたら効率が悪い
(下左のようなコードになる)
終端操作の際に、全ての中間操作をまとめて実行
57
for (Emp emp : list) {
if (emp.getDept() == Dept.SALES) {
// 処理
}
}
for (Emp emp : list) {
if (emp.getSalary() >= 150000) {
// 処理
}
}
for (Emp emp : list) {
if (emp.getDept() == Dept.SALES) {
// 処理
}
if (emp.getSalary() >= 150000) {
// 処理
}
}
繰り返し2回→効率× 繰り返し1回→効率○
※このコードはイメージです
ポイント⑩ 中間操作はsetterと考える
58
public class Stream<T> {
private Predicate<T> pred;
public Stream<T> filter(Predicate<T> pred) {
this.pred = pred;
}
public R collect(・・・) {
for (T t : elements) {
if (pred.test(t)) {
// tを結果に追加
}
}
}
}
※このコードはイメージです
中間操作の時点では、
条件は中に保持するだけ
終端操作の時点で、
条件を実行
これを「遅延実行」と呼んでいるだけ
その他の中間操作
Stream<T> sorted(Comparator<T> comparator)
要素を並び替える
Stream<R> flatMap(Function<T, Stream<R>>
mapper)
各要素からStreamを生成し、それらを一本化する
59
その他の中間操作
Stream<T> distinct()
重複を削除する(Object#equals()がtrueとなるものは重
複と見なされる)
Stream<T> limit(long maxSize)
最初の要素から、最大maxSize個までの要素のみを含
んだStreamを返す
Stream<T> skip(long n)
最初の要素から数えてn個の要素を破棄し、残りの要素
のみを含んだStreamを返す
Stream<T> peek(Consumer<T> action)
forEach()の中間操作バージョン(デバッグが主目的)
60
中間操作が分かると・・・
読める行数が飛躍的に増加
61
public static List<String> filterByDeptAndSalarySortById() {
return EMP_LIST.stream()
// DeptがSALESの人のみ抽出
.filter(emp -> emp.getDept() == Dept.SALES)
// 給与が150000以上の人のみ抽出
.filter(emp -> emp.getSalary() >= 150000)
// IDの昇順で並び替え
.sorted((e1, e2) -> e1.getId() - e2.getId())
// 「ID : 給与」という文字列に変換
.map(emp -> emp.getId() + " : " + emp.getSalary())
// 文字列のリストに集約
.collect(Collectors.toList());
}
62
ステップ4:
終端操作で好きな値に
変換しよう!
Stream#collect()メソッド
Streamを任意のコレクションなどに集約する
引数はCollectorインターフェイス(後述)
63
Collectorsクラス
汎用のCollectorを返すファクトリークラス
主なメソッド
toList()
リストに変換するCollectorを返す
toMap()
マップに変換するCollectorを返す
groupingBy()
マップにグループ化するCollectorを返す
counting()
要素の個数を数えるCollectorを返す
64
Collectors.toList()メソッド
65
public static List<Emp> filterByDept() {
Stream<Emp> stream = EMP_LIST.stream();
Stream<Emp> filteredStream
= stream.filter((Emp emp) -> {
return emp.getDept() == Dept.SALES; });
List<Emp> result = filteredStream.collect(Collectors.toList());
}
Collectors.toMap()メソッド
toMap(Function<T, K> keyMapper,
Function<T, U> valueMapper)
T:Streamの要素の型
K:マップのキーとなる型(自分で決められる)
U:マップの値となる型(自分で決められる)
例:社員IDがキー、社員名が値のマップに変換
66
public static Map<Integer, String> getIdNameMap() {
Stream<Emp> stream = EMP_LIST.stream();
Map<Integer, String> map = stream.collect(Collectors.toMap(
(Emp emp) -> { return emp.getId();}, // マップのキー
(Emp emp) -> { return emp.getName();})); // マップの値
return map;
}
Collectors.groupingBy()メソッド
groupingBy(Function<T, K> classifier)
T:Streamの要素の型
K:マップのキーとなる型(自分で決められる)
例:部署がキー、その部署に所属する社員のリスト
が値のマップに変換
67
public static Map<Dept, List<Emp>> groupByDept() {
Stream<Emp> stream = EMP_LIST.stream();
Map<Dept, List<Emp>> map
= stream.collect(Collectors.groupingBy(
(Emp emp) -> { return emp.getDept();})); // マップのキー
return map;
}
Collectors.groupingBy()メソッド
groupingBy(Function<T, K> classifier,
Collector<T, A, D> downstream)
T:Streamの要素の型
K:マップのキーとなる型(自分で決められる)
A、Dは後述
例:部署がキー、その部署に所属する社員の人数が値のマップに変換
68
public static Map<Dept, Long> groupByDeptAndCounting() {
Stream<Emp> stream = EMP_LIST.stream();
Map<Dept, Long> map = stream.collect(Collectors.groupingBy(
(Emp emp) -> { return emp.getDept();}, // マップのキー
Collectors.counting())); // マップの値
return map;
}
Collectors.groupingBy()メソッド
例:部署がキー、その部署に所属する社員の給与の合計
が値のマップに変換
69
public static Map<Dept, Long> groupByDeptAndSummingSal() {
Stream<Emp> stream = EMP_LIST.stream();
Map<Dept, Long> map = stream.collect(Collectors.groupingBy(
(Emp emp) -> { return emp.getDept();}, // マップのキー
Collectors.summingLong(
(Emp emp) -> { return emp.getSalary(); } ))); // マップの値
return map;
}
ポイント⑪ 好きな型に集約する手順
① 要素(T)を蓄積するコンテナ(A)を生成する
→サプライヤで生成
② 要素(T)をコンテナ(A)に蓄積する
→アキュムレータで蓄積
③ コンテナ(A)をマージする(パラレル実行の場合)
→コンバイナでマージ
④ コンテナ(A)を最終的に返す型(R)に変換する
→フィニッシャで変換
(コンテナをそのまま返す場合は不要)
70
Collector<T, A, R>インターフェイス
T:Streamの要素、A:コンテナ、R:最終的に返す型
4つのメソッドを持つ
Supplier<A> supplier()
BiConsumer<A, T> accumulator()
BinaryOperator<A> combiner()
Function<A, R> finisher()
Collector.of()メソッドで、
実装クラス(Collectors.CollectorImplクラス)の
インスタンスを生成して返す
71
Collectors.toList()のソースを読む
72
public static <T> Collector<T, ArrayList<T>, List<T>> toList() {
Supplier<ArrayList<T>> supplier = () -> {
return new ArrayList<>(); // コンテナを生成
};
BiConsumer<ArrayList<T>, T> accumulator = (ArrayList<T> list, T t) -> {
list.add(t); // 要素をコンテナに蓄積
};
BinaryOperator<ArrayList<T>> combiner
= (ArrayList<T> list1, ArrayList<T> list2) -> {
list1.addAll(list2); // コンテナをマージ
return list1;
};
Function<ArrayList<T>, List<T>> finisher = (ArrayList<T> list) -> {
return (List<T>) list; // コンテナを最終的に返す型に変換
};
return Collector.of(supplier, accumulator, combiner, finisher);
}
※このコードはイメージです
Collectors.toMap()のソースを読む
73
public static <T, K, U> Collector<T, HashMap<K, U>, Map<K,U>>
toMap(Function<T, K> keyMapper, Function<T, U> valueMapper) {
Supplier<HashMap<K, U>> supplier = () -> {
return new HashMap<>(); // コンテナを生成
};
BiConsumer<HashMap<K, U>, T> accumulator
= (HashMap<K, U> map, T t) -> {
map.put(keyMapper.apply(t), valueMapper.apply(t)); // 要素をコンテナに蓄積
};
BinaryOperator<HashMap<K, U>> combiner
= (HashMap<K, U> map1, HashMap<K, U> map2) -> {
/* 長いので省略 */ // コンテナをマージ
};
Function<HashMap<K, U>, Map<K, U>> finisher = (HashMap<K, U> map) -> {
return (Map<K, U>) map; // コンテナを最終的に返す型に変換
};
return Collector.of(supplier, accumulator, combiner, finisher);
}
※このコードはイメージです
Stream#collect()のソースを読む
74
public <T, A, R> R collect(Collector<T, A, R> collector) {
Supplier<A> supplier = collector.supplier();
A container = supplier.get(); // コンテナを生成
BiConsumer<A, T> accumulator = collector.accumulator();
forEach((T t) -> {
accumulator.accept(container, t); // 要素をコンテナに蓄積
});
BinaryOperator<A> combiner = collector.combiner();
container = combiner.apply(container1, container2); // コンテナをマージ
Function<A, R> finisher = collector.finisher();
R result = finisher.apply(container); // コンテナを最終的に返す型に変換
return result;
}
※このコードはイメージです
最初のコード(再掲)
75
public static Map<Character, Integer> countByInitial() {
return EMP_LIST.stream()
.collect(Collector.of(
() -> IntStream.rangeClosed('A', 'Z')
.mapToObj(i -> (char) i)
.collect(Collectors.toMap(c -> c, c -> 0)),
(map, emp) -> map.compute(emp.getName().charAt(0),
(initial, count) -> ++count),
(map1, map2) -> {
map1.forEach((initial, count) ->
map1.put(initial, count + map2.get(initial));
return map1;
},
map -> Collections.unmodifiableMap(map)));
}
やりたいこと(仕様)
List<Emp>をMap<Character, Integer>に変換
する
Mapのキーは、A~Zまでのイニシャル
Mapの値は、そのイニシャルの人数
そのイニシャルがいない場合、値は0
結果のMapはイミュータブル(変更不可能)
76
①サプライヤ
Map<Character, Integer>を生成
→A~Zまでの文字をキーとし、各値に0をput
77
Supplier<Map<Character, Integer>> supplier = () -> {
IntStream stream = IntStream.rangeClosed('A', 'Z');
Stream<Character> charStream
= stream.mapToObj((int i) -> { return (char) i; });
Map<Character, Integer> map
= charStream.collect(Collectors.toMap(
(Character c) -> { return c; },
(Character c) -> { return 0; }));
return map;
};
②アキュムレータ
①のMapとEmpが引数。Empのnameからイニシ
ャルを取得し、それに対応するMapの値をインク
リメント
78
BiConsumer<Map<Character, Integer>, Emp> accumulator =
(Map<Character, Integer> map, Emp emp) -> {
char initial = emp.getName().charAt(0);
map.compute(initial, (Character k, Integer v) -> ++v);
};
③コンバイナ
2つのMapをマージする。一方のMapの全キーに
対して、2つのMapの合計値をput
79
BinaryOperator<Map<Character, Integer>> combiner =
(Map<Character, Integer> map1,
Map<Character, Integer> map2) -> {
map1.forEach((Character initial, Integer count1) -> {
int count2 = map2.get(initial);
map1.put(initial, count1 + count2);
});
return map1;
};
④フィニッシャ
Mapをイミュータブルに変換する
80
Function<Map<Character, Integer>,
Map<Character, Integer>> finisher =
(Map<Character, Integer> map) ->
{ return Collections.unmodifiableMap(map); };
まとめると、こうなる
81
public static Map<Character, Integer> countByInitial() {
Supplier<Map<Character, Integer>> supplier = ・・・;
BiConsumer<Map<Character, Integer>, Emp> accumulator = ・・・;
BinaryOperator<Map<Character, Integer>> combiner = ・・・;
Function<Map<Character, Integer>, Map<Character, Integer>>
finisher = ・・・;
Collector<Emp, Map<Character, Integer>, Map<Character, Integer>>
collector = Collector.of(supplier, accumulator, combiner, finisher);
return EMP_LIST.stream().collect(collector);
}
無理やり1文にすると、こうなる
82
public static Map<Character, Integer> countByInitial() {
return EMP_LIST.stream()
.collect(Collector.of(
() -> IntStream.rangeClosed('A', 'Z')
.mapToObj(i -> (char) i)
.collect(Collectors.toMap(c -> c, c -> 0)),
(map, emp) -> map.compute(emp.getName().charAt(0),
(initial, count) -> ++count),
(map1, map2) -> {
map1.forEach((initial, count) ->
map1.put(initial, count + map2.get(initial));
return map1;
},
map -> Collections.unmodifiableMap(map)));
}
ポイント⑫ Collectorを自作する場合
サプライヤなどは、一旦変数に入れた方が
可読性が上がる
無理に1文で書くと読みづらい
閉じカッコの数が合わなかったりして地味に辛い
IDEが真っ赤っかになってコンパイルエラーの箇所が
特定しづらい
83
その他の終端操作
Optional<T> reduce(BinaryOperator<T>
accumulator)
全要素に対して順に演算を行う
long count()
Streamに含まれる要素数を返す
Optional<T> max(Comparator<T> comparator)
指定したComparatorの順で最大(順番が最後)の値を
返す(Streamが空の場合は、空のOptional)
Optional<T> min(Comparator<T> comparator)
指定したComparatorの順で最小(順番が最初)の値を
返す(Streamが空の場合は、空のOptional)
84
その他の終端操作
boolean allMatch(Predicate<T> predicate)
Streamに含まれる全要素が引数の条件に合致する
場合、trueを返す
boolean anyMatch(Predicate<T> predicate)
Streamに含まれるいずれかの要素が引数の条件に
合致する場合、trueを返す
boolean noneMatch(Predicate<T> predicate)
Streamに含まれる全要素が引数の条件に合致しな
い場合、trueを返す
85
その他の終端操作
Optional<T> findFirst()
Stream内の各要素を順番に検索し、条件(filter()な
どで指定)に合致した最初の要素を返す
Optional<T> findAny()
Stream内の各要素を並列で検索し、条件(filter()な
どで指定)に合致した、最初に見つかった要素を返
す
実行の度に戻り値が異なる場合があるので注意
86
87
ステップ5:
何でもかんでも
ラムダ式・Stream APIで書こう!
汎用関数型インターフェイスとラムダ式の練習
88
わざとFunctionやPredicateを使って書いてみる
ラムダ式と汎用関数型インターフェイスを理解す
る練習になる
String name = emp.getName();
↓
Function<Emp, String> func = e -> e.getName();
String name = func.apply(emp);
if (emp.getSalary() >= 150000) { ・・・ }
↓
Predicate<Emp> pred = e -> e.getSalary() >= 150000
if (pred.test(emp)) { ・・・ }
汎用関数型インターフェイスとラムダ式の練習
89
Functionなどを引数とするメソッドを自作する
Java SE 8での定石
forやwhileを見たらStream APIへの置き換えを
考える!(@cero_tさん)
forEach()使ったら負け! (@skrbさん)
null書いたら負け! (@kisさん)
90
繰り返しをStream APIで書き換える練習
1~20までの偶数のみの和を求める
91
int sum = IntStream.rangeClosed(1, 20).filter(i -> i % 2 == 0) .sum();
int sum = IntStream.rangeClosed(1, 10).map(i -> i * 2) .sum();
int sum = IntStream.rangeClosed(1, 10).map(i -> i * 2)
.reduce(0, (i1, i2) -> i1 + i2);
FizzBuzz
List<String> list = IntStream.rangeClosed(1, 40)
.mapToObj(i -> i % 15 == 0 ? "FizzBuzz"
: i % 3 == 0 ? "Fizz"
: i % 5 == 0 ? "Buzz"
: String.valueOf(i))
.collect(Collectors.toList());
「何でもかんでもラムダ式・Stream APIで
書けばいいって訳じゃないよねー」
とは言いますが、でもそれって
「何でもかんでもラムダ式・Stream API
で書ける実力」
があってこそではないでしょうか?
(自戒も込めて・・・)
まずはチャレンジしてみてください!
92
あの日を思い出してください
初めてプログラミング言語に触れたあの日・・・
何でもかんでも順次・分岐・繰り返しで書いて、
楽しんでいたのではないでしょうか?
その気持ちを思い出して、何でもかんでも
ラムダ式・Stream APIで書いてみてください
そのうちに自然と身に付きます!
93
最後のまとめ
慣れるまでは、ラムダ式は引数の型・returnなどを
省略せずに書こう!
Stream APIは、無理してメソッドチェーンを使わない
でOK。まずは型の変換をしっかり理解しよう!
Collectorインターフェイスを極めよう!
何でもかんでもラムダ式・Stream APIで書いて、
どんどん慣れていこう!
94
Enjoy Java SE 8 !!
95
ご清聴ありがとう
ございました!

More Related Content

What's hot

入社1年目のプログラミング初心者がSpringを学ぶための手引き
入社1年目のプログラミング初心者がSpringを学ぶための手引き入社1年目のプログラミング初心者がSpringを学ぶための手引き
入社1年目のプログラミング初心者がSpringを学ぶための手引き土岐 孝平
 
さくっと理解するSpring bootの仕組み
さくっと理解するSpring bootの仕組みさくっと理解するSpring bootの仕組み
さくっと理解するSpring bootの仕組みTakeshi Ogawa
 
これから始めるSpringのwebアプリケーション
これから始めるSpringのwebアプリケーションこれから始めるSpringのwebアプリケーション
これから始めるSpringのwebアプリケーション土岐 孝平
 
JAVA_HOME/binにあるコマンド、いくつ使っていますか?[JVM関連ツール編](JJUGナイトセミナー「Java解析ツール特集」 発表資料)
JAVA_HOME/binにあるコマンド、いくつ使っていますか?[JVM関連ツール編](JJUGナイトセミナー「Java解析ツール特集」 発表資料)JAVA_HOME/binにあるコマンド、いくつ使っていますか?[JVM関連ツール編](JJUGナイトセミナー「Java解析ツール特集」 発表資料)
JAVA_HOME/binにあるコマンド、いくつ使っていますか?[JVM関連ツール編](JJUGナイトセミナー「Java解析ツール特集」 発表資料)NTT DATA Technology & Innovation
 
スレッドダンプの読み方
スレッドダンプの読み方スレッドダンプの読み方
スレッドダンプの読み方Funato Takashi
 
ここが変だよ、グローバルスタンダードの脆弱性対策~入力値の考え方~
ここが変だよ、グローバルスタンダードの脆弱性対策~入力値の考え方~ここが変だよ、グローバルスタンダードの脆弱性対策~入力値の考え方~
ここが変だよ、グローバルスタンダードの脆弱性対策~入力値の考え方~Hiroshi Tokumaru
 
怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション土岐 孝平
 
ドメイン駆動設計のための Spring の上手な使い方
ドメイン駆動設計のための Spring の上手な使い方ドメイン駆動設計のための Spring の上手な使い方
ドメイン駆動設計のための Spring の上手な使い方増田 亨
 
Spring bootでweb 基本編
Spring bootでweb 基本編Spring bootでweb 基本編
Spring bootでweb 基本編なべ
 
SparkとCassandraの美味しい関係
SparkとCassandraの美味しい関係SparkとCassandraの美味しい関係
SparkとCassandraの美味しい関係datastaxjp
 
今さら聞けないDiとspring
今さら聞けないDiとspring今さら聞けないDiとspring
今さら聞けないDiとspring土岐 孝平
 
これからSpringを使う開発者が知っておくべきこと
これからSpringを使う開発者が知っておくべきことこれからSpringを使う開発者が知っておくべきこと
これからSpringを使う開発者が知っておくべきこと土岐 孝平
 
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところ
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところ
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところY Watanabe
 
はまる!JPA(初学者向けライト版)
はまる!JPA(初学者向けライト版)はまる!JPA(初学者向けライト版)
はまる!JPA(初学者向けライト版)Masatoshi Tada
 
Practical migration from JSP to Thymeleaf
Practical migration from JSP to Thymeleaf Practical migration from JSP to Thymeleaf
Practical migration from JSP to Thymeleaf Toshiki Iga
 
例外設計における大罪
例外設計における大罪例外設計における大罪
例外設計における大罪Takuto Wada
 
GraalVMを3つの主機能から眺めてみよう(Oracle Groundbreakers APAC Virtual Tour 2020 講演資料)
GraalVMを3つの主機能から眺めてみよう(Oracle Groundbreakers APAC Virtual Tour 2020 講演資料)GraalVMを3つの主機能から眺めてみよう(Oracle Groundbreakers APAC Virtual Tour 2020 講演資料)
GraalVMを3つの主機能から眺めてみよう(Oracle Groundbreakers APAC Virtual Tour 2020 講演資料)NTT DATA Technology & Innovation
 
ジェネリクスの基礎と クラス設計への応用
ジェネリクスの基礎とクラス設計への応用ジェネリクスの基礎とクラス設計への応用
ジェネリクスの基礎と クラス設計への応用nagise
 
Springを何となく使ってる人が抑えるべきポイント
Springを何となく使ってる人が抑えるべきポイントSpringを何となく使ってる人が抑えるべきポイント
Springを何となく使ってる人が抑えるべきポイント土岐 孝平
 
O/Rマッパーによるトラブルを未然に防ぐ
O/Rマッパーによるトラブルを未然に防ぐO/Rマッパーによるトラブルを未然に防ぐ
O/Rマッパーによるトラブルを未然に防ぐkwatch
 

What's hot (20)

入社1年目のプログラミング初心者がSpringを学ぶための手引き
入社1年目のプログラミング初心者がSpringを学ぶための手引き入社1年目のプログラミング初心者がSpringを学ぶための手引き
入社1年目のプログラミング初心者がSpringを学ぶための手引き
 
さくっと理解するSpring bootの仕組み
さくっと理解するSpring bootの仕組みさくっと理解するSpring bootの仕組み
さくっと理解するSpring bootの仕組み
 
これから始めるSpringのwebアプリケーション
これから始めるSpringのwebアプリケーションこれから始めるSpringのwebアプリケーション
これから始めるSpringのwebアプリケーション
 
JAVA_HOME/binにあるコマンド、いくつ使っていますか?[JVM関連ツール編](JJUGナイトセミナー「Java解析ツール特集」 発表資料)
JAVA_HOME/binにあるコマンド、いくつ使っていますか?[JVM関連ツール編](JJUGナイトセミナー「Java解析ツール特集」 発表資料)JAVA_HOME/binにあるコマンド、いくつ使っていますか?[JVM関連ツール編](JJUGナイトセミナー「Java解析ツール特集」 発表資料)
JAVA_HOME/binにあるコマンド、いくつ使っていますか?[JVM関連ツール編](JJUGナイトセミナー「Java解析ツール特集」 発表資料)
 
スレッドダンプの読み方
スレッドダンプの読み方スレッドダンプの読み方
スレッドダンプの読み方
 
ここが変だよ、グローバルスタンダードの脆弱性対策~入力値の考え方~
ここが変だよ、グローバルスタンダードの脆弱性対策~入力値の考え方~ここが変だよ、グローバルスタンダードの脆弱性対策~入力値の考え方~
ここが変だよ、グローバルスタンダードの脆弱性対策~入力値の考え方~
 
怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション
 
ドメイン駆動設計のための Spring の上手な使い方
ドメイン駆動設計のための Spring の上手な使い方ドメイン駆動設計のための Spring の上手な使い方
ドメイン駆動設計のための Spring の上手な使い方
 
Spring bootでweb 基本編
Spring bootでweb 基本編Spring bootでweb 基本編
Spring bootでweb 基本編
 
SparkとCassandraの美味しい関係
SparkとCassandraの美味しい関係SparkとCassandraの美味しい関係
SparkとCassandraの美味しい関係
 
今さら聞けないDiとspring
今さら聞けないDiとspring今さら聞けないDiとspring
今さら聞けないDiとspring
 
これからSpringを使う開発者が知っておくべきこと
これからSpringを使う開発者が知っておくべきことこれからSpringを使う開発者が知っておくべきこと
これからSpringを使う開発者が知っておくべきこと
 
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところ
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところ
ツール比較しながら語る O/RマッパーとDBマイグレーションの実際のところ
 
はまる!JPA(初学者向けライト版)
はまる!JPA(初学者向けライト版)はまる!JPA(初学者向けライト版)
はまる!JPA(初学者向けライト版)
 
Practical migration from JSP to Thymeleaf
Practical migration from JSP to Thymeleaf Practical migration from JSP to Thymeleaf
Practical migration from JSP to Thymeleaf
 
例外設計における大罪
例外設計における大罪例外設計における大罪
例外設計における大罪
 
GraalVMを3つの主機能から眺めてみよう(Oracle Groundbreakers APAC Virtual Tour 2020 講演資料)
GraalVMを3つの主機能から眺めてみよう(Oracle Groundbreakers APAC Virtual Tour 2020 講演資料)GraalVMを3つの主機能から眺めてみよう(Oracle Groundbreakers APAC Virtual Tour 2020 講演資料)
GraalVMを3つの主機能から眺めてみよう(Oracle Groundbreakers APAC Virtual Tour 2020 講演資料)
 
ジェネリクスの基礎と クラス設計への応用
ジェネリクスの基礎とクラス設計への応用ジェネリクスの基礎とクラス設計への応用
ジェネリクスの基礎と クラス設計への応用
 
Springを何となく使ってる人が抑えるべきポイント
Springを何となく使ってる人が抑えるべきポイントSpringを何となく使ってる人が抑えるべきポイント
Springを何となく使ってる人が抑えるべきポイント
 
O/Rマッパーによるトラブルを未然に防ぐ
O/Rマッパーによるトラブルを未然に防ぐO/Rマッパーによるトラブルを未然に防ぐ
O/Rマッパーによるトラブルを未然に防ぐ
 

Viewers also liked

【java8 勉強会】 怖くない!ラムダ式, Stream API
【java8 勉強会】 怖くない!ラムダ式, Stream API【java8 勉強会】 怖くない!ラムダ式, Stream API
【java8 勉強会】 怖くない!ラムダ式, Stream APIdcomsolution
 
Java EE 8先取り!MVC 1.0入門 [EDR2対応版] 2015-10-10更新
Java EE 8先取り!MVC 1.0入門 [EDR2対応版] 2015-10-10更新Java EE 8先取り!MVC 1.0入門 [EDR2対応版] 2015-10-10更新
Java EE 8先取り!MVC 1.0入門 [EDR2対応版] 2015-10-10更新Masatoshi Tada
 
JPAの同時実行制御とロック20140518 #ccc_r15 #jjug_ccc
JPAの同時実行制御とロック20140518 #ccc_r15 #jjug_cccJPAの同時実行制御とロック20140518 #ccc_r15 #jjug_ccc
JPAの同時実行制御とロック20140518 #ccc_r15 #jjug_cccMasatoshi Tada
 
NetBeansでかんたんJava EE ○分間クッキング! #kuwaccho lt
NetBeansでかんたんJava EE ○分間クッキング! #kuwaccho ltNetBeansでかんたんJava EE ○分間クッキング! #kuwaccho lt
NetBeansでかんたんJava EE ○分間クッキング! #kuwaccho ltMasatoshi Tada
 
徹底解説!Project Lambdaのすべて[JJUG CCC 2013 Fall H-2]
徹底解説!Project Lambdaのすべて[JJUG CCC 2013 Fall H-2]徹底解説!Project Lambdaのすべて[JJUG CCC 2013 Fall H-2]
徹底解説!Project Lambdaのすべて[JJUG CCC 2013 Fall H-2]bitter_fox
 
Getting start Java EE Action-Based MVC with Thymeleaf
Getting start Java EE Action-Based MVC with ThymeleafGetting start Java EE Action-Based MVC with Thymeleaf
Getting start Java EE Action-Based MVC with ThymeleafMasatoshi Tada
 
Java EEハンズオン資料 JJUG CCC 2015 Fall
Java EEハンズオン資料 JJUG CCC 2015 FallJava EEハンズオン資料 JJUG CCC 2015 Fall
Java EEハンズオン資料 JJUG CCC 2015 FallMasatoshi Tada
 
地域の魅力を伝えるツアーガイドAI
地域の魅力を伝えるツアーガイドAI地域の魅力を伝えるツアーガイドAI
地域の魅力を伝えるツアーガイドAIJubatusOfficial
 
Dockerで始める Java EE アプリケーション開発 for JJUG CCC 2017
Dockerで始める Java EE アプリケーション開発 for JJUG CCC 2017Dockerで始める Java EE アプリケーション開発 for JJUG CCC 2017
Dockerで始める Java EE アプリケーション開発 for JJUG CCC 2017Kohei Saito
 
Java SE 9の紹介: モジュール・システムを中心に
Java SE 9の紹介: モジュール・システムを中心にJava SE 9の紹介: モジュール・システムを中心に
Java SE 9の紹介: モジュール・システムを中心にTaku Miyakawa
 

Viewers also liked (10)

【java8 勉強会】 怖くない!ラムダ式, Stream API
【java8 勉強会】 怖くない!ラムダ式, Stream API【java8 勉強会】 怖くない!ラムダ式, Stream API
【java8 勉強会】 怖くない!ラムダ式, Stream API
 
Java EE 8先取り!MVC 1.0入門 [EDR2対応版] 2015-10-10更新
Java EE 8先取り!MVC 1.0入門 [EDR2対応版] 2015-10-10更新Java EE 8先取り!MVC 1.0入門 [EDR2対応版] 2015-10-10更新
Java EE 8先取り!MVC 1.0入門 [EDR2対応版] 2015-10-10更新
 
JPAの同時実行制御とロック20140518 #ccc_r15 #jjug_ccc
JPAの同時実行制御とロック20140518 #ccc_r15 #jjug_cccJPAの同時実行制御とロック20140518 #ccc_r15 #jjug_ccc
JPAの同時実行制御とロック20140518 #ccc_r15 #jjug_ccc
 
NetBeansでかんたんJava EE ○分間クッキング! #kuwaccho lt
NetBeansでかんたんJava EE ○分間クッキング! #kuwaccho ltNetBeansでかんたんJava EE ○分間クッキング! #kuwaccho lt
NetBeansでかんたんJava EE ○分間クッキング! #kuwaccho lt
 
徹底解説!Project Lambdaのすべて[JJUG CCC 2013 Fall H-2]
徹底解説!Project Lambdaのすべて[JJUG CCC 2013 Fall H-2]徹底解説!Project Lambdaのすべて[JJUG CCC 2013 Fall H-2]
徹底解説!Project Lambdaのすべて[JJUG CCC 2013 Fall H-2]
 
Getting start Java EE Action-Based MVC with Thymeleaf
Getting start Java EE Action-Based MVC with ThymeleafGetting start Java EE Action-Based MVC with Thymeleaf
Getting start Java EE Action-Based MVC with Thymeleaf
 
Java EEハンズオン資料 JJUG CCC 2015 Fall
Java EEハンズオン資料 JJUG CCC 2015 FallJava EEハンズオン資料 JJUG CCC 2015 Fall
Java EEハンズオン資料 JJUG CCC 2015 Fall
 
地域の魅力を伝えるツアーガイドAI
地域の魅力を伝えるツアーガイドAI地域の魅力を伝えるツアーガイドAI
地域の魅力を伝えるツアーガイドAI
 
Dockerで始める Java EE アプリケーション開発 for JJUG CCC 2017
Dockerで始める Java EE アプリケーション開発 for JJUG CCC 2017Dockerで始める Java EE アプリケーション開発 for JJUG CCC 2017
Dockerで始める Java EE アプリケーション開発 for JJUG CCC 2017
 
Java SE 9の紹介: モジュール・システムを中心に
Java SE 9の紹介: モジュール・システムを中心にJava SE 9の紹介: モジュール・システムを中心に
Java SE 9の紹介: モジュール・システムを中心に
 

Similar to ステップ・バイ・ステップで学ぶラムダ式・Stream api入門 #jjug ccc #ccc h2

Springでdao 20070413
Springでdao 20070413Springでdao 20070413
Springでdao 20070413Funato Takashi
 
from old java to java8 - KanJava Edition
from old java to java8 - KanJava Editionfrom old java to java8 - KanJava Edition
from old java to java8 - KanJava Edition心 谷本
 
Java8から始める関数型プログラミング
Java8から始める関数型プログラミングJava8から始める関数型プログラミング
Java8から始める関数型プログラミングstylefreeslide
 
Ruby on Rails 入門
Ruby on Rails 入門Ruby on Rails 入門
Ruby on Rails 入門Yasuko Ohba
 
Head toward Java 16 (Night Seminar Edition)
Head toward Java 16 (Night Seminar Edition)Head toward Java 16 (Night Seminar Edition)
Head toward Java 16 (Night Seminar Edition)Yuji Kubota
 
Apexコアデベロッパーセミナー(Apexコード)071010
Apexコアデベロッパーセミナー(Apexコード)071010Apexコアデベロッパーセミナー(Apexコード)071010
Apexコアデベロッパーセミナー(Apexコード)071010stomita
 
Kai = (Dynamo + memcache API) / Erlang
Kai = (Dynamo + memcache API) / ErlangKai = (Dynamo + memcache API) / Erlang
Kai = (Dynamo + memcache API) / ErlangTakeru INOUE
 
pi-3. 式の抽象化とメソッド
pi-3. 式の抽象化とメソッドpi-3. 式の抽象化とメソッド
pi-3. 式の抽象化とメソッドkunihikokaneko1
 
T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門伸男 伊藤
 
60分で体験する Stream / Lambda
 ハンズオン
60分で体験する Stream / Lambda
 ハンズオン60分で体験する Stream / Lambda
 ハンズオン
60分で体験する Stream / Lambda
 ハンズオンHiroto Yamakawa
 

Similar to ステップ・バイ・ステップで学ぶラムダ式・Stream api入門 #jjug ccc #ccc h2 (20)

Introduction of Python
Introduction of PythonIntroduction of Python
Introduction of Python
 
HDCLT
HDCLTHDCLT
HDCLT
 
Cubby 2006-08-23
Cubby 2006-08-23Cubby 2006-08-23
Cubby 2006-08-23
 
Gorinphp0729
Gorinphp0729Gorinphp0729
Gorinphp0729
 
Gorinphp0729
Gorinphp0729Gorinphp0729
Gorinphp0729
 
Springでdao 20070413
Springでdao 20070413Springでdao 20070413
Springでdao 20070413
 
ATN No.2 Scala事始め
ATN No.2 Scala事始めATN No.2 Scala事始め
ATN No.2 Scala事始め
 
from old java to java8 - KanJava Edition
from old java to java8 - KanJava Editionfrom old java to java8 - KanJava Edition
from old java to java8 - KanJava Edition
 
Project lambda
Project lambdaProject lambda
Project lambda
 
Java8から始める関数型プログラミング
Java8から始める関数型プログラミングJava8から始める関数型プログラミング
Java8から始める関数型プログラミング
 
Ruby on Rails 入門
Ruby on Rails 入門Ruby on Rails 入門
Ruby on Rails 入門
 
Wtm
WtmWtm
Wtm
 
Head toward Java 16 (Night Seminar Edition)
Head toward Java 16 (Night Seminar Edition)Head toward Java 16 (Night Seminar Edition)
Head toward Java 16 (Night Seminar Edition)
 
pi-6. 繰り返し
pi-6. 繰り返しpi-6. 繰り返し
pi-6. 繰り返し
 
Apexコアデベロッパーセミナー(Apexコード)071010
Apexコアデベロッパーセミナー(Apexコード)071010Apexコアデベロッパーセミナー(Apexコード)071010
Apexコアデベロッパーセミナー(Apexコード)071010
 
PHPコアから読み解くPHP5.5
PHPコアから読み解くPHP5.5PHPコアから読み解くPHP5.5
PHPコアから読み解くPHP5.5
 
Kai = (Dynamo + memcache API) / Erlang
Kai = (Dynamo + memcache API) / ErlangKai = (Dynamo + memcache API) / Erlang
Kai = (Dynamo + memcache API) / Erlang
 
pi-3. 式の抽象化とメソッド
pi-3. 式の抽象化とメソッドpi-3. 式の抽象化とメソッド
pi-3. 式の抽象化とメソッド
 
T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門
 
60分で体験する Stream / Lambda
 ハンズオン
60分で体験する Stream / Lambda
 ハンズオン60分で体験する Stream / Lambda
 ハンズオン
60分で体験する Stream / Lambda
 ハンズオン
 

More from Masatoshi Tada

Java ORマッパー選定のポイント #jsug
Java ORマッパー選定のポイント #jsugJava ORマッパー選定のポイント #jsug
Java ORマッパー選定のポイント #jsugMasatoshi Tada
 
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetupこれで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
これで怖くない!?コードリーディングで学ぶSpring Security #中央線MeetupMasatoshi Tada
 
Pivotal認定講師によるSpring Framework 5.1 & Spring Boot 2.1ハンズオン! #jjug_ccc
Pivotal認定講師によるSpring Framework 5.1 & Spring Boot 2.1ハンズオン! #jjug_cccPivotal認定講師によるSpring Framework 5.1 & Spring Boot 2.1ハンズオン! #jjug_ccc
Pivotal認定講師によるSpring Framework 5.1 & Spring Boot 2.1ハンズオン! #jjug_cccMasatoshi Tada
 
基礎からのOAuth 2.0とSpring Security 5.1による実装
基礎からのOAuth 2.0とSpring Security 5.1による実装基礎からのOAuth 2.0とSpring Security 5.1による実装
基礎からのOAuth 2.0とSpring Security 5.1による実装Masatoshi Tada
 
初めてでも30分で分かるSpring 5 & Spring Boot 2オーバービュー
初めてでも30分で分かるSpring 5 & Spring Boot 2オーバービュー初めてでも30分で分かるSpring 5 & Spring Boot 2オーバービュー
初めてでも30分で分かるSpring 5 & Spring Boot 2オーバービューMasatoshi Tada
 
ReactiveだけじゃないSpring 5 & Spring Boot 2新機能解説
ReactiveだけじゃないSpring 5 & Spring Boot 2新機能解説ReactiveだけじゃないSpring 5 & Spring Boot 2新機能解説
ReactiveだけじゃないSpring 5 & Spring Boot 2新機能解説Masatoshi Tada
 
Java EE 8新機能解説 -Bean Validation 2.0編-
Java EE 8新機能解説 -Bean Validation 2.0編-Java EE 8新機能解説 -Bean Validation 2.0編-
Java EE 8新機能解説 -Bean Validation 2.0編-Masatoshi Tada
 
JSUG SpringOne 2017報告会
JSUG SpringOne 2017報告会JSUG SpringOne 2017報告会
JSUG SpringOne 2017報告会Masatoshi Tada
 
とにかく分かりづらいTwelve-Factor Appの解説を試みる
とにかく分かりづらいTwelve-Factor Appの解説を試みるとにかく分かりづらいTwelve-Factor Appの解説を試みる
とにかく分かりづらいTwelve-Factor Appの解説を試みるMasatoshi Tada
 
Java EEでもOAuth 2.0!~そしてPayara Micro on Cloud Foundryで遊ぶ~
Java EEでもOAuth 2.0!~そしてPayara Micro on Cloud Foundryで遊ぶ~Java EEでもOAuth 2.0!~そしてPayara Micro on Cloud Foundryで遊ぶ~
Java EEでもOAuth 2.0!~そしてPayara Micro on Cloud Foundryで遊ぶ~Masatoshi Tada
 
Spring Data JPAによるデータアクセス徹底入門 #jsug
Spring Data JPAによるデータアクセス徹底入門 #jsugSpring Data JPAによるデータアクセス徹底入門 #jsug
Spring Data JPAによるデータアクセス徹底入門 #jsugMasatoshi Tada
 

More from Masatoshi Tada (11)

Java ORマッパー選定のポイント #jsug
Java ORマッパー選定のポイント #jsugJava ORマッパー選定のポイント #jsug
Java ORマッパー選定のポイント #jsug
 
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetupこれで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
 
Pivotal認定講師によるSpring Framework 5.1 & Spring Boot 2.1ハンズオン! #jjug_ccc
Pivotal認定講師によるSpring Framework 5.1 & Spring Boot 2.1ハンズオン! #jjug_cccPivotal認定講師によるSpring Framework 5.1 & Spring Boot 2.1ハンズオン! #jjug_ccc
Pivotal認定講師によるSpring Framework 5.1 & Spring Boot 2.1ハンズオン! #jjug_ccc
 
基礎からのOAuth 2.0とSpring Security 5.1による実装
基礎からのOAuth 2.0とSpring Security 5.1による実装基礎からのOAuth 2.0とSpring Security 5.1による実装
基礎からのOAuth 2.0とSpring Security 5.1による実装
 
初めてでも30分で分かるSpring 5 & Spring Boot 2オーバービュー
初めてでも30分で分かるSpring 5 & Spring Boot 2オーバービュー初めてでも30分で分かるSpring 5 & Spring Boot 2オーバービュー
初めてでも30分で分かるSpring 5 & Spring Boot 2オーバービュー
 
ReactiveだけじゃないSpring 5 & Spring Boot 2新機能解説
ReactiveだけじゃないSpring 5 & Spring Boot 2新機能解説ReactiveだけじゃないSpring 5 & Spring Boot 2新機能解説
ReactiveだけじゃないSpring 5 & Spring Boot 2新機能解説
 
Java EE 8新機能解説 -Bean Validation 2.0編-
Java EE 8新機能解説 -Bean Validation 2.0編-Java EE 8新機能解説 -Bean Validation 2.0編-
Java EE 8新機能解説 -Bean Validation 2.0編-
 
JSUG SpringOne 2017報告会
JSUG SpringOne 2017報告会JSUG SpringOne 2017報告会
JSUG SpringOne 2017報告会
 
とにかく分かりづらいTwelve-Factor Appの解説を試みる
とにかく分かりづらいTwelve-Factor Appの解説を試みるとにかく分かりづらいTwelve-Factor Appの解説を試みる
とにかく分かりづらいTwelve-Factor Appの解説を試みる
 
Java EEでもOAuth 2.0!~そしてPayara Micro on Cloud Foundryで遊ぶ~
Java EEでもOAuth 2.0!~そしてPayara Micro on Cloud Foundryで遊ぶ~Java EEでもOAuth 2.0!~そしてPayara Micro on Cloud Foundryで遊ぶ~
Java EEでもOAuth 2.0!~そしてPayara Micro on Cloud Foundryで遊ぶ~
 
Spring Data JPAによるデータアクセス徹底入門 #jsug
Spring Data JPAによるデータアクセス徹底入門 #jsugSpring Data JPAによるデータアクセス徹底入門 #jsug
Spring Data JPAによるデータアクセス徹底入門 #jsug
 

ステップ・バイ・ステップで学ぶラムダ式・Stream api入門 #jjug ccc #ccc h2