3
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ラムダ式の基本とその背景

Last updated at Posted at 2025-04-21

はじめに

本記事では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コメントは省略)

java.util.function.Function
@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)メソッドに対応します。
ラムダ式は特定の関数型インタフェースの抽象メソッドと結び付けられることで、シンプルかつ効率的なコード記述を可能にしています。

3
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?