2017-03-03 9 views
1

私は、削減したいenum値のストリームを持っています。ストリームが空であるか、異なる値を含む場合は、nullが必要です。単一の値(複数のインスタンス)しか含まれていない場合は、その値が必要です。結果がnullのときにStream.reduce(BinaryOperator)がNullPointerをスローするのはなぜですか?

[]    null 
[A, B, A]  null 
[A]    A 
[A, A, A]  A 

私は削減でそれを実行しようとしました:

return <lots of filtering, mapping, and other stream stuff> 
     .reduce((enum1, enum2) -> enum1 == enum2 ? enum1 : null) 
     .orElse(null); 

結果がnullあるとき、この減らす方法がNullPointerExceptionをスローするので残念ながら、これは、動作しません。誰がなぜそれが起こるのか知っていますか? nullは有効な結果ではないのはなぜですか?今の

、私はこのように、これを解決:

MyEnum[] array = <lots of filtering, mapping, and other stream stuff> 
       .distinct() 
       .toArray(MyEnum[]::new); 
return array.length == 1 ? array[0] : null; 

を、これは動作しますが、私はこの「迂回」と満足していません。私はそれが適切であり、すべてを1つのストリームに入れるように見えたので、減少が気に入った。

誰もがreduce(これはあまりにも多くのコードではない)の代わりに考えることができますか?

+0

この回答は、なぜあなたにいくつかの洞察を与えるかもしれません。http://stackoverflow.com/a/17115490/1544715 – Magnus

答えて

1

離れてnull結果と「ノー結果」(空のストリームを)伝えることは不可能であろうと、Optionalを返すすべてのストリーム方法はnull値を許可していません。あなたが仕事-の周りにすることができ、この残念な型の安全性を(enumセット外のいかなる型互換値が存在しないとして)一時停止する必要がプレースホルダ値、と

return <lots of filtering, mapping, and other stream stuff> 
    .reduce((enum1, enum2) -> enum1 == enum2? enum1: "") 
    .map(r -> r==""? null: (MyEnum)r) 
    .orElse(null); 

Optional.mapが返されますマッピング関数がnullを返した場合は空のオプションなので、そのステップの後に空のストリームとnullの結果を区別することはできません。orElse(null)はどちらの場合もnullを返します。

しかし、配列の迂回は、配列が中間結果のための最良の選択肢ではないので、不満足に感じるかもしれませんか? enumタイプが64個の定数以下である場合にどのようにについての

EnumSet<MyEnum> set = <lots of filtering, mapping, and other stream stuff> 
    .collect(Collectors.toCollection(() -> EnumSet.noneOf(MyEnum.class))); 
return set.size()==1? set.iterator().next(): null; 

EnumSetはビットセット、単一long値です。それは、アレイよりもはるかに安価だとSet sが自然に異なっていることから、ボンネットの下にHashSetを作成し、ストリーム上のdistinct()操作のための必要はありません。

+0

ありがとうございます。私はあなたが与えた理由を理解していますが、私はまだ試してみてください。配列に切り替える前に 'toSet()'を使って収集しようとしました(より簡潔で速いと思いました)。私はEnumSetを知らなかった、私はそれを試してみるだろう。 –

0

ほとんどのストリーム上位関数では、パラメータまたは関数の戻り値としてnullを使用できません。彼らはまだ別のものを防ぐことですbillion-dollar mistake。そのような応答はhere文書化されている:

.....

例外

オプション(BinaryOperatorアキュムレータ)を低減: 場合NullPointerException - 還元の結果がnullの場合

0

本当に数学的なアプローチ(私は同意するのは難しい)はどうですか?一般

Arrays.stream(array).map(e -> e.ordinal() + 1).reduce(Integer::sum) 
      .map(i -> (double) i/array.length == array[0].ordinal() + 1 ? array[0] : null) 
      .orElse(null) 
+0

配列は生成されておらず、配列を生成することは、すでにOPが取得したい回避策の一部です捨てる。 – Holger

関連する問題