如何使用JavaOptional類-創(chuàng)新互聯(lián)

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

成都創(chuàng)新互聯(lián)公司從2013年開始,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項目成都網(wǎng)站建設(shè)、網(wǎng)站建設(shè)網(wǎng)站策劃,項目實施與項目整合能力。我們以讓每一個夢想脫穎而出為使命,1280元青銅峽做網(wǎng)站,已為上家服務(wù),為青銅峽各地企業(yè)和個人服務(wù),聯(lián)系電話:13518219792

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

Java Optional 簡介

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

新建 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ù)的容器。如果確認(rèn) value 存在,可以用 get() 方法執(zhí)行拆箱操作。具有諷刺意味的是,調(diào)用 get() 前如果不進(jìn)行檢查,可能會拋出 NoSuchElementException。

方法二,得到 Optional 對象的另一種方法是使用 stream。Stream提供的一些方法會返回Optional,可以用來檢查結(jié)果是否存在,例如:

  • 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īng)的業(yè)務(wù)邏輯。在前面的章節(jié)用 if-else實現(xiàn)了功能。當(dāng)然,還有其他辦法: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 不存在
});

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

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

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

另一個示例

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

首先,加入下面代碼

從 POJO 類 Car 開始。它遵循 immutable 模式,所有字段都標(biāo)記為 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 倉庫的做法類似,結(jié)果可能為 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ù),便于演示。為了突出重點(diǎn),避免問題復(fù)雜化,下面的討論專注于 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對應(yīng)的汽車,檢查該車是否存在。輸入俄羅斯車牌找不到對應(yīng)的汽車,因為倉庫中只有捷克車。結(jié)果為 null 可能會拋出 NullPointerException。

接下來用Java Optional。第一步,獲得 Optional 實例,從存儲庫中使用指定方法返回 Optional:

@Test
void getCarByIdWithOptional(){
   Optional<Car> tesla = repository.findCarByIdWithOptional("1A9 4321");
   tesla.ifPresent(System.out::println);
}

這時調(diào)用findCarByIdWithOptional方法打印車輛信息(如果有的話)。運(yùn)行程序,得到以下結(jié)果:

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返回默認(rèn)值:

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 來完成上述任務(wù)。例如,設(shè)置默認(rèn)值:

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

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

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

如何根據(jù)數(shù)據(jù)是否存在來執(zhí)行相應(yīng)操作,類似 Optional 中 ifPresent?有幾種實現(xiàn)方式。與 Optional 中 isPresent 類似,在 Option 中對應(yīng)的方法稱為 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ù)跟進(jìn)一些類似 map、narrow、isLazy 和 when 這樣有趣的功能。

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

網(wǎng)頁標(biāo)題:如何使用JavaOptional類-創(chuàng)新互聯(lián)
URL地址:http://bm7419.com/article38/hdppp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供商城網(wǎng)站、網(wǎng)站制作、定制網(wǎng)站、響應(yīng)式網(wǎng)站、微信公眾號、關(guān)鍵詞優(yōu)化

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站托管運(yùn)營