如何處理null
怎樣做才能避免不期而至的NullPointerException呢?通常,可以在需要的地方添加null的檢查(過於激進的防御式檢查甚至會在不太需要的地方添加檢測代碼),並且添加的方式往往各有不同。
null-安全的第一種嘗試:深層質疑

“深層質疑”,原因是它不斷重復着一種模式:每次不確定一個變量是否為null時,都需要添加一個進一步嵌套的if塊,也增加了代碼縮進的層數。很明顯,這種方式不具備擴展性,同時還犧牲了代碼的可讀性。
null-安全的第二種嘗試:過多的退出語句

第二種嘗試中,試圖避免深層遞歸的if語句塊,采用了一種不同的策略:每次遭遇null變量,都返回一個字符串常量“Unknown”。然而,這種方案遠非理想,現在這個方法有了四個截然不同的退出點,使得代碼的維護異常艱難。
使用Optional獲取car的Insurance名稱
汲取Haskell和Scala的靈感,Java 8中引入了一個新的類java.util.Optional<T>。這是一個封裝Optional值的類。
public String getCarInsuranceName(Optional<Person> person){ return person.flatMap(Person::getCar) .flatMap(Car::getInsurance) .map(Insurance::getName) .orElse("Unknown");//如果Optional的結果值為空,設置默認值 }
創建Optional對象
1. 聲明一個空的Optional
可以通過靜態工廠方法Optional.empty,創建一個空的Optional對象:
Optional<Car> optCar = Optional.empty();
2. 依據一個非空值創建Optional
還可以使用靜態工廠方法Optional.of,依據一個非空值創建一個Optional對象:
如果car是一個null,這段代碼會立即拋出一個NullPointerException,而不是等到試圖訪問car的屬性值時才返回一個錯誤。
Optional<Car> optCar = Optional.of(car);
3. 可接受null的Optiona
使用靜態工廠方法Optional.ofNullable,可以創建一個允許null值的Optional對象:
如果car是null,那么得到的Optional對象就是個空對象。
Optional<Car> optCar = Optional.ofNullable(car);
Optional類的方法

•null引用在歷史上被引入到程序設計語言中,目的是為了表示變量值的缺失。
•Java 8中引入了一個新的類java.util.Optional<T>,對存在或缺失的變量值進行建模。
•可以使用靜態工廠方法Optional.empty、Optional.of以及Optional.ofNullable創建Optional對象。
•Optional類支持多種方法,比如map、flatMap、filter,它們在概念上與Stream類中對應的方法十分相似。
•使用Optional會迫使更積極地解引用Optional對象,以應對變量值缺失的問題,最終,能更有效地防止代碼中出現不期而至的空指針異常。
•使用Optional能幫助設計更好的API,用戶只需要閱讀方法簽名,就能了解該方法是否接受一個Optional類型的值。
附:類代碼
public class Person { private Car car; public Car getCar() { return car; } } public class Car { private Insurance insurance; public Insurance getInsurance() { return insurance; } } public class Insurance { private String name; public String getName() { return name; } }
附:使用Optional重新定義Person/Car/Insurance的數據模型
public class Person { private Optional<Car> car;//人可能有車,也可能沒有車,因此將這個字段聲明為Optional public Optional<Car> getCar() { return car; } } public class Car { private Optional<Insurance> insurance;//車可能進行了保險,也可能沒有保險,所以將這個字段聲明為Optional public Optional<Insurance> getInsurance() { return insurance; } } public class Insurance { private String name;//保險公司必須有名字 public String getName() { return name; } }
文章來源:java8實戰 第十章
