0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ラムダ式とStream API、Javaで整理してみた

0
Last updated at Posted at 2026-09-16

今回は、Java 8で導入された「ラムダ式」と「Stream API」の基本を紹介します。list.stream().filter(...).map(...)のような書き方の意味を整理してみました。

対象読者

  • List・Set・Mapの基本とジェネリクスを理解している方
  • for文でコレクションを操作するコードを、filterやmapのようなメソッドチェーンに書き換えたい方
  • ラムダ式の->という書き方や、「関数型インターフェース」という言葉に馴染みがない方

並列Stream(parallelStream)のパフォーマンスチューニングや、独自の関数型インターフェースを設計する際の詳細なルールまでは扱いません。あくまで基本の書き方と、それぞれが何のためにあるのかという整理に絞っています。

検証環境

Java 25(LTS、2025年9月リリース)を前提にしています。2026年3月にリリースされたJava 26は非LTSでサポート期間が6か月に限定されている1ため、学習用途で環境を作るなら、現行LTSであるJava 25を使うのが無難です。

ラムダ式とは何か

ラムダ式は、1つのメソッドだけを持つインターフェース(関数型インターフェース)の実装を、簡潔に書くための構文です2。「名前のないメソッド」のようなものだと考えると分かりやすいです。

「年齢が3歳以上の動物だけを表示する」という条件を、まず独自のインターフェースと匿名クラスで書いてみます。

interface AnimalCondition {
    boolean test(Animal animal);
}

static void printAnimals(List<Animal> animals, AnimalCondition condition) {
    for (Animal animal : animals) {
        if (condition.test(animal)) {
            System.out.println(animal.name);
        }
    }
}
printAnimals(animals, new AnimalCondition() {
    @Override
    public boolean test(Animal animal) {
        return animal.age >= 3;
    }
});

AnimalConditionというインターフェース1つのメソッドを実装するためだけに、匿名クラスとして4行以上のコードを書く必要があります。これをラムダ式で書き換えると、次のようになります。

printAnimals(animals, animal -> animal.age >= 3);

ラムダ式の基本構文は「(仮パラメータ) -> 本体」です2。パラメータが1つの場合は括弧を省略でき、本体が単一の式であればreturnも{}も不要です。Oracleの公式チュートリアルでは、ラムダ式が導入された理由として、単一メソッドのインターフェースに対する匿名クラスの記述が冗長すぎたことと、処理そのものをメソッドの引数として渡せるようにする(関数型プログラミング的な書き方をできるようにする)ことが挙げられています2。

関数型インターフェースとjava.util.function

ラムダ式の代入先になれるインターフェースは、抽象メソッドを1つだけ持つ関数型インターフェースに限られます2。先ほどのAnimalConditionもその一例ですが、実際の開発では毎回自分でインターフェースを定義するのではなく、java.util.functionパッケージにある標準の関数型インターフェースを使うのが一般的です2。

インターフェース メソッド 用途
Predicate<T> boolean test(T t) 条件を判定する
Function<T, R> R apply(T t) 値を受け取り、別の値に変換する
Consumer<T> void accept(T t) 値を受け取り、何らかの処理を行う(戻り値なし)
Supplier<T> T get() 値を何も受け取らずに供給する

先ほどのAnimalConditionは、実質的にPredicate<Animal>と同じ形をしています。独自のインターフェースを定義する代わりに、標準のPredicate<Animal>を使うこともできます。

メソッド参照:ラムダ式をさらに短く書く

ラムダ式の本体が、既存のメソッドをそのまま呼び出すだけの場合、メソッド参照という::を使った書き方でさらに簡潔に書けます3。

// ラムダ式
animals.sort((a, b) -> Animal.compareByAge(a, b));

// メソッド参照
animals.sort(Animal::compareByAge);

メソッド参照には次の4種類があります3。

種類 構文 例
静的メソッド参照 クラス::静的メソッド名 Animal::compareByAge
特定オブジェクトのインスタンスメソッド参照 オブジェクト::メソッド名 myAnimal::bark
任意のオブジェクトのインスタンスメソッド参照 型::メソッド名 String::toUpperCase
コンストラクタ参照 クラス::new ArrayList::new

Stream API:コレクションを集計・加工する

Stream APIは、Java 8で導入された、コレクションに対する集計操作(filter・map・集計など)のための機能です4。for文でコレクションを1件ずつ処理する代わりに、処理の流れをメソッドチェーンとして表現できます。

「年齢が3歳以上の動物の名前だけを一覧にする」という処理を、for文とStream APIそれぞれで書いてみます。

// for文
List<String> names = new ArrayList<>();
for (Animal animal : animals) {
    if (animal.age >= 3) {
        names.add(animal.name);
    }
}
// Stream API
List<String> names = animals.stream()
    .filter(animal -> animal.age >= 3)
    .map(animal -> animal.name)
    .collect(Collectors.toList());

Oracleの公式チュートリアルでは、Stream APIとfor文の違いとして、繰り返し方法が「外部反復(コードが明示的にループを制御する)」から「内部反復(JDK側が最適な繰り返し方法を決める)」に変わる点が説明されています4。この内部反復の仕組みにより、後からstream()をparallelStream()に置き換えるだけで並列処理に切り替えられる、という利点もあります。

Stream APIの処理は、大きく3つの要素からなる「パイプライン」として組み立てます。

  1. ソース(source):animals.stream()のように、コレクションなどからStreamを作る
  2. 中間操作(intermediate operations):filter・mapのように、Streamを別のStreamに変換する。何度でも連ねられる
  3. 終端操作(terminal operation):collect・forEach・countのように、最終的な結果を生成する。これが呼ばれるまで、実際の処理は実行されない

先ほどの例で言えば、filterとmapが中間操作、collect(Collectors.toList())が終端操作です。終端操作を呼ぶまでは、実際にはまだ何も処理されていない、という点は最初は意識しづらいポイントかもしれません。

ラムダ式とStream APIの関係

filter・map・forEachといったStream APIのメソッドは、いずれも先ほど紹介したPredicateやFunction、Consumerのような関数型インターフェースを引数として受け取ります。つまりStream APIは、「ラムダ式で処理内容を渡す」という仕組みを、コレクション操作に応用したものだと言えます。ラムダ式そのものの書き方を理解しておくと、Stream APIのメソッドチェーンも自然に読み書きできるようになります。

まとめ

  • ラムダ式は、1つのメソッドを持つ関数型インターフェースの実装を、(仮パラメータ) -> 本体という形で簡潔に書く構文
  • 関数型インターフェースにはjava.util.functionの標準的なもの(Predicate・Function・Consumer・Supplierなど)があり、独自に定義しなくても多くの場面で使える
  • メソッド参照(::)を使うと、既存のメソッドをそのまま渡すラムダ式をさらに簡潔に書ける
  • Stream APIは、コレクションに対する集計操作をパイプライン(ソース→中間操作→終端操作)として表現する仕組み
  • filter・mapなどのStream APIのメソッドは関数型インターフェースを引数に取るため、ラムダ式と組み合わせて使うのが基本

for文とif文で書いていた処理が、filter・map・collectのメソッドチェーンに置き換えられるようになると、コレクションを扱うコードの見通しがかなり良くなります。ラムダ式の構文そのものに慣れることが、Stream APIを読み書きするための一番の近道だと感じました。

脚注

参考資料

  1. Java 26は2026年3月18日にリリースされた非LTS版で、サポート期間は6か月間(2026年9月まで)。現行LTSはJava 25(2025年9月リリース)。詳細はJava 26 正式リリース — ラーゲイト株式会社を参照。 ↩

  2. Lambda Expressions | The Java™ Tutorials (Oracle) ↩ ↩2 ↩3 ↩4 ↩5

  3. Method References | The Java™ Tutorials (Oracle) ↩ ↩2

  4. Aggregate Operations | The Java™ Tutorials (Oracle) ↩ ↩2

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?