モダンなJavaの書き方①:ラムダ式
ラムダ式とは
ラムダ式(Lambda Expression)は Java 8 で導入された機能で、メソッドを短く簡潔に表現できる書き方です。処理を「値として渡す」ことができ、無名クラス(匿名クラス)を使っていた冗長なコードを大幅に短縮できます。
ラムダ式は 関数型インターフェース(抽象メソッドが1つだけのインターフェース)に対してのみ使用できます。
基本構文
ラムダ式の基本的な書き方は以下の通りです。
書式
(引数) -> { 処理; }
// 引数が1つの場合は括弧を省略できる
引数 -> { 処理; }
// 処理が1行の場合は {} と return を省略できる
(引数) -> 式
無名クラスとの比較
ラムダ式導入以前は、インターフェースを実装するために無名クラスを使っていました。
Java(無名クラスを使った書き方)
import java.util.ArrayList;
import java.util.Collections;
ArrayList<String> list = new ArrayList<>();
list.add("banana");
list.add("apple");
list.add("cherry");
// 無名クラスで Comparator を実装
Collections.sort(list, new java.util.Comparator<String>() {
@Override
public int compare(String a, String b) {
return a.compareTo(b);
}
});
System.out.println(list);
Java(ラムダ式を使った書き方)
import java.util.ArrayList;
import java.util.Collections;
ArrayList<String> list = new ArrayList<>();
list.add("banana");
list.add("apple");
list.add("cherry");
// ラムダ式で同じ処理を1行に
Collections.sort(list, (a, b) -> a.compareTo(b));
System.out.println(list);
実行結果
[apple, banana, cherry]
関数型インターフェース
Java 8 では java.util.function パッケージに代表的な関数型インターフェースが用意されています。
| インターフェース | 抽象メソッド | 用途 |
|---|---|---|
| Runnable | void run() | 引数なし・戻り値なしの処理 |
| Consumer<T> | void accept(T t) | 引数あり・戻り値なしの処理 |
| Supplier<T> | T get() | 引数なし・値を返す処理 |
| Function<T, R> | R apply(T t) | 引数を変換して返す処理 |
| Predicate<T> | boolean test(T t) | 条件を判定する処理 |
Consumer を使ったサンプル
Consumer は「受け取って処理するだけ、値は返さない」インターフェースです。
Java
import java.util.function.Consumer;
// 文字列を受け取って表示する Consumer
Consumer<String> printer = s -> System.out.println("入力値: " + s);
printer.accept("Hello");
printer.accept("Java");
実行結果
入力値: Hello
入力値: Java
入力値: Java
Predicate を使ったサンプル
Predicate は「条件を判定して true/false を返す」インターフェースです。
Java
import java.util.function.Predicate;
// 偶数かどうかを判定する Predicate
Predicate<Integer> isEven = n -> n % 2 == 0;
System.out.println(isEven.test(4)); // true
System.out.println(isEven.test(7)); // false
// Predicate の合成(and / or / negate)
Predicate<Integer> isPositive = n -> n > 0;
Predicate<Integer> isPositiveEven = isEven.and(isPositive);
System.out.println(isPositiveEven.test(6)); // true
System.out.println(isPositiveEven.test(-4)); // false(負の数)
実行結果
true
false
true
false
false
true
false
Function を使ったサンプル
Function は「値を受け取って変換した値を返す」インターフェースです。
Java
import java.util.function.Function;
// 整数を受け取り、その2乗を返す Function
Function<Integer, Integer> square = n -> n * n;
System.out.println(square.apply(5)); // 25
// Function の合成(andThen)
Function<String, String> trim = s -> s.trim();
Function<String, String> upper = s -> s.toUpperCase();
Function<String, String> clean = trim.andThen(upper);
System.out.println(clean.apply(" hello ")); // HELLO
実行結果
25
HELLO
HELLO
独自の関数型インターフェース
@FunctionalInterface アノテーションを付けると、独自の関数型インターフェースを定義できます。
Java
@FunctionalInterface
interface Calculator {
int calc(int a, int b);
}
// ラムダ式で実装
Calculator add = (a, b) -> a + b;
Calculator mul = (a, b) -> a * b;
System.out.println("足し算: " + add.calc(3, 4)); // 7
System.out.println("掛け算: " + mul.calc(3, 4)); // 12
実行結果
足し算: 7
掛け算: 12
掛け算: 12
メソッド参照
既存のメソッドをラムダ式の代わりに直接参照する メソッド参照 という書き方もあります。
書式
// 静的メソッド参照
クラス名::メソッド名
// インスタンスメソッド参照
インスタンス::メソッド名
// コンストラクタ参照
クラス名::new
Java
import java.util.Arrays;
import java.util.List;
List<String> list = Arrays.asList("banana", "apple", "cherry");
// ラムダ式による表示
list.forEach(s -> System.out.println(s));
// メソッド参照による表示(上と同じ動作)
list.forEach(System.out::println);
実行結果
banana
apple
cherry
apple
cherry
まとめ
・ラムダ式は
・関数型インターフェース(抽象メソッドが1つ)に対してのみ使える
・
・メソッド参照
・次の Stream API と組み合わせると真価を発揮する
・ラムダ式は
(引数) -> 処理 の形で書く・関数型インターフェース(抽象メソッドが1つ)に対してのみ使える
・
Consumer・Predicate・Function など標準の関数型インターフェースを活用する・メソッド参照
クラス::メソッド でさらに簡潔に書ける・次の Stream API と組み合わせると真価を発揮する