java - optional用法 - optional string to string




java 8 findFirst vs map可選 (3)

首先,你的兩個代碼片段map是不同的操作:

//            v--- stream intermediate operation
list.stream().map(Foo::getAttr).findAny().orElse(null);  //A
//                      v---- a Optional utility method 
list.stream().findAny().map(Foo::getAttr).orElse(null);  //B

並且在Stream#findAny操作中發生NullPointerException ,因為它不能接受null值。 由於它使用Optional.of而不是Optional.ofNullable 。 並且Stream#findAny的文檔已經聲明:

拋出

NullPointerException - 如果選擇的元素為null

所以如果你想讓你的A代碼片段正常工作,你必須在調用Stream#findAny之前過濾所有的null值,例如:

//when no elements in stream, `findAny` will be return a empty by Optional.empty()
//                                                       v   
list.stream().map(Foo::getAttr).filter(Objects::nonNull).findAny().orElse(null);//A

鑑於此代碼:

class Foo {
  Integer attr;
  public Integer getAttr() {return attr;}
}

List<Foo> list = new ArrayList<>();
list.add(new Foo());

list.stream().map(Foo::getAttr).findAny().orElse(null);  //A
list.stream().findAny().map(Foo::getAttr).orElse(null);  //B

A線投擲

java.lang.NullPointerException:null

而行B則返回null。

這種行為的原因是什麼? findAny()map()返回Optional<T>


list.stream().map(Foo::getAttr).findAny().orElse(null);

對於流的Java文檔說:Stream:“返回一個包含將給定函數應用到此流的元素的結果的流”,如果選擇的元素為null,則findAny()可以返回aNullPointerException。 在你的Foo類中,Integer(不是int)在默認情況下被設置為null,因為被聲明了,但是沒有被初始化。 請參閱Primitives 在Java中 查看默認值和對像初始化

初始化是不同的:A)類成員(對象和原語)B)局部變量


這顯然是因為你執行這些操作的順序,也是因為findAny顯式說: throws NullPointerException if the element selected is null

當你做map(Foo::getAttr)你已經有效地將它映射為null ,所以你的Stream現在包含一個null ; 因此findAny打破了一個異常(因為findAny應用於null)

另一個操作首先找到Foo對象,然後將其映射到Foo::getAttr (從而將其映射到Optional.empty() ),從而orElse

另外,這會更有意義(至少對我來說):

 list.stream()
     .findAny()
     .flatMap(f -> Optional.ofNullable(f.getAttr()))
     .orElse(null);

flatMap將映射到Optional<Integer> (attributes),如果這個是empty獲得orElse結果。





optional