您好,登錄后才能下訂單哦!
這篇文章主要講解了“如何使用Java Optional類”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“如何使用Java Optional類”吧!
注意:示例代碼要求使用Java 11及更高版本。所有代碼在 Vavr0.10.2環境下完成測試。
Java Optional 簡介
Optional 并不是什么新概念,像 Haskell、Scala 這樣的函數式編程語言已經提供了實現。調用方法后,返回值未知或者不存在(比如 null)的情況下,用 Optional 處理非常好用。下面通過實例進行介紹。
新建 Optional 實例
首先,需要獲得 Optional 實例,有以下幾種方法可以新建 Optional 實例。不僅如此,還可以創建empty Optional。方法一,通過 value 創建,過程非常簡單:
Optional<Integer> four = Optional.of(Integer.valueOf(4));
if (four.isPresent){
System.out.println("Hoorayy! We have a value");
}
else {
System.out.println("No value");
}
為Integer 4 新建一個Optional實例。這種方法得到的 Optional 始終包含一個 value 且不為 null,例如上面這個示例。使用 ifPresent() 可以檢查value是否存在。可以注意到 four 不是 Integer,而是一個裝有整數的容器。如果確認 value 存在,可以用 get() 方法執行拆箱操作。具有諷刺意味的是,調用 get() 前如果不進行檢查,可能會拋出 NoSuchElementException。
方法二,得到 Optional 對象的另一種方法是使用 stream。Stream提供的一些方法會返回Optional,可以用來檢查結果是否存在,例如:
findAny
findFirst
max
min
reduce
查看下面的代碼段:
Optional<Car> car = cars.stream().filter(car->car.getId().equalsIgnoreCase(id)).findFirst();
方法三,使用 Nullable 新建 Optional。可能產生 null:
Optional<Integer> nullable = Optional.ofNullable(client.getRequestData());
最后,可以新建一個 empty Optional:
Optional<Integer> nothing = Optional.empty();
如何使用 Optional
獲得 Optional 對象后即可使用。一種典型的場景是在 Spring 倉庫中根據 Id 查找記錄。可以使用 Optional 實現代碼邏輯,避免 null 檢查(順便提一下,Spring 也支持 Vavr Option)。比如,從圖書倉庫里查找一本書。
Optional<Book> book = repository.findOne("some id");
首先,如果有這本書,可以繼續執行對應的業務邏輯。在前面的章節用 if-else實現了功能。當然,還有其他辦法:Optional 提供了一個方法,接收 Consumer 對象作為輸入:
repository.findOne("some id").ifPresent(book -> System.out.println(book));
還可以直接使用方法引用,看起來更簡單:
repository.findOne("some id").ifPresent(System.out::println);
如果倉庫中沒有該書,可以用ifPresentOrElseGet提供回調函數:
repository.findOne("some id").ifPresentOrElseGet(book->{
// 如果 value 存在
}, ()->{
// 如果 value 不存在
});
如果結果不存在,可以返回另一個value:
Book result = repository.findOne("some id").orElse(defaultBook);
但是,Optional 也有缺點,使用時需要注意。最后一個例子中,“確保”無論如何都能獲得一本書,可能在倉庫中,也可能來自 orElse。但如果默認的返回值不是常量或者需要支持一些復雜方法該怎么辦?首先,Java 無論如何都會執行 findOne,然后調用 orElse方法。默認返回值可以為常量,但正如我之前所說那樣,執行過程比較耗時。
另一個示例
下面用一個簡單的示例介紹如何實際使用 Optional 和 Option 類。有一個 CarRepository,可以根據提供的 ID(比如車牌號)查找汽車,接下來用這個示例介紹如何使用 Optional 和 Option。
首先,加入下面代碼
從 POJO 類 Car 開始。它遵循 immutable 模式,所有字段都標記為 final,只包含 getter 沒有 setter。初始化時提供所有數據:
public class Car {
private final String name;
private final String id;
private final String color;
public Car (String name, String id, String color){
this.name = name;
this.id = id;
this.color = color;
}
public String
getId(){
return id;
}
public String
getColor() {
return color;
}
public String
getName() {
return name;
}
@Override
public String
toString() {
return "Car "+name+" with license id "+id+" and of color "+color;
}
}
接下來創建 CarRepository類。提供兩種方法根據Id查找汽車:一種是老辦法,使用 Optional。和之前在 Spring 倉庫的做法類似,結果可能為 null。
publicclass CarRepository {
private List<Car> cars;
public CarRepository(){
getSomeCars();
}
Car
findCarById(String id){
for (Car car: cars){function(){ //外匯跟單www.gendan5.com if (car.getId().equalsIgnoreCase(id)){
return car;
}
}
return null;
}
Optional<Car> findCarByIdWithOptional(String id){
return cars.stream().filter(car->car.getId().equalsIgnoreCase(id)).findFirst();
}
private void getSomeCars(){
cars = new ArrayList<>();
cars.add(new Car("tesla", "1A9 4321", "red"));
cars.add(new Car("volkswagen", "2B1 1292", "blue"));
cars.add(new Car("skoda", "5C9 9984", "green"));
cars.add(new Car("audi", "8E4 4321", "silver"));
cars.add(new Car("mercedes", "3B4 5555", "black"));
cars.add(new Car("seat", "6U5 3123", "white"));
}
}
注意:初始化過程會在倉庫中添加一些汽車模擬數據,便于演示。為了突出重點,避免問題復雜化,下面的討論專注于 Optional 和 Option。
使用Java Optional
使用JUnit創建一個新測試:
@Test
void getCarById(){
Car car = repository.findCarById("1A9 4321");
Assertions.assertNotNull(car);
Car nullCar = repository.findCarById("M 432 KT");
Assertions.assertThrows(NullPointerException.class, ()->{
if (nullCar == null){
throw new NullPointerException();
}
});
}
上面的代碼段采用了之前的老辦法。查找捷克牌照1A9 4321對應的汽車,檢查該車是否存在。輸入俄羅斯車牌找不到對應的汽車,因為倉庫中只有捷克車。結果為 null 可能會拋出 NullPointerException。
接下來用Java Optional。第一步,獲得 Optional 實例,從存儲庫中使用指定方法返回 Optional:
@Test
void getCarByIdWithOptional(){
Optional<Car> tesla = repository.findCarByIdWithOptional("1A9 4321");
tesla.ifPresent(System.out::println);
}
這時調用findCarByIdWithOptional方法打印車輛信息(如果有的話)。運行程序,得到以下結果:
Car tesla with license id 1A9 4321 and of color red
但是,如果代碼中沒有特定方法該怎么辦?這種情況可以從方法返回可能包含 null 的 Optional,稱為nullable。
Optional<Car> nothing = Optional.ofNullable(repository.findCarById("5T1 0965"));
Assertions.assertThrows(NoSuchElementException.class, ()->{
Car car = nothing.orElseThrow(()->new NoSuchElementException());
});
上面這段代碼段中,我們發現了另一種方法。通過 findCarById 創建 Optional,如果未找到汽車可以返回 null。沒有找到車牌號5T1 0965汽車時,可以用 orElseThrow 手動拋出 NoSuchElementException。另一種情況,如果請求的數據不在倉庫中,可以用orElse返回默認值:
Car audi = repository.findCarByIdWithOptional("8E4 4311")
.orElse(new Car("audi",
"1W3 4212",
"yellow"));
if (audi.getColor().equalsIgnoreCase("silver")){
System.out.println("We have silver audi in garage!");
}
else {
System.out.println("Sorry, there is no silver audi, but we called you a taxi");
}
好的,車庫里沒有找到銀色奧迪,只好打車了!
使用 Vavr Option
Vavr OptionOption提供了另一種解決辦法。首先,在項目中添加依賴,(使用 Maven)安裝 Vavr:
<dependency>
<groupId>io.vavr</groupId>
<artifactId>vavr</artifactId>
<version>0.10.2</version>
</dependency>
簡而言之,Vavr 提供了類似的 API 新建 Option 實例。可以從 nullable 新建 Option 實例,像下面這樣:
Option<Car> nothing = Option.of(repository.findCarById("T 543 KK"));
也可以用 none 靜態方法創建一個empty容器:
Option<Car> nullable = Option.none();
此外,還有一種方法可以用 Java Optional 新建 Option。看下面這段代碼:
Option<Car> result = Option.ofOptional(repository.findCarByIdWithOptional("5C9 9984"));
使用 Vavr Option,可以使用與 Optional相同的 API 來完成上述任務。例如,設置默認值:
Option<Car> result = Option.ofOptional(repository.findCarByIdWithOptional("5C9 9984"));
Car skoda = result.getOrElse(new Car("skoda",
"5E2 4232",
"pink"));
System.out.println(skoda);
或者,請求的數據不存在時可以拋出異常:
Option<Car> nullable = Option.none();
Assertions.assertThrows(NoSuchElementException.class, ()->{
nullable.getOrElseThrow(()->new NoSuchElementException());
});
另外,當數據不可用時,可以執行以下操作:
nullable.onEmpty(()->{
///runnable
});
如何根據數據是否存在來執行相應操作,類似 Optional 中 ifPresent?有幾種實現方式。與 Optional 中 isPresent 類似,在 Option 中對應的方法稱為 isDefined:
if (result.isDefined()){
// 實現功能
}
然而,使用 Option能擺脫 if-else。是否可以用Optional相同的方式完成?使用 peek 操作:
result.peek(val -> System.out.println(val)).onEmpty(() -> System.out.println("Result is missed"));
此外,Vavr Option還提供了一些其他非常有用的方法,在函數式編程上比Optional類效果更好。因此,建議您花一些時間來探索 Vavr Option javadocs嘗試使用這些API。我會持續跟進一些類似 map、narrow、isLazy 和 when 這樣有趣的功能。
感謝各位的閱讀,以上就是“如何使用Java Optional類”的內容了,經過本文的學習后,相信大家對如何使用Java Optional類這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。