Javaのラムダ式とStreamのfilterを徹底解説!初心者でもわかる条件による絞り込み処理
生徒
「Javaで特定の条件に合うデータだけを取り出すにはどうすればいいですか?」
先生
「JavaのStreamAPIにあるfilterメソッドを使うと、条件に合うデータだけを簡単に抽出できますよ。」
生徒
「それってfor文を使うより簡単なんですか?」
先生
「ラムダ式と組み合わせれば、読みやすくてスマートなコードが書けますよ。実際に見てみましょう!」
1. Javaのfilterとは?Streamで使う基本の絞り込み処理
Javaのfilterメソッドは、リストや配列などに入っている複数のデータの中から「必要なものだけ」を取り出すための機能です。StreamAPIとラムダ式をあわせて使うことで、分かりにくい条件分岐を書かずに、直感的で読みやすい処理が書けます。特に初心者の方にとっては、データを絞り込む仕組みを理解する最初のステップとして最適です。
例えば、「偶数だけを取り出したい」というシンプルな条件であれば、次のように書けます。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
List<Integer> evenNumbers = numbers.stream()
.filter(n -> n % 2 == 0) // 偶数だけを残す条件
.collect(Collectors.toList());
System.out.println(evenNumbers);
[2, 4, 6]
このサンプルでは、「n % 2 == 0」という条件に一致した数字だけがevenNumbersに残ります。従来のfor文で条件分岐を書くよりも短く、どんなデータを抽出しているのかが一目で分かるのがfilterの大きな魅力です。初心者でも扱いやすく、後からコードを読む人にも優しい書き方ができるため、Javaの学習で早めに覚えておくと非常に便利です。
2. ラムダ式で条件を指定!filterの書き方をマスターしよう
filterは、条件を指定する部分にラムダ式を使います。ラムダ式では、各要素が引数として渡され、返り値としてtrueならその要素が残り、falseなら除外されます。
以下は、リスト内の文字列の中から長さが4以上の文字列だけを抽出する例です。
List<String> names = Arrays.asList("Java", "Go", "Python", "C");
List<String> longNames = names.stream()
.filter(name -> name.length() >= 4)
.collect(Collectors.toList());
System.out.println(longNames);
[Java, Python]
このように、filterにラムダ式を渡すことで、柔軟な条件判定が可能になります。
3. filterはfor文より読みやすい?初心者でも実感できる違い
初心者の方はついfor文で条件判定を書きがちですが、filterを使えばコードがすっきりとします。次のように書き換えることができます。
for文の例:
List<String> result = new ArrayList<>();
for (String name : names) {
if (name.length() >= 4) {
result.add(name);
}
}
filterを使った例:
List<String> result = names.stream()
.filter(name -> name.length() >= 4)
.collect(Collectors.toList());
これにより、読みやすさも保守性も向上します。
4. オブジェクトの条件絞り込みにも使えるfilter
filterは、数値や文字列だけでなく、オブジェクトの条件にも使えます。例えば、Userクラスのインスタンスの中から年齢が20歳以上のユーザーを抽出するには、次のようにします。
class User {
String name;
int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public int getAge() { return age; }
public String getName() { return name; }
}
List<User> users = Arrays.asList(
new User("Yamada", 18),
new User("Sato", 25),
new User("Kobayashi", 30)
);
List<User> adults = users.stream()
.filter(user -> user.getAge() >= 20)
.collect(Collectors.toList());
for (User u : adults) {
System.out.println(u.getName());
}
Sato
Kobayashi
このようにfilterは業務アプリケーションにも応用できる便利な機能です。
5. filterと他のStream操作を組み合わせる使い方
filterは単体で使うだけでなく、mapやsorted、collectなどの他のStream操作と組み合わせることで、さらに柔軟なデータ処理が可能になります。
以下は、偶数だけを抽出して2倍に変換する例です。
List<Integer> doubledEvens = numbers.stream()
.filter(n -> n % 2 == 0)
.map(n -> n * 2)
.collect(Collectors.toList());
System.out.println(doubledEvens);
[4, 8, 12]
このように、複数のStreamメソッドを順につなげて使うことで、可読性の高い処理が実現できます。
6. nullや例外に注意!filter使用時の落とし穴
filterを使う際には、null値があると例外が発生する可能性があります。必ずnullチェックを入れるようにしましょう。
例:
List<String> items = Arrays.asList("apple", null, "banana");
List<String> nonNullItems = items.stream()
.filter(Objects::nonNull)
.collect(Collectors.toList());
System.out.println(nonNullItems);
[apple, banana]
Objects::nonNullはnullを除外するための便利なメソッド参照です。
7. 条件の複雑化を防ぐ!メソッド分割で読みやすく
ラムダ式が複雑になる場合は、別メソッドに処理を切り出すと読みやすくなります。次のようにメソッド参照に置き換えることが可能です。
private static boolean isAdult(User user) {
return user.getAge() >= 20;
}
List<User> adults = users.stream()
.filter(MyClass::isAdult)
.collect(Collectors.toList());
この方法により、ラムダ式内のロジックをテストしやすくなる利点もあります。
まとめ
今回の記事では、JavaのStreamとラムダ式を使ったfilter処理を中心に、条件による絞り込みの基本から、オブジェクトの抽出、for文との違い、mapやsortedとの組み合わせ、null対策、そしてメソッド参照を使った読みやすいコード設計まで幅広く学びました。とくにJavaのデータ処理では、filterを用いることにより、複雑になりがちな条件分岐をシンプルに表現でき、可読性や保守性が大きく向上します。さらに、ラムダ式によって短く明快なロジックを記述できるため、初心者でも扱いやすく、現場でも頻繁に利用される重要なテクニックです。実務で多いリストの加工処理や業務データの抽出にも応用しやすく、filterを基礎に覚えることで、JavaのストリームAPI全体の理解も進みます。 また、for文との比較では、冗長なコードがfilterを使うだけで驚くほど簡潔になり、条件式が読みやすくなる点も重要なメリットです。さらに、filterとmapを組み合わせれば、条件に合う値の変換や集計処理なども簡潔に書けます。業務開発でも、データの絞り込みと加工はほぼ必ず登場するため、この考え方は大きな武器になります。 その一方で、null値を含むリストを扱う際には、Objects::nonNullのようなメソッド参照を利用することで、安全にストリーム処理が可能となります。こうした例外回避の工夫は、プログラムの品質を高めるうえでも非常に大切です。また、条件式が複雑になるとラムダ式が長文化してしまうため、別メソッドへ抽出してメソッド参照を使うことで読みやすさと再利用性を高める方法も有効です。Javaのfilterは単なる絞り込み機能ではなく、コードの設計や読みやすさにも大きく貢献する要素であることが理解できます。 さらに、初心者がつまずきやすいポイントとして「ラムダ式の書き方」「ストリームの流れ」「filter後にどう処理するか」などが挙げられますが、実際にサンプルコードを見ることで自然と理解が深まります。抽出したデータをcollectでリストに戻す流れや、複数のストリーム操作をつなげる直感的な表記など、実際の開発現場でもよく使われるテクニックが多数登場しました。Javaプログラミングにおいて、filterは単なる便利機能ではなく、コード全体の構造を改善する強力な道具であると言えるでしょう。 最後に、本記事の内容をもとにしたサンプルコードを以下に掲載します。実際に手を動かしながらfilterやラムダ式に慣れることで、今後より高度なStream処理にも対応しやすくなります。
サンプルプログラム:filterを使った基本の絞り込みと加工
List<Integer> base = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
List<Integer> processed = base.stream()
.filter(n -> n % 2 == 0)
.map(n -> n * 3)
.sorted()
.collect(Collectors.toList());
System.out.println(processed);
このプログラムでは、まず偶数をfilterで抽出し、mapで3倍に変換し、sortedで昇順に並べ替えています。基礎的な例ですが、filterとmap、sortedを組み合わせて使う流れが自然に理解できる構成になっています。こうしたストリームの直列操作は、データ加工の基本となる重要な考え方です。
生徒
「filterって最初は難しそうに感じましたけど、条件に合うものだけを残すって考えるとわかりやすいですね。」
先生
「そうですね。for文で書くよりも短くて読みやすいので、データ処理ではとても便利ですよ。mapやsortedとつなげて使うとさらに力を発揮します。」
生徒
「オブジェクトにも使えるのが意外でした!名前とか年齢での絞り込みも簡単なんですね。」
先生
「その通り。業務では何かしらのクラスを対象に絞り込みすることが多いので、filterはとても役立ちますよ。null対策を忘れずにね。」
生徒
「ラムダ式が長くなったらメソッド参照を使うという考え方も勉強になりました!」
先生
「読みやすいコードを書くことは、プログラミングの大事な心得です。今日学んだfilterの使い方をしっかり活かしていきましょう。」