ラムダ式とは何か
ラムダ式は、匿名関数(名前を持たない関数)を簡潔に表現するための構文です。従来、匿名クラスを使用して記述していたコードを、よりシンプルに書くことができます。これにより、コードの可読性が向上し、開発効率もアップします。
例:匿名クラスとラムダ式の比較
// 匿名クラスを使用
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("Hello, World!");
}
};
// ラムダ式を使用
Runnable runnable = () -> System.out.println("Hello, World!");
ラムダ式の基本構文
ラムダ式の基本的な構文は以下のとおりです。
(引数リスト) -> { 処理内容 }
引数リスト:関数が受け取る引数をカンマで区切って列挙します。
矢印演算子(->):ラムダ式であることを示します。
処理内容:メソッドの本体を中括弧 {} 内に記述します。
シンプルな例
// 引数なし、戻り値なし
() -> System.out.println("Hello, Lambda!");
// 引数あり、戻り値なし
(String message) -> System.out.println(message);
// 引数あり、戻り値あり
(int x, int y) -> x + y;
省略可能な部分
引数の型はコンパイラが推論できる場合、省略可能。
引数が1つの場合、括弧 () を省略可能。
処理内容が単一の式の場合、中括弧 {} と return キーワードを省略可能。
省略例
// 型と括弧を省略
message -> System.out.println(message);
// 中括弧とreturnを省略
(x, y) -> x + y;
関数型インターフェース
ラムダ式は関数型インターフェースを実装するために使用されます。関数型インターフェースとは、抽象メソッドを1つだけ持つインターフェースのことです。
代表的な関数型インターフェース
Consumer<T>
:引数を1つ取り、戻り値なし。(コンシューマー)
Function<T, R>
:引数を1つ取り、戻り値あり。(ファンクション)
Predicate<T>
:引数を1つ取り、boolean を返す。(プレディケート)
Supplier<T>
:引数なし、戻り値あり。 (サプライヤー)
Comparator<T>
:2つの引数を取り、整数を返す。(コンパレーター)
早見表
メソッド | 役割 | 使用する関数型インターフェース |
---|---|---|
forEach | 各要素に対する処理 | Consumer< T > |
map | 各要素の変換 | Function< T , R > |
filter | 条件に合う要素を抽出 | Predicate< T > |
sort | 要素の並べ替え | Comparator< T > |
reduce | 要素の集約 | BinaryOperator< T > |
ifPresent | 値が存在する場合の処理 | Consumer< T > |
submit (スレッド) | タスクの非同期実行 | Runnable or Callable< V > |
collect(toMap) | リストやセットをマップに変換 | Function< T , K >, Function< T, V > |
peek | 各要素に処理を行い、ストリームを返す | Consumer< T > |
allMatch | すべての要素が条件を満たすか判定 | Predicate< T > |
anyMatch | いずれかの要素が条件を満たすか判定 | Predicate< T > |
noneMatch | すべての要素が条件を満たさないか判定 | Predicate< T > |
findFirst | 最初の要素を取得 | Supplier> |
findAny | 任意の要素を取得(並列処理に適用) | Supplier< Optional < T > > |
max | 最大値を取得 | Comparator< T > |
min | 最小値を取得 | Comparator< T > |
groupingBy(Collectors) | グループ化しマップに変換 | Function< T , K > |
partitioningBy(Collectors) | 条件で2つのグループに分ける | Predicate< T > |
flatMap | 要素を展開して一つのストリームにする | Function< T, Stream< R>> |
ラムダ式の活用例
コレクションの操作
forEachメソッド
コレクションの各要素に対して処理を行います。
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.forEach(name -> System.out.println(name));
sortメソッド
リストの要素を特定の基準で並べ替えます。
names.sort((a, b) -> a.length() - b.length());
ストリームAPIとの連携
mapメソッド
各要素に関数を適用して、新しいストリームを生成します。
List<Integer> nameLengths = names.stream()
.map(name -> name.length())
.collect(Collectors.toList());
filterメソッド
条件に合致する要素だけを抽出します。
List<String> shortNames = names.stream()
.filter(name -> name.length() <= 3)
.collect(Collectors.toList());
reduceメソッド
ストリームの要素を集約して1つの結果にまとめます。
int totalLength = names.stream()
.map(name -> name.length())
.reduce(0, (a, b) -> a + b);
並行処理での使用
Runnable
(ラナブル)とCallable
(カラブル)
スレッドやタスクの実行で使用されます。
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(() -> System.out.println("Task is running"));
executor.shutdown();
Optionalクラスとの組み合わせ
ifPresentメソッド
(イフプレゼント)
値が存在する場合に処理を実行します。
Optional<String> optionalName = Optional.of("Alice");
optionalName.ifPresent(name -> System.out.println("Name: " + name));
mapメソッド
Optionalの値を変換します。
Optional<Integer> nameLength = optionalName.map(name -> name.length());
メソッド参照とラムダ式
ラムダ式が既存のメソッドをそのまま呼び出すだけの場合、メソッド参照を使用してより簡潔に記述できます。
シンタックス
ClassName::methodName
object::methodName
// ラムダ式を使用
names.forEach(name -> System.out.println(name));
// メソッド参照を使用
names.forEach(System.out::println);