Javaのラムダ式とStream API
Java8から導入された「ラムダ式」と「Stream API」の基本パターンです。1時間ぐらいでモダンな機能の基本をマスターできると思います。
目次
1. ラムダ式(LAMBDA)
2. Stream API(ラムダ式の活用)
2-1. List版
2-2. Set版
2-3. Map版
2-4. 配列をStreamに変換する
2-5. 並列処理
3. Stream APIの例
3-1. filter(フィルタリング/絞込み)
3-2. map(マッピング/値の編集)
3-3. allMatch,anyMatch,noneMatch(マッチング/真偽)
3-4. sorted(ソート/整列)
3-5. count(カウント/リスト数)
3-6. average(アベレージ/平均)
3-7. max(マックス/最大値)
3-8. min(ミニ/最小値)
3-9. limit(リミット/要素数の制限)
3-10. distinct(ディスティンクト/重複削除)
3-11. flatMap(フラットマップ/新リストの作成)
3-12. reduce(リダクション/要素を集計する)
3-13. collect(コレクト/オブジェクトを返す)
3-14. groupingBy(グルーピング/要素の分類)
3-15. まとめ
1. ラムダ式(LAMBDA)
ラムダ式では関数オブジェクトを即時利用(定義及び生成)できます。
// メソッドの型を作成する(インターフェース)
interface MyFunction {
int run(int x);
}
public class Main {
public static void main(String[] args) {;
// ラムダ式でメソッドの参照(ポインタ)を取得する
MyFunction my = (int x) -> {return x * 10;};
// メソッドを実行する
System.out.println(my.run(1));
// ラムダ式でメソッドを即時実行する
int val = ((MyFunction)((int x) -> {return x * 10;})).run(1);
System.out.println(val);
}
}
結果
10
コードの省略
ラムダ式はコードを次のように省略可能なのでスッキリします。
| 引数の型を省略できる。(型推論) |
| 引数が1つの場合は()を省略できる。 |
| {}が単文の場合は{}とreturnを省略できる。 |
// メソッドの型を作成する(インターフェース)
interface MyFunction {
int run(int x);
}
public class Main {
public static void main(String[] args) {;
// 元のラムダ式
MyFunction my1 = (int x) -> {return x * 10;};
System.out.println(my1.run(1));
// 型の省略
MyFunction my2 = (x) -> {return x * 10;};
System.out.println(my2.run(1));
// ()の省略
MyFunction my3 = x -> {return x * 10;};
System.out.println(my3.run(1));
// {}とreturnの省略
MyFunction my4 = x -> x * 10;
System.out.println(my4.run(1));
}
}
結果
10
10
10
2. Stream API(ラムダ式の活用)
コレクションにStream APIとラムダ式を使用する事が可能です。
2-1. List版
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {;
// リストの生成
List<Integer> list = Arrays.asList(1,2,3);
// 拡張for文
for(Integer x : list) {
System.out.println(x);
}
System.out.println("---");
// Stream APIとラムダ式を活用する
list.stream().forEach(x -> System.out.println(x));
System.out.println("---");
// 引数の型/個数が一致している場合は更に省略可能
list.stream().forEach(System.out::println);
}
}
結果
2
3
---
1
2
3
---
1
2
3
2-2. Set版
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class Main {
public static void main(String[] args) {;
// リストの生成
Set<String> list = new HashSet<>(Arrays.asList("あ","い"));
// 拡張for文
for(String x : list) {
System.out.println(x);
}
System.out.println("---");
// Stream APIとラムダ式を活用する
list.stream().forEach(x -> System.out.println(x));
System.out.println("---");
// 引数の型/個数が一致している場合は省略可能
list.stream().forEach(System.out::println);
}
}
結果
い
---
あ
い
---
あ
い
2-3. Map版
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {;
Map<String,String> map = new HashMap<>();
map.put("R" ,"赤色");
map.put("G" ,"緑色");
map.put("B" ,"青色");
// 拡張for文
for(String key : map.keySet()) {
System.out.println(key + ":" + map.get(key));
}
System.out.println("---");
// Stream APIとラムダ式を活用する
map.entrySet().stream()
.map(v -> v.getKey() + ":" + v.getValue())
.forEach(x -> System.out.println(x));
System.out.println("---");
// 引数の型/個数が一致している場合は省略可能
map.entrySet().stream()
.map(v -> v.getKey() + ":" + v.getValue())
.forEach(System.out::println);
}
}
結果 ※Mapは環境により順序が異なる
B:青色
G:緑色
---
R:赤色
B:青色
G:青色
---
R:赤色
B:青色
G:緑色
2-4. 配列をStreamに変換する
import java.util.Arrays;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {;
Integer[] list = {1,2,3};
Stream<Integer> st = Arrays.stream(list);
st.forEach(System.out::println);
}
}
結果
2
3
2-5. 並列処理
stream()の代わりにparallelStream()を使用すると並列処理を行います。環境によっては処理速度が速くなる場合があります。
3. Stream APIの例
次節からStreamの基本的なパターンをご紹介します。
| 公式APIの解説 | Stream |
|---|---|
| Comparator | |
| Collectors |
不明点は公式のAPI解説書をご覧下さい。
3-1. filter(フィルタリング/絞込み)
SQLで言うとWHEREと同様です。
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {;
List<Integer> list = Arrays.asList(1,2,3);
// filter
list.stream()
.filter(i -> i <= 2)
.forEach(System.out::println);
}
}
結果
2
3-2. map(マッピング/値の編集)
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {;
List<String> list = Arrays.asList("A","B","C");
// map
list.stream()
.map(s -> s.toLowerCase())
.forEach(System.out::println);
}
}
結果
b
c
3-3. allMatch,anyMatch,noneMatch(マッチング/真偽)
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {;
// リストの生成
List<String> list = Arrays.asList("A","B","A");
// allMatch(全て一致する)
boolean flg1 = list.stream()
.allMatch("A"::equals);
System.out.println(flg1);
// anyMatch(いずれかが一致する)
boolean flg2 = list.stream()
.anyMatch("A"::equals);
System.out.println(flg2);
// noneMatch(全て一致しない)
boolean flg3 = list.stream()
.noneMatch(a -> (a == "C"));
System.out.println(flg3);
}
}
結果
true
true
3-4. sorted(ソート/整列)
SQLのORDER BYと同様。
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
public class Main {
public static void main(String[] args) {;
List<Integer> list = Arrays.asList(3,1,2);
// sorted(昇順)
list.stream()
.sorted(Comparator.naturalOrder())
.forEach(System.out::println);
System.out.println("---");
// sorted(降順)
list.stream()
.sorted(Comparator.reverseOrder())
.forEach(System.out::println);
}
}
結果
2
3
---
3
2
1
3-5. count(カウント/リスト数)
SQLのCOUNTと同様。
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {;
List<Integer> list = Arrays.asList(1,2,3);
// count
long val = list.stream().count();
System.out.println(val);
}
}
結果
3-6. average(アベレージ/平均)
SQLのAVGと同様。
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {;
List<Integer> list = Arrays.asList(1,2,3);
// average
double val = list.stream()
.mapToInt(x->x)
.average()
.getAsDouble();
System.out.println(val);
}
}
結果
3-7. max(マックス/最大値)
SQLのMAXと同様。
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
public class Main {
public static void main(String[] args) {;
List<Integer> list = Arrays.asList(1,2,3);
// max
Integer val = list.stream()
.max(Comparator.naturalOrder())
.get();
System.out.println(val);
}
}
結果
3-8. min(ミニ/最小値)
SQLのMINと同様。
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
public class Main {
public static void main(String[] args) {;
List<Integer> list = Arrays.asList(1,2,3);
// min
Integer val = list.stream()
.min(Comparator.naturalOrder())
.get();
System.out.println(val);
}
}
結果
3-9. limit(リミット/要素数の制限)
SQLのLIMITと同様。
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {;
List<Integer> list = Arrays.asList(1,2,3,4,5);
// limit
list.stream()
.limit(3)
.forEach(System.out::println);
}
}
結果
2
3
3-10. distinct(ディスティンクト/重複削除)
SQLのDISTINCTと同様。
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {;
List<Integer> list = Arrays.asList(1,3,3,3,5);
// distinct
list.stream()
.distinct()
.forEach(System.out::println);
}
}
結果
3
5
3-11. flatMap(フラットマップ/新リストの作成)
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {;
List<String> list = Arrays.asList("1,2,3","4,5,6");
// flatMap
list.stream()
.flatMap(s -> Arrays.stream(s.split(",")))
.forEach(System.out::println);
}
}
結果
2
3
4
5
6
3-12. reduce(リダクション/要素を集計する)
要素を集計して集計結果を返します。SQLのSUMに近いです。
<例1>
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {;
List<Integer> list = Arrays.asList(1,2,3,4,5);
// reduce
Integer sum = list.stream()
.reduce(Integer::sum)
.get();
System.out.println(sum);
}
}
結果
<例2>
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {;
List<Integer> list = Arrays.asList(1,2,3,4,5);
// reduce
Integer sum = list.stream()
.reduce((a,b) -> a + b)
.get();
System.out.println(sum);
}
}
結果
<例3>
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {;
List<Integer> list = Arrays.asList(1,2,3,4,5);
// reduce
Integer sum = list.stream()
.reduce(10,(a,b) -> a + b);
System.out.println(sum);
}
}
結果
※stream()とparallelStream()では計算結果が異なるので注意して下さい。
3-13. collect(コレクト/オブジェクトを返す)
オブジェクトは次のストリームがある場合は「次のストリームへ」。ない場合は「戻り値」になります。※次節の3-14もご覧下さい。
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {;
List<Integer> list = Arrays.asList(1,2,3);
// collect
List<Integer> result = list.stream().collect(Collectors.toList());
result.forEach(System.out::println);
}
}
結果
2
3
3-14. groupingBy(グルーピング/要素の分類)
SQLのGROUP BYと同様。
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {;
List<String> list = Arrays.asList
("とら","たらんちゅあ","ねこ","しまうま","きりん");
// groupingBy
list.stream()
.collect(Collectors.groupingBy(s -> s.length()))
.forEach((a,b) -> System.out.println(a + ":" + b));
}
}
結果
3:[きりん]
4:[しまうま]
6:[たらんちゅあ]
3-15. まとめ
Stream APIはデータをSQLのように操作できる仕組みです。
また、mapやfilterなどはメソッドチェーン(メソッドを連続して呼び出す)で複数、組み合わせて使用する事が可能です。
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {;
List<String> list = Arrays.asList("とら","しまうま","きりん");
list.stream()
.map(a->a + "A")
.filter(a-> a.length() != 0)
.filter(a-> a.length() < 5)
.collect(Collectors.groupingBy(s -> s.length()))
.forEach((a,b) -> System.out.println(a + ":" + b));
}
}
結果
4:[きりんA]
初めての方には「やや難しい」ですが便利なので色々と試すと良いです。
関連記事
プチモンテ ※この記事を書いた人
![]() | |
![]() | 💻 ITスキル・経験 サーバー構築からWebアプリケーション開発。IoTをはじめとする電子工作、ロボット、人工知能やスマホ/OSアプリまで分野問わず経験。 画像処理/音声処理/アニメーション、3Dゲーム、会計ソフト、PDF作成/編集、逆アセンブラ、EXE/DLLファイルの書き換えなどのアプリを公開。詳しくは自己紹介へ |
| 🎵 音楽制作 BGMは楽器(音源)さえあれば、何でも制作可能。歌モノは主にロック、バラード、ポップスを制作。歌詞は抒情詩、抒情的な楽曲が多い。楽曲制作は🔰2023年12月中旬 ~ | |









