【可読性向上】java.utils.Objects.isNull()によるnullチェック【関数型プログラミングに便利】
前書き:”==”や”!=”による判定と何が違う?
Javaでコードを書くと、nullチェック(NullPointerException防止)は避けられません。
私のようにC言語脳の人は、”==”(等価演算子)や”!=”(不等価演算子)を用いてnullチェックを行うかもしれません。しかし、Java SE8以降は、null関係の判定メソッドとしてjava.utils.ObjectsにisNull()やnonNull()が用意されています。
「演算子使わずにnullチェックするメリットがあるのか?(新しい方法のメリットが分からない)」と思われる方がいらっしゃるかもしれませんが、主に2点メリットがあります。
- ソースコードの可読性向上
- 演算子を用いるよりも関数型プログラミングが書きやすい
本記事では、Java SE11環境で「従来の演算子を用いたnullチェック方法」と「isNull()やnonNull()を用いた方法」を比較します。また、関数型プログラミングにおけるnullチェック方法に関しても説明します。
演算子を用いたnullチェック方法
以下のサンプルコードでは、文字列リストの内容を表示します。
文字列リストの表示前は、
- 文字列リストのnullチェック(”==”によるチェック)
- リストから取り出した文字列に対するnot nullチェック(”!=”によるチェック)
を行います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
import java.util.List; import java.util.Arrays; public class App { public static void main(String[] args) { List<String> names = Arrays.asList("Rance", null, "Sill Plain", "KENTO Kanami", null, "Ria Parapara-Leazas" ); System.out.println("===Argument is not null List==="); printStr(names); System.out.println("===Argument is null.==="); printStr(null); System.out.println("===The end.==="); } /** * 文字列リストの内容を表示する。Listがnullの場合は、何も表示されない。 * Listの要素がnullの場合はその要素はスキップされる。 * @param strs 文字列リスト */ private static void printStr(List<String> strs) { if(strs == null) { return; } for(String str: strs) { if(str != null) { System.out.println(str); } } } } |
以下が実行結果です。文字列リストがnullの場合は何も出力されず、リストの要素がnullの場合は文字列出力がバイパスされます。
1 2 3 4 5 6 7 |
===Argument is not null List=== Rance Sill Plain KENTO Kanami Ria Parapara-Leazas ===Argument is null.=== ===The end.=== |
isNull()およびnonNull()を用いたnullチェック
文字列リスト内容を出力する前述のコード(printStr())をisNull()およびnonNull()で書き換えます。
なお、isNull(Object obj)はobjがnullの場合にtrueを返し、objが非nullの場合はfalseを返します。nonNull(Object obj)は、その逆の動作、すなわち! isNull()となります。
以下、サンプルコードです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
import java.util.List; import java.util.Objects; import java.util.Arrays; public class App { public static void main(String[] args) { List names = Arrays.asList("Rance", null, "Sill Plain", "KENTO Kanami", null, "Ria Parapara-Leazas" ); System.out.println("===Argument is not null List==="); printStr(names); System.out.println("===Argument is null.==="); printStr(null); System.out.println("===The end.==="); } /** * 文字列リストの内容を表示する。Listがnullの場合は、何も表示されない。 * Listの要素がnullの場合はその要素はスキップされる。 * @param strs 文字列リスト */ private static void printStr(List strs) { if(Objects.isNull(strs)) { // "strs == null" return; } for(String str: strs) { if(Objects.nonNull(str)) { // "str != null" System.out.println(str); } } } } |
出力結果に違いはありません。
isNull()およびnonNull()を用いた方が自然言語(英語)で処理内容が記載されているため、可読性が高いです。個人的な印象としては、上記のコードはPythonライクに見えます。
なお、上記のような判定処理でisNull()/nonNull()を用いるのは冗長という意見もあります。
関数型プログラミングでのisNull()/nonNull()
Java Core API(Javadoc)の説明にある通り、isNull()とnonNull()はStram APIで使用するために設計されています。
このメソッドは、
Predicate
(filter(Objects::isNull)
)として使用するために存在します。
Streamを用いた処理は、以下の3工程に大別され、従来のfor文を用いたループ処理よりも簡潔かつ可読性の高いコードを作りやすいです。
- Stream生成:Collectionや配列から生成
- 中間処理 :フィルター/加工/nullチェックなど
- 終端処理 :集計/出力など
以下のサンプルコードでは、Integer型リストに格納された各要素の総和を求める処理をStream APIで記述しています。総和を求めるsum()メソッド内のfilter()処理でリスト要素のnot null判定をしています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
import java.util.List; import java.util.Objects; import java.util.Arrays; import java.util.Collection; public class App { public static void main(String[] args) { List numbers = Arrays.asList(1, null, 2, 3, null, 4); System.out.println("===Calculate list=="); System.out.println(sum(numbers)); System.out.println("===Argument is null.==="); System.out.println(sum(null)); System.out.println("===The end.==="); } /** * Integer型リストの和を返す。 * @param integers Integer型のリスト * @return Integerリストの和を返す。リストがnullの場合は0を返す。 */ public static int sum(List integers) { if (Objects.isNull(integers)) { return 0; } return integers.stream() .filter(Objects::nonNull) // 別の書き方は.filter(i -> i != null) .mapToInt(Integer::intValue).sum(); } } |
以下が実行結果です。Integer型リストがnullの場合は0が出力され、リストの要素がnullの場合はその要素はフィルタリング(除外)されます。
1 2 3 4 5 |
===Calculate list== 10 ===Argument is null.=== 0 ===The end.=== |
フィルタリング処理を「filter(i -> i != null)」と書くより、「filter(Objects::nonNull) 」と書いた方がパッと見で処理を理解しやすい筈です。
おまけ:requireNonNull()
requireNonNull(T obj)は、指定されたオブジェクトがnullでない事を検査するメソッドです。引数がnullではない場合はobjをそのまま返しますが、nullの場合はNullPointerExceptionをスローします。
第二引数に、例外発生時のメッセージを指定できます。
1234 public Foo(Bar bar, Baz baz) {this.bar = Objects.requireNonNull(bar, "bar must not be null");this.baz = Objects.requireNonNull(baz, "baz must not be null");}
後書き
Javaを書く限りはnullチェックが必要ですが、C言語に比べるとJavaはAPIが揃っているので、まだマシと言えるでしょう。
ちなみに、nullチェックを不要にするAPIとして、java.util.Optionalもあります。
ロシア人と国際結婚した地方エンジニア。
小学〜大学院、就職の全てが新潟。
大学の専攻は福祉工学だったのに、エンジニアとして就職。新卒入社した会社ではOS開発や半導体露光装置ソフトを開発。現在はサーバーサイドエンジニアとして修行中。HR/HM(メタル)とロシア妻が好き。サイトに関するお問い合わせやTwitterフォローは、お気軽にどうぞ。