Loading

ROUTE

ルートゼロの
アクティビティ

Java Streamでnull除外|Objects::nonNullの使い方

1

Java Streamでnull要素を除外するだけなら、`.filter(Objects::nonNull)`で対応できます。これは`x -> x != null`をメソッド参照で書いた分かりやすい形で、どちらか一方だけが特別に安全というわけではありません。注意したいのは「nullがどこにあるか」です。Stream内の要素がnullなのか、そもそもList自体がnullなのか、map後にnullが生まれるのかで対策は変わります。

まず結論:nullがある場所で対策を分ける

nullの場所 主な対策 ポイント
Streamの要素 filter(Objects::nonNull) 後続処理へnullを流さない
元のList自体 stream()前にnull確認 filterへ到達する前にNPEになる
map()の戻り値 map後にfilter(Objects::nonNull) 変換後に生まれたnullを除外する
単一のnullable値 Stream.ofNullable(value) nullなら空Streamにする
findFirst/findAnyの候補 先にnullを除外 選択された要素がnullだとNPEになる

Oracleの`Objects.nonNull`は、`filter(Objects::nonNull)`のようにPredicateとして使うためのAPIです。まず「要素のnull」と「Streamを作る前のnull」を分けると、不要なNPE対策を増やさずに済みます。


Objects::nonNullでnull要素を除外する

Listの中にnull要素が混じっている場合は、処理の早い段階でfilterしておくと、後続のmapやmethod referenceへnullを渡さずに済みます。

import java.util.Arrays;
import java.util.List;
import java.util.Objects;

List<String> raw = Arrays.asList("Alice", null, "Bob");

List<String> names = raw.stream()
    .filter(Objects::nonNull)
    .toList();

System.out.println(names); // [Alice, Bob]

`Objects::nonNull`は受け取った参照がnullでなければtrueを返します。filterはPredicateがtrueになった要素だけを残すため、null要素だけを除外できます。


Objects::nonNullとx -> x != nullはどう違う?

null除外という目的では、`.filter(Objects::nonNull)`と`.filter(x -> x != null)`は同じ判定を表します。メソッド参照の方が「nullを除外する」という意図を短く読めるため便利ですが、挙動が特別に強化されるわけではありません。

raw.stream()
    .filter(Objects::nonNull)
    .toList();

raw.stream()
    .filter(x -> x != null)
    .toList();

複合条件まで確認したい場合は、ラムダ式の方が読みやすいこともあります。書き方ではなく、どの段階でnullを許容し、どこから先では許容しないかを決める方が重要です。


List自体がnullならfilterでは防げない

`items`そのものがnullなら、`items.stream()`を呼んだ時点で例外になり、filterには到達しません。このケースはStream要素のnull対策とは分けて考えます。

import java.util.Collections;
import java.util.List;
import java.util.Objects;

List<String> safeItems = items == null
    ? Collections.emptyList()
    : items;

List<String> result = safeItems.stream()
    .filter(Objects::nonNull)
    .toList();

境界でnullを受け取ること自体が想定外なら、空Listへ変換するより入力時点でfail-fastにする設計もあります。空として扱うか異常として扱うかは、業務上の意味に合わせて決めます。

mapの後にnullが生まれる場合は変換後にも確認する

元の要素が非nullでも、getterや変換処理の結果がnullになることがあります。この場合、最初のfilterだけでは後続処理のnullを防げません。

List<String> emails = users.stream()
    .filter(Objects::nonNull)
    .map(User::getEmail)
    .filter(Objects::nonNull)
    .toList();

ただし、map後のnullに業務上の意味があるなら、何でも除外すると情報が失われます。「メール未登録を捨ててよいのか」を確認し、必要ならOptionalや別の状態表現を検討します。

単一のnullable値ならStream.ofNullableも使える

Java 9以降の`Stream.ofNullable`は、値が非nullなら1要素のStream、nullなら空Streamを返します。単一値をStream処理へつなげたいときに、null判定を外側へ増やさず書けます。

import java.util.stream.Stream;

List<String> normalized = Stream.ofNullable(email)
    .map(String::trim)
    .filter(s -> !s.isEmpty())
    .toList();

複数要素のListからnullを落とす用途は`filter(Objects::nonNull)`、単一のnullable値を0件または1件のStreamへ変換する用途は`Stream.ofNullable`と考えると使い分けやすくなります。

findFirst・findAnyの前にnullを残さない

OracleのStream APIでは、`findFirst()`と`findAny()`は選択された要素がnullの場合に`NullPointerException`を送出すると明記されています。nullが混じる可能性のあるStreamでは、検索前に除外します。

String first = raw.stream()
    .filter(Objects::nonNull)
    .findFirst()
    .orElse("未設定");

「Optionalで返るからnullも安全に包まれる」とは限りません。Optionalを返す終端操作でも、APIごとのnull契約を確認することが大切です。

実務ではnullを消す前に意味を確認する

  • null要素が単なる欠損で、処理対象外にしてよいならfilterで除外する
  • List自体のnullはstream()前に扱う
  • map後にnullが生まれるなら変換後の契約も確認する
  • 単一値をStreamへつなぐならStream.ofNullableを検討する
  • nullがエラー状態を表すなら、黙って除外せず入力検証や例外を使う

(Stream以外も含めたNullPointerExceptionの原因を整理したい場合については『Spring Boot NullPointerException完全対策|3大原因と実装例まとめ』をご参照ください)

nullを除外できることと、nullを除外してよいことは別です。データ欠損を無視してよい処理なのか、異常として検知すべき処理なのかを先に決めると、Streamのコードも読みやすくなります。

よくある質問

Objects::nonNullはラムダ式より安全ですか?

null判定そのものは同等です。`Objects::nonNull`は`filter`用Predicateとして意図が読み取りやすい書き方です。

filter(Objects::nonNull)を書けばNullPointerExceptionはすべて防げますか?

防げません。元のList自体がnullならstream()で例外になりますし、filter後のmap処理が別のnullを返す場合もあります。nullがどの段階にあるかを切り分けます。

Stream.ofNullableはいつ使いますか?

単一の値がnullかもしれず、それを0件または1件のStreamとして後続処理へつなぎたい場合に便利です。Java 9から利用できます。

まず現在のStream処理で、nullが「元のList」「要素」「map後の値」のどこに入り得るかを1つずつ確認してみてください。

カジュアル面談はこちら

すべてを開示している会社です

ポジティブな面もネガティブな面も、包み隠さず誠実にお答えします。
気になることがあれば、面談の際にすべてオープンにお話します。