仲間のJava開発者の皆さん、
JDK8はまだリリースされていないので(とにかく今のところではありません)、主題は少しin advance
かもしれませんが、Lambda式に関する記事、特に既知の新しいコレクションAPIに関連する部分を読んでいましたストリームとして。
Java Magazineの記事 (カワウソの集団アルゴリズムです。)で与えられている例は次のとおりです。
Set<Otter> otters = getOtters();
System.out.println(otters.stream()
.filter(o -> !o.isWild())
.map(o -> o.getKeeper())
.filter(k -> k.isFemale())
.into(new ArrayList<>())
.size());
私の質問は、Setの内部反復の途中で、カワウソの1つがヌルの場合に何が起こるかということです。
NullPointerExceptionがスローされることを期待しますが、おそらく以前の開発パラダイム(機能しない)にとどまっている可能性があります。これを処理する方法について誰かに教えてもらえますか?
これが本当にNullPointerExceptionをスローする場合、この機能は非常に危険であることがわかり、以下のようにのみ使用する必要があります。
最良のオプション、または他のオプションは何ですか?
ありがとう!
現在の考え方は、nullを「許容」すること、つまり、一般にnullを許可することのように思われますが、一部の操作は許容度が低く、最終的にNPEをスローする場合があります。 Lambda Librariesエキスパートグループメーリングリストの discussion of nulls 、特に this message 。その後、オプション#3についてのコンセンサスが浮上しました(Doug Leaからの顕著な異議があります)。はい、そうです、NPEで爆発するパイプラインに関するOPの懸念は有効です。
Tony Hoareがnullを "Billion Dollar Mistake。" と呼んだのは何の役にも立たない。nullの扱いは本当の痛みである。クラシックコレクション(ラムダやストリームを考慮しない)であっても、nullには問題があります。 fge がコメントで言及しているように、コレクションによってはnullを許可するものと許可しないものがあります。 nullを許可するコレクションでは、これによりAPIにあいまいさが生じます。たとえば、 Map.get() の場合、nullの戻り値は、キーが存在しその値がnullであるか、キーが存在しないことを示します。 。これらのケースを明確にするために、追加の作業を行う必要があります。
Nullの通常の使用法は、値がないことを示すことです。 Java SE 8で提案されているこれに対処するアプローチは、新しい Java.util.Optional
タイプを導入することです。値、デフォルト値を提供する動作、例外をスローする動作、または値が存在しない場合は関数を呼び出す動作など。 Optional
は新しいAPIでのみ使用されますが、システム内の他のすべては依然としてnullの可能性に耐える必要があります。
私のアドバイスは、可能な限り実際のnull参照を避けることです。 「ヌル」のカワウソがどのように存在する可能性があるかを与えられた例から見るのは難しいです。ただし、必要な場合は、ヌル値をフィルタリングするか、センチネルオブジェクトにマッピングするというOPの提案( ヌルオブジェクトパターン )は素晴らしいアプローチです。
回答は100%正しいですが、 オプション を使用して、リスト自体のnull
ケース処理を改善するための小さな提案です。
List<String> listOfStuffFiltered = Optional.ofNullable(listOfStuff)
.orElseGet(Collections::emptyList)
.stream()
.filter(Objects::nonNull)
.collect(Collectors.toList());
Optional.ofNullable(listOfStuff).orElseGet(Collections::emptyList)
部分により、listOfStuff
がnullの場合をうまく処理し、NullPointerExceptionで失敗する代わりにemptyListを返すことができます。
スチュアートの答えは素晴らしい説明を提供しますが、別の例を提供したいと思います。
Null値を含むStreamでreduce
を実行しようとしたときにこの問題に遭遇しました(実際にはLongStream.average()
で、これは削減の一種です)。 average()はOptionalDouble
を返すため、Streamにnullが含まれる可能性があると想定しましたが、代わりにNullPointerExceptionがスローされました。これは、 Stuartの説明 null v。emptyによるものです。
そのため、OPが示唆するように、次のようなフィルターを追加しました。
list.stream()
.filter(o -> o != null)
.reduce(..);
または、以下に示すタンジェントのように、Java APIによって提供される述語を使用します。
list.stream()
.filter(Objects::nonNull)
.reduce(..);
Stuartがリンクしたメーリングリストの議論から: StreamsのnullのBrian Goetz
ストリームからヌル値をフィルタリングするだけの場合は、単純に Java.util.Objects.nonNull(Object) へのメソッド参照を使用できます。そのドキュメントから:
このメソッドは、 述語 、
filter(Objects::nonNull)
として使用するために存在します
例えば:
List<String> list = Arrays.asList( null, "Foo", null, "Bar", null, null);
list.stream()
.filter( Objects::nonNull ) // <-- Filter out null values
.forEach( System.out::println );
これは印刷されます:
Foo
Bar
GroupingByの前にnullインスタンスを除外します。
MyObjectlist.stream()
.filter(p -> p.getSomeInstance() != null)
.collect(Collectors.groupingBy(MyObject::getSomeInstance));