PR

Java:ラムダ式(lambda)を3分でわかりやすく

Java

このページでは直感的には中々理解しづらいJavaのラムダ式について解説します。

ラムダ式を理解するうえでは、その前段階として「ローカルクラス」や「匿名クラス」がどういうものかをおさらいすると整理しやすいです。それらを学ぶ流れの中で頭の中を整理すると、なぜラムダ式が生まれたのかも自然にわかります。このページでは、まずローカルクラスと匿名クラスをざっくり紹介し、最後にラムダ式へとつながるイメージを整理していきます。

スポンサーリンク

【前提その1】ローカルクラス (Local Class)

ローカルクラスは、その名の通り「メソッドの中」で定義されるクラスです。通常のクラスはフィールドやメソッドの外側に定義しますが、ローカルクラスはメソッド内のローカル変数のように「メソッドブロックの中」で定義されます。

サンプルコード メソッド内でクラスを定義

public void doSomething() {
    // メソッド内でクラスを定義
    class LocalPrinter {
        public void print(String message) {
            System.out.println("LocalPrinter: " + message);
        }
    }

    // ここでLocalPrinterを使う
    LocalPrinter printer = new LocalPrinter();
    printer.print("Hello, Local Class!");
}
  • この LocalPrinter クラスは doSomething() メソッドの中でしか使えません。
  • メソッド内の名前空間だけで有効な“ローカル”なクラスになります。
  • ちょっとしたクラスを作って使いたい場合に、わざわざ大きなクラスファイルを用意しなくても済むメリットがあります。
  • ただ、クラス定義をメソッドに書くため見通しが悪くなる可能性もあるので、あまり大規模には使われない傾向があります。

【前提その2】匿名クラス (Anonymous Class)

匿名クラスは、名前をつけないままクラスを定義して、その場でインスタンスを生成 できる仕組みです。
インターフェースや抽象クラスを “その場で” 実装したいときに使われます。

new 抽象クラスまたはインターフェース() {
    // クラスの実装 (メソッドのオーバーライド、フィールドの定義など)
};

サンプルコード 匿名クラスを使ってインターフェースを実装

public void setListener() {
    button.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("ボタンがクリックされました");
        }
    });
}
  • new ActionListener() { ... }{ ... } 部分が「匿名クラスの本体」。
  • ActionListener はインターフェースなので、そこに定義された抽象メソッド(actionPerformed)を実装する必要があります。
  • GUIイベントや、コールバックなど「この場面でだけ使う一度きりの処理」を書くときに便利。
  • インスタンスを生成しながら同時にクラスを定義できるので、コードのまとまりとしては便利なのですが、どうしても冗長な表記になりがちです。

匿名クラス (Anonymous Class)は感覚的にピンとこない方も多いのでここで補足します。

まずは通常の「クラス定義 + インスタンス生成」をおさらいしましょう。ふつうクラスを使うときは、ざっくりこんな流れです。

1.クラス定義

class MyWorker implements Runnable {
    @Override
    public void run() {
        System.out.println("Hello from MyWorker!");
    }
}

2.インスタンス生成 + 呼び出し

MyWorker worker = new MyWorker();
worker.run();  // => "Hello from MyWorker!"

これが通常の使い方ですよね。しかし、毎回クラス名 MyWorker をつけてわざわざファイルを作るほどでもない「ちょっとした実装を、その場でパッと書きたい」ことがあります。

ポイント 「匿名クラス」はクラス定義とインスタンス化を同時にやる

匿名クラスは、以下のように クラス名を持たないまま 、クラス定義とインスタンス生成をセットにして書くやり方です。

Runnable worker = new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello from Anonymous Class!");
    }
};
  • new Runnable() { ... }{ ... } の部分が「今ここで定義したクラスの中身」です。
  • implements Runnable のようにインターフェースを実装している形ですが、ここでは「匿名(名前なし)クラス」を使って 1回限り 実装を作っているわけです。

呼び出しは通常と同じで、worker.run(); とすればOK。「Runnable を実装した“何かのクラス”」をその場で作り、そのインスタンスを worker に代入しているイメージです。

「匿名クラス」の課題とラムダ式の登場

匿名クラスは「一度きりの処理」を書く際に非常に便利でした。しかし、次第に下記のような「冗長さ」が目立つようになりました。

  1. 記述が長い
    • インターフェース名を書き、new して { ... } でメソッドをオーバーライドする、という部分がどうしてもかさばる。
  2. メソッド名を書く必要がある
    • actionPerformed とか、run とか、インターフェースで決められたメソッド名を明示的に書く必要がある。
  3. 「処理」だけ書きたいのに、構文が多い
    • “やりたい処理” は「ボタンがクリックされたら、コンソールに文字を出す」という一行の処理だけなのに、記述が散らばる。

このようなニーズをよりシンプルに実現するために生まれたのが ラムダ式 です。「匿名クラス+1メソッド」という状況を、もっと短い構文で書けるようにしたもの、と考えるとイメージがつかみやすいでしょう。

ラムダ式へつながるイメージ

匿名クラスからラムダ式へ

サンプルコード 匿名クラス (Java 8以前の書き方)

button.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("ボタンがクリックされました");
    }
});

サンプルコード ラムダ式 (Java 8以降の書き方)

button.addActionListener(e -> {
    System.out.println("ボタンがクリックされました");
});
  • クラスを定義して、メソッド名をオーバーライドする」という部分が消え、(引数) -> { 処理 } という形に集約されました。
  • 背景では「ActionListeneractionPerformed メソッドを実装しているオブジェクト」が生成されているのですが、開発者は「何の引数が来て、何をするのか」だけを書けばよい構文になっています。

ラムダ式のための「関数型インターフェース」

ラムダ式を使えるのは、抽象メソッドを1つだけ持つインターフェース (関数型インターフェース) がある場合に限られます。
ActionListeneractionPerformed メソッドだけのインターフェースなので、ラムダ式で表せるわけです。

Javaのラムダ式:まとめ

  1. ローカルクラス
    • メソッドの中でクラス定義をする機能。
    • 小さな補助的クラスをメソッド内だけで完結して書くときに便利。
  2. 匿名クラス
    • 名前をつけずにクラスをその場で定義→即インスタンス化する機能。
    • 一度きりの実装を簡潔に書く場面で使うが、実際には“クラスの定義+メソッドのオーバーライド”が冗長になりがち。
  3. ラムダ式
    • 「匿名クラスで1メソッドしか実装しないケース」をもっと短く書くために導入。
    • 関数型インターフェース (抽象メソッド1つのみ) に対応。
    • コードの簡潔化・読みやすさ向上に大いに貢献。

ローカルクラスや匿名クラスは、「その場限りのクラスやメソッド実装を手軽に書きたい」という欲求から生まれましたが、さらに一歩進んで「メソッド(=処理のかたまり)だけをピンポイントに書きたい」という場合に、ラムダ式が非常に強力に機能します。特にJava 8以降はラムダ式とStream APIを併用して「コレクションを扱う処理」を一気に書きやすくすることができるようになり、現代Javaのスタンダードな書き方として定着しています。

タイトルとURLをコピーしました