「null除外」は“混ざってしまった null を一度で掃除する”ユーティリティ
業務コードを書いていると、こういうコレクションがよく生まれます。
List<String> names = Arrays.asList("山田", null, "佐藤", null, "鈴木");
JavaDBからの結果、外部APIのレスポンス、画面入力のマージなどで、
「null が混ざった List / Set / Map」ができてしまうのは、ほぼ日常です。
問題は、その後の処理で毎回こう書くことになることです。
for (String name : names) {
if (name != null) {
// ここで処理
}
}
Javanull除外ユーティリティは、この「毎回の if (x != null)」をやめて、
「最初に一度だけ null を全部取り除いてしまう」ための小さな道具です。
基本形:List から null を全部取り除く
removeNulls で「null なしの新しい List」を返す
まずは一番よく使う List 版から考えます。
「元の List はそのまま」「null を除いた新しい List を返す」形にするのが安全です。
import java.util.ArrayList;
import java.util.List;
public final class CollectionUtils {
private CollectionUtils() {}
public static <T> List<T> removeNulls(List<T> source) {
if (source == null || source.isEmpty()) {
return List.of(); // 空の不変List
}
List<T> result = new ArrayList<>(source.size());
for (T e : source) {
if (e != null) {
result.add(e);
}
}
return result;
}
}
Java使い方はこうなります。
List<String> raw = List.of("山田", null, "佐藤", null, "鈴木");
List<String> cleaned = CollectionUtils.removeNulls(raw);
System.out.println(cleaned); // [山田, 佐藤, 鈴木]
for (String name : cleaned) {
// ここでは null チェック不要
System.out.println(name + " さん");
}
Javaここで深掘りしたい重要ポイントは三つです。
一つ目は、「元の List を変更していない」ことです。removeIf(Objects::isNull) のように“その場で削る”方法もありますが、
呼び出し元が同じ List を他でも使っていると、思わぬ副作用になります。
ユーティリティでは「新しい List を返す」方が安全です。
二つ目は、「null や空 List が来たら、空の不変 List を返す」ことです。
これにより、呼び出し側は null を気にせずに for-each できます。
三つ目は、「戻り値は“null がない”と約束されている」ことです。removeNulls を通した List に対しては、if (x != null) を書かなくてよい世界になります。
Set から null を除外する
重複排除+null除外を一度にやる
Set はそもそも「重複を持たない」コレクションですが、
null は普通に入ってきます。
Set<String> raw = new HashSet<>();
raw.add("A");
raw.add(null);
raw.add("B");
Javaこれも同じ発想で、「null を除いた新しい Set」を返すユーティリティを用意します。
import java.util.HashSet;
import java.util.Set;
public static <T> Set<T> removeNulls(Set<T> source) {
if (source == null || source.isEmpty()) {
return Set.of(); // 空の不変Set
}
Set<T> result = new HashSet<>(source.size());
for (T e : source) {
if (e != null) {
result.add(e);
}
}
return result;
}
Java使い方はこうです。
Set<String> raw = new HashSet<>();
raw.add("A");
raw.add(null);
raw.add("B");
Set<String> cleaned = CollectionUtils.removeNulls(raw);
System.out.println(cleaned); // [A, B] など(null は消えている)
Javaここでのポイントは、「null除外と重複排除が自然に組み合わさる」ことです。
「とにかく“有効な値だけの集合”が欲しい」というときに、removeNulls を一発かませば済むようになります。
Map の「キーの null」「値の null」をどう扱うか決める
まずは「値が null のエントリだけ除外する」版
Map の場合、null が入りうる場所は二つあります。
キーが null、値が null。
多くの業務コードでは、「キーは null にしない」「値は null のこともある」
という設計が多いので、まずは「値が null のエントリを除外する」版を作ります。
import java.util.HashMap;
import java.util.Map;
public static <K, V> Map<K, V> removeNullValues(Map<K, V> source) {
if (source == null || source.isEmpty()) {
return Map.of(); // 空の不変Map
}
Map<K, V> result = new HashMap<>(source.size());
for (Map.Entry<K, V> e : source.entrySet()) {
if (e.getValue() != null) {
result.put(e.getKey(), e.getValue());
}
}
return result;
}
Java使い方はこうです。
Map<String, String> raw = new HashMap<>();
raw.put("A", "あ");
raw.put("B", null);
raw.put("C", "う");
Map<String, String> cleaned = CollectionUtils.removeNullValues(raw);
System.out.println(cleaned); // {A=あ, C=う}
Javaここでの重要ポイントは、「null を“キーが存在しない”のと同じ扱いにする」かどうかを、
ユーティリティ側で決めていることです。removeNullValues を通した Map に対しては、
「値が null という状態は存在しない」とみなせます。
キーの null も排除したい場合
もし「キーも絶対に null にしたくない」設計なら、
キーもチェックする版を用意します。
public static <K, V> Map<K, V> removeNullKeysAndValues(Map<K, V> source) {
if (source == null || source.isEmpty()) {
return Map.of();
}
Map<K, V> result = new HashMap<>(source.size());
for (Map.Entry<K, V> e : source.entrySet()) {
if (e.getKey() != null && e.getValue() != null) {
result.put(e.getKey(), e.getValue());
}
}
return result;
}
Javaこのように、「どこまでを null除外の対象にするか」を
メソッド名と中身で明示しておくと、後から読んだ人にも意図が伝わります。
Stream を使った書き方との違いと使い分け
Stream 版は短いが、「共通ルール」としてはユーティリティに寄せる
Java 8 以降なら、Stream を使って一行で書くこともできます。
List<String> cleaned =
raw.stream()
.filter(Objects::nonNull)
.toList();
Javaこれ自体はとてもきれいですが、
あちこちで同じ filter(Objects::nonNull) が出てくると、
「このプロジェクトでは null をどう扱うのか」というルールが散らばってしまいます。
そこで、「null除外は必ず CollectionUtils.removeNulls を通す」と決めておくと、
ルールの場所が一箇所にまとまります。
Stream を使いたければ、ユーティリティの中で使えばよいだけです。
public static <T> List<T> removeNulls(List<T> source) {
if (source == null || source.isEmpty()) {
return List.of();
}
return source.stream()
.filter(Objects::nonNull)
.toList();
}
Java呼び出し側は常に removeNulls だけを知っていればよく、
実装が for 文か Stream かは気にしなくて済みます。
まとめ:null除外ユーティリティで身につけてほしい感覚
null除外ユーティリティは、単に「if (x != null) を減らす小技」ではなく、
「null が混ざったコレクションを、最初に一度だけ“きれいな世界”に変換する」ための道具です。
List なら removeNulls(List) で「null なし List」を作る。
Set なら removeNulls(Set) で「null なし Set」を作る。
Map なら removeNullValues や removeNullKeysAndValues で、「null を含まないマップ」に正規化する。
「どこまで null を許すか」をユーティリティのメソッド名と実装で明示し、プロジェクトのルールとして固定する。
もしあなたのコードの中に、
if (x != null) { ... }
if (value != null) { list.add(value); }
Javaのようなパターンが何度も出てきているなら、
それを一度「null除外ユーティリティ」にまとめられないか、眺めてみてください。
その小さな整理が、
「null に振り回されず、“きれいなコレクション”を前提にロジックを書けるエンジニア」への、
確かな一歩になります。
