溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何使用Java Optional類

發(fā)布時間:2021-12-21 16:44:16 來源:億速云 閱讀:167 作者:iii 欄目:編程語言

這篇文章主要講解了“如何使用Java Optional類”,文中的講解內(nèi)容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“如何使用Java Optional類”吧!

注意:示例代碼要求使用Java 11及更高版本。所有代碼在 Vavr0.10.2環(huán)境下完成測試。

Java Optional 簡介

Optional 并不是什么新概念,像 Haskell、Scala 這樣的函數(shù)式編程語言已經(jīng)提供了實現(xiàn)。調(diào)用方法后,返回值未知或者不存在(比如 null)的情況下,用 Optional 處理非常好用。下面通過實例進行介紹。

新建 Optional 實例

首先,需要獲得 Optional 實例,有以下幾種方法可以新建 Optional 實例。不僅如此,還可以創(chuàng)建empty Optional。方法一,通過 value 創(chuàng)建,過程非常簡單:

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,而是一個裝有整數(shù)的容器。如果確認 value 存在,可以用 get() 方法執(zhí)行拆箱操作。具有諷刺意味的是,調(diào)用 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??赡墚a(chǎn)生 null:

Optional<Integer> nullable = Optional.ofNullable(client.getRequestData());

最后,可以新建一個 empty Optional:

Optional<Integer> nothing = Optional.empty();

如何使用 Optional

獲得 Optional 對象后即可使用。一種典型的場景是在 Spring 倉庫中根據(jù) Id 查找記錄??梢允褂?Optional 實現(xiàn)代碼邏輯,避免 null 檢查(順便提一下,Spring 也支持 Vavr Option)。比如,從圖書倉庫里查找一本書。

Optional<Book> book = repository.findOne("some id");

首先,如果有這本書,可以繼續(xù)執(zhí)行對應的業(yè)務邏輯。在前面的章節(jié)用 if-else實現(xiàn)了功能。當然,還有其他辦法:Optional 提供了一個方法,接收 Consumer 對象作為輸入:

repository.findOne("some id").ifPresent(book -> System.out.println(book));

還可以直接使用方法引用,看起來更簡單:

repository.findOne("some id").ifPresent(System.out::println);

如果倉庫中沒有該書,可以用ifPresentOrElseGet提供回調(diào)函數(shù):

repository.findOne("some id").ifPresentOrElseGet(book->{
// 如果 value 存在
}, ()->{
// 如果 value 不存在
});

如果結果不存在,可以返回另一個value:

Book result = repository.findOne("some id").orElse(defaultBook);

但是,Optional 也有缺點,使用時需要注意。最后一個例子中,“確?!睙o論如何都能獲得一本書,可能在倉庫中,也可能來自 orElse。但如果默認的返回值不是常量或者需要支持一些復雜方法該怎么辦?首先,Java 無論如何都會執(zhí)行 findOne,然后調(diào)用 orElse方法。默認返回值可以為常量,但正如我之前所說那樣,執(zhí)行過程比較耗時。

另一個示例

下面用一個簡單的示例介紹如何實際使用 Optional 和 Option 類。有一個 CarRepository,可以根據(jù)提供的 ID(比如車牌號)查找汽車,接下來用這個示例介紹如何使用 Optional 和 Option。

首先,加入下面代碼

從 POJO 類 Car 開始。它遵循 immutable 模式,所有字段都標記為 final,只包含 getter 沒有 setter。初始化時提供所有數(shù)據(jù):

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;
   }
}

接下來創(chuàng)建 CarRepository類。提供兩種方法根據(jù)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"));
   }
}

注意:初始化過程會在倉庫中添加一些汽車模擬數(shù)據(jù),便于演示。為了突出重點,避免問題復雜化,下面的討論專注于 Optional 和 Option。

使用Java Optional

使用JUnit創(chuàng)建一個新測試:

@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);
}

這時調(diào)用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());
});

上面這段代碼段中,我們發(fā)現(xiàn)了另一種方法。通過 findCarById 創(chuàng)建 Optional,如果未找到汽車可以返回 null。沒有找到車牌號5T1 0965汽車時,可以用 orElseThrow 手動拋出 NoSuchElementException。另一種情況,如果請求的數(shù)據(jù)不在倉庫中,可以用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 靜態(tài)方法創(chuàng)建一個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);

或者,請求的數(shù)據(jù)不存在時可以拋出異常:

Option<Car> nullable = Option.none();
Assertions.assertThrows(NoSuchElementException.class, ()->{
nullable.getOrElseThrow(()->new NoSuchElementException());
});

另外,當數(shù)據(jù)不可用時,可以執(zhí)行以下操作:

nullable.onEmpty(()->{
///runnable
});

如何根據(jù)數(shù)據(jù)是否存在來執(zhí)行相應操作,類似 Optional 中 ifPresent?有幾種實現(xiàn)方式。與 Optional 中 isPresent 類似,在 Option 中對應的方法稱為 isDefined:

if (result.isDefined()){
// 實現(xiàn)功能
}

然而,使用 Option能擺脫 if-else。是否可以用Optional相同的方式完成?使用 peek 操作:

result.peek(val -> System.out.println(val)).onEmpty(() -> System.out.println("Result is missed"));

此外,Vavr Option還提供了一些其他非常有用的方法,在函數(shù)式編程上比Optional類效果更好。因此,建議您花一些時間來探索 Vavr Option javadocs嘗試使用這些API。我會持續(xù)跟進一些類似 map、narrow、isLazy 和 when 這樣有趣的功能。

感謝各位的閱讀,以上就是“如何使用Java Optional類”的內(nèi)容了,經(jīng)過本文的學習后,相信大家對如何使用Java Optional類這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI