はじめに
本記事ではJavaのラムダ式および関数型インタフェースの基本とその背景について説明していきます。
対象者
・ラムダ式および関数型インタフェースを初めて学ぶ初心者
・基礎的な知識を習得済みで、再確認や実践例を通じて理解を深めたい方
ラムダ式とは何か?
ラムダ式の背景
Javaのラムダ式は、Java 8で導入された機能です。
それ以前のJavaではサポートされていなかった「関数型プログラミング」の概念を取り入れることで、コードの簡潔さと柔軟性を向上させ、複雑で多様なケースに応用が可能となりました。
例として、Java 8より前のバージョンでは、匿名クラスを使ってインタフェースを実装する場合、多くのコードを記述する必要がありました。
以下は、Runnable
インタフェースを匿名クラスとして実装し、run
メソッドをオーバーライドした例になります。
Runnable task = new Runnable() {
@Override
public void run() {
System.out.println("Hello, World!");
}
};
以下は、同じ処理をラムダ式で書き直した例です。
ラムダ式の導入によって、コードの量を最小限に抑えることができ、匿名クラスを使った面倒な記述が必要なくなったため、簡潔に記述できるようになりました。
Runnable task = () -> System.out.println("Hello, World!");
ラムダ式の構文とルール
基本構文
ラムダ式の基本構文は以下になります。
(型1 引数名1, 型2 引数名2, ...) -> {
処理;
}
引数の型は暗黙的に推論されるため、省略するのが一般的です。
また、実行結果を呼び出し元に返す場合は、コードブロック内においてreturn
文によって戻り値を指定します。
省略記法
ラムダ式では、状況に応じて記述を簡略化できる場合があります。
以下のラムダ式を題材に、省略記法のルールについて説明していきます。
Function<Integer, Integer> func = (Integer x) -> {
return x * 2;
};
まず、代入時はラムダ式の引数宣言における型を省略可能です。
これはJavaコンパイラがラムダ式の代入先である変数の型(Function<Integer, Integer>
)から推論できるためです。
Function<Integer, Integer> func = (x) -> {
return x * 2;
};
次に、ラムダ式の引数が1つの場合は丸カッコ()
を省略可能です。
※引数を一つも取らない場合は丸カッコ()
を省略できません。
Function<Integer, Integer> func = x -> {
return x * 2;
};
最後に、ラムダ式のブロック内の命令文が一行の場合は波カッコ{}
を省略可能です。
この場合、対象の命令文がreturn
の場合は、return
キーワードも省略が必要です。
Function<Integer, Integer> func = x -> x * 2;
ラムダ式の動作原理
ラムダ式は、あくまで「関数型インタフェースの実装を簡潔に書く記法」です。
裏では匿名クラスのように関数型インタフェースを実装するオブジェクトが生成されています。
関数型インタフェースとは
関数型インタフェースとは、抽象メソッドを一つだけ持つインタフェースのことを指します。
抽象メソッドが一つだけであれば、静的メソッドやデフォルトメソッドが含まれていても、関数型インタフェースとして扱うことができます。
以下は、java.util.function
パッケージのFunction
インタフェースの実装です。(JavaDocコメントは省略)
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
static <T> Function<T, T> identity() {
return t -> t;
}
}
Function
インタフェースの詳細については公式ドキュメントをご確認ください。
Function (Java Platform SE 8)
FunctionalInterfaceアノテーション
@FunctionalInterface
アノテーションは、インタフェースが関数型インタフェースであることを明示するためのアノテーションです。
Javaコンパイラが関数型インタフェースとして正しいかをチェックし、不正な実装(例:抽象メソッドが複数ある)を検出します。
以下のコードでは、正しい関数型インタフェースを作成しています。
@FunctionalInterface
interface MyFunctionalInterface {
void method(); // 抽象メソッド
}
但し、次のように複数の抽象メソッドを定義した場合、@FunctionalInterface
アノテーションのチェックによりコンパイルエラーとなります。
@FunctionalInterface
interface MyFunctionalInterface {
void method1(); // 抽象メソッド
void method2(); // 抽象メソッド(エラー)
}
ラムダ式と関数型インタフェースの関連
上述の通り、ラムダ式は「関数型インタフェースの実装を簡潔に書く記法」です。
ラムダ式と関数型インタフェースの関連について、例を用いて説明します。
【関数型インタフェースの定義】
@FunctionalInterface
interface Greeting {
void sayHello(String name);
}
【ラムダ式を使った実装】
public class Main {
public static void main(String[] args) {
// ラムダ式を使用して、Greetingインタフェースを実装
Greeting greeting = name -> System.out.println("Hello, " + name + "!");
// 実行
greeting.sayHello("World");
}
}
【出力結果】
Hello, World!
この例では、Greeting
インタフェースの sayHello
メソッドをラムダ式で実装しています。
ラムダ式は実行時にGreeting
インタフェースを実装するオブジェクトとして振る舞い、sayHello(String name)
メソッドに対応します。
ラムダ式は特定の関数型インタフェースの抽象メソッドと結び付けられることで、シンプルかつ効率的なコード記述を可能にしています。