欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中Optional的使用指南

 更新時(shí)間:2021年01月31日 11:10:23   作者:申城異鄉(xiāng)人  
這篇文章主要給大家介紹了關(guān)于Java中Optional使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

提到NullPointerException(簡稱NPE)異常,相信每個(gè)Java開發(fā)人員都不陌生,從接觸編程的第1天起,它就和我們?nèi)缬半S形,最近處理的線上bug中,有不少都是對象沒判空導(dǎo)致的NullPointerException異常。

1. 簡單回顧

引起NullPointerException異常的地方有很多,比如調(diào)用String的trim()方法,比如對BigDecimal進(jìn)行計(jì)算時(shí),比如將包裝類型轉(zhuǎn)化為基本類型時(shí),這里簡單回顧下。

假設(shè)有個(gè)導(dǎo)入模版定義如下:

package com.zwwhnly.springbootaction.model;

import lombok.AllArgsConstructor;
import lombok.Data;

/**
 * 導(dǎo)入模版
 */
@Data
@AllArgsConstructor
public class ImportTemplate {
 /**
 * 模版id
 */
 private int templateId;

 /**
 * 模版名稱
 */
 private String templateName;

 /**
 * 模版下載url
 */
 private String url;

 /**
 * 備注
 */
 private String remark;
}

然后看下如下代碼:

public static void main(String[] args) {
 ImportTemplate importTemplate = getImportTemplateById(1);
 System.out.println(importTemplate.getUrl());
}

public static ImportTemplate getImportTemplateById(int id) {
 return new ImportTemplate(1, "銷售訂單-普通商品導(dǎo)入模版", "o_w-140e3c1f41c94f238196539558e25bf7", null);
}

正常情況下,這段代碼肯定是沒有問題的,但當(dāng)getImportTemplateById方法返回null時(shí),這段代碼就會拋出NullPointerException異常,如下所示:

public static ImportTemplate getImportTemplateById(int id) {
 return null;
}

為了程序能正常運(yùn)行,就要判斷importTemplate是否為null,所以代碼就修改為了:

public static void main(String[] args) {
 ImportTemplate importTemplate = getImportTemplateById(1);
 if (importTemplate != null) {
 System.out.println(importTemplate.getUrl());
 }
}

項(xiàng)目中類似的判空代碼應(yīng)該有很多,大家可以自行看下自己項(xiàng)目的代碼。

2. 使用Optional

為了避免NullPointerException異常,JDK1.8新增了Optional類來處理空指針異常,該類位于java.util包下,提供了一系列方法,

并且可以配合Lambda表達(dá)式一起使用,使代碼看起來更加清晰,接下來我們看下它的使用方法。

2.1 創(chuàng)建實(shí)例

創(chuàng)建Optional實(shí)例有以下3種方式,分別為:

調(diào)用empty方法

Optional<ImportTemplate> optionalImportTemplate = Optional.empty();

調(diào)用of方法

ImportTemplate importTemplate = new ImportTemplate(1, "銷售訂單-普通商品導(dǎo)入模版",
 "o_w-140e3c1f41c94f238196539558e25bf7", null);
Optional<ImportTemplate> optionalImportTemplate = Optional.of(importTemplate);

調(diào)用ofNullable方法(推薦)

ImportTemplate importTemplate = new ImportTemplate(1, "銷售訂單-普通商品導(dǎo)入模版",
  "o_w-140e3c1f41c94f238196539558e25bf7", null);
Optional<ImportTemplate> optionalImportTemplate = Optional.ofNullable(importTemplate);

值得注意的是,當(dāng)參數(shù)為null時(shí),調(diào)用of方法會拋NullPointerException異常,但調(diào)用ofNullable方法不會(更符合使用場景),因此推薦使用ofNullable方法:

ImportTemplate importTemplate = null;
Optional<ImportTemplate> optionalImportTemplate = Optional.of(importTemplate);

2.2 判斷是否有值

可以調(diào)用isPresent方法來判斷對象是否有值(不為null),使用方法如下所示:

ImportTemplate importTemplate = null;
Optional<ImportTemplate> optionalImportTemplate = Optional.ofNullable(importTemplate);

System.out.println(optionalImportTemplate.isPresent());

以上代碼的輸出結(jié)果為:

ImportTemplate importTemplate = new ImportTemplate(1, "銷售訂單-普通商品導(dǎo)入模版",
  "o_w-140e3c1f41c94f238196539558e25bf7", null);
Optional<ImportTemplate> optionalImportTemplate = Optional.ofNullable(importTemplate);

System.out.println(optionalImportTemplate.isPresent());

以上代碼的輸出結(jié)果為:

看下isPresent的源碼,邏輯非常簡單,就是判斷了我們傳入的對象是否有值,即不為null:

/**
 * Return {@code true} if there is a value present, otherwise {@code false}.
 *
 * @return {@code true} if there is a value present, otherwise {@code false}
 */
public boolean isPresent() {
 return value != null;
}

2.3 獲取值

可以調(diào)用get方法來獲取對象的有值,使用方法如下所示:

ImportTemplate importTemplate = new ImportTemplate(1, "銷售訂單-普通商品導(dǎo)入模版",
  "o_w-140e3c1f41c94f238196539558e25bf7", null);
Optional<ImportTemplate> optionalImportTemplate = Optional.ofNullable(importTemplate);
System.out.println(optionalImportTemplate.get());

以上代碼的輸出結(jié)果為:

值得注意的是,當(dāng)我們傳入的對象為null時(shí),調(diào)用get方法會拋出java.util.NoSuchElementException異常,而不是返回null。

ImportTemplate importTemplate = null;
Optional<ImportTemplate> optionalImportTemplate = Optional.ofNullable(importTemplate);
System.out.println(optionalImportTemplate.get());

以上代碼的輸出結(jié)果為:

看下get方法的源碼,就可以知道原因:

public T get() {
 if (value == null) {
  throw new NoSuchElementException("No value present");
 }
 return value;
}

2.4 先用isPresent,再用get(不推薦)

然后我們回顧下文初的代碼:

ImportTemplate importTemplate = getImportTemplateById(1);
if (importTemplate != null) {
 System.out.println(importTemplate.getUrl());
}

可能很多同學(xué)會把代碼優(yōu)化為下面這樣的寫法:

Optional<ImportTemplate> optionalImportTemplate = Optional.ofNullable(getImportTemplateById(1));
if (optionalImportTemplate.isPresent()) {
 System.out.println(optionalImportTemplate.get().getUrl());
}

不推薦這么使用,因?yàn)榕袛嗟牡胤經(jīng)]減少,而且還不如原來看起來清晰。

2.5 ifPresent(推薦)

那該怎么優(yōu)化呢?答案就是使用ifPresent方法,該方法接收一個(gè)Consumer類型的參數(shù),當(dāng)值不為null時(shí),就執(zhí)行,當(dāng)值為null時(shí),就不執(zhí)行,源碼如下所示:

public void ifPresent(Consumer<? super T> consumer) {
 if (value != null)
  consumer.accept(value);
}

優(yōu)化之后的代碼如下所示:

Optional<ImportTemplate> optionalImportTemplate = Optional.ofNullable(getImportTemplateById(1));
optionalImportTemplate.ifPresent(importTemplate -> System.out.println(importTemplate.getUrl()));

當(dāng)然,也可以寫更多的邏輯:

Optional<ImportTemplate> optionalImportTemplate = Optional.ofNullable(getImportTemplateById(1));
optionalImportTemplate.ifPresent(importTemplate -> {
 System.out.println(importTemplate.getTemplateId());
 System.out.println(importTemplate.getTemplateName());
 System.out.println(importTemplate.getUrl());
 System.out.println(importTemplate.getRemark());
});

2.6 自定義默認(rèn)值

Optional類提供了以下2個(gè)方法來自定義默認(rèn)值,用于當(dāng)對象為null時(shí),返回自定義的對象:

  • orElse
  • orElseGet

先來看下orElse方法的使用:

public static void main(String[] args) {
 ImportTemplate importTemplate = null;
 ImportTemplate firstImportTemplate = Optional.ofNullable(importTemplate)
   .orElse(getDefaultTemplate());
 System.out.println(firstImportTemplate);

 importTemplate = new ImportTemplate(2, "銷售訂單-不定規(guī)格商品導(dǎo)入模版", "o_w-a7109db89f8d4508b4c6202889a1a2c1", null);

 ImportTemplate secondImportTemplate = Optional.ofNullable(importTemplate)
   .orElse(getDefaultTemplate());
 System.out.println(secondImportTemplate);
}

public static ImportTemplate getDefaultTemplate() {
 System.out.println("getDefaultTemplate");
 return new ImportTemplate(1, "銷售訂單-普通商品導(dǎo)入模版", "o_w-140e3c1f41c94f238196539558e25bf7", null);
}

輸出結(jié)果:

再來看下orElseGet方法的使用:

public static void main(String[] args) {
 ImportTemplate importTemplate = null;
 ImportTemplate firstImportTemplate = Optional.ofNullable(importTemplate)
   .orElseGet(() -> getDefaultTemplate());
 System.out.println(firstImportTemplate);

 importTemplate = new ImportTemplate(2, "銷售訂單-不定規(guī)格商品導(dǎo)入模版", "o_w-a7109db89f8d4508b4c6202889a1a2c1", null);

 ImportTemplate secondImportTemplate = Optional.ofNullable(importTemplate)
   .orElseGet(() -> getDefaultTemplate());
 System.out.println(secondImportTemplate);
}

public static ImportTemplate getDefaultTemplate() {
 System.out.println("getDefaultTemplate");
 return new ImportTemplate(1, "銷售訂單-普通商品導(dǎo)入模版", "o_w-140e3c1f41c94f238196539558e25bf7", null);
}

輸出結(jié)果:

從輸出結(jié)果看,2個(gè)方法好像差不多,第1次調(diào)用都返回了默認(rèn)模版,第2次調(diào)用都返回了傳入的模版,但其實(shí)仔細(xì)觀察,你會發(fā)現(xiàn)當(dāng)使用

orElse方法時(shí),getDefaultTemplate方法執(zhí)行了2次,但調(diào)用orElseGet方法時(shí),getDefaultTemplate方法只執(zhí)行了2次(只在第1次傳入模版為null時(shí)執(zhí)行了)。

為什么會這樣呢?帶著這個(gè)疑問,我們看下這2個(gè)方法的源碼,其中orElse方法的源碼如下所示:

public T orElse(T other) {
 return value != null ? value : other;
}

可以看到,參數(shù)other是個(gè)對象,這個(gè)參數(shù)肯定是要傳的,但只有value為空時(shí),才會用到(返回)這個(gè)對象。

orElseGet方法的源碼如下所示:

public T orElseGet(Supplier<? extends T> other) {
 return value != null ? value : other.get();
}

可以看到,參數(shù)other并不是直接傳入對象,如果value為null,才會執(zhí)行傳入的參數(shù)獲取對象,如果不為null,直接返回value。

2.7 自定義異常

Optional類提供了orElseThrow方法,用于當(dāng)傳入的對象為null時(shí),拋出自定義的異常,使用方法如下所示:

public static void main(String[] args) {
 ImportTemplate importTemplate = new ImportTemplate(2, "銷售訂單-不定規(guī)格商品導(dǎo)入模版", "o_w-a7109db89f8d4508b4c6202889a1a2c1", null);
 ImportTemplate firstImportTemplate = Optional.ofNullable(importTemplate)
   .orElseThrow(() -> new IndexOutOfBoundsException());
 System.out.println(firstImportTemplate);

 importTemplate = null;

 ImportTemplate secondImportTemplate = Optional.ofNullable(importTemplate)
   .orElseThrow(() -> new IndexOutOfBoundsException());
 System.out.println(secondImportTemplate);
}

輸出結(jié)果:

2.8 過濾數(shù)據(jù)

Optional類提供了filter方法來過濾數(shù)據(jù),該方法接收一個(gè)Predicate參數(shù),返回匹配條件的數(shù)據(jù),如果不匹配條件,返回一個(gè)空的Optional,使用方法如下所示:

public static void main(String[] args) {
 ImportTemplate importTemplate = getImportTemplateById(1);
 Optional<ImportTemplate> filterById = Optional.ofNullable(importTemplate)
   .filter(f -> f.getTemplateId() == 1);
 System.out.println(filterById.isPresent());

 Optional<ImportTemplate> filterByName = Optional.ofNullable(importTemplate)
   .filter(f -> f.getTemplateName().contains("發(fā)貨單"));
 System.out.println(filterByName.isPresent());
}

public static ImportTemplate getImportTemplateById(int id) {
 return new ImportTemplate(1, "銷售訂單-普通商品導(dǎo)入模版", "o_w-140e3c1f41c94f238196539558e25bf7", null);
}

輸出結(jié)果:

2.9 轉(zhuǎn)換值

Optional類提供了以下2個(gè)方法來轉(zhuǎn)換值:

  • map
  • flatMap

map方法的使用方法如下所示:

public static void main(String[] args) {
 ImportTemplate importTemplate = getImportTemplateById(1);
 Optional<String> optionalUrl = Optional.ofNullable(importTemplate)
   .map(f -> "url:" + f.getUrl());
 System.out.println(optionalUrl.isPresent());
 System.out.println(optionalUrl.get());
}

public static ImportTemplate getImportTemplateById(int id) {
 return new ImportTemplate(1, "銷售訂單-普通商品導(dǎo)入模版", "o_w-140e3c1f41c94f238196539558e25bf7", null);
}

輸出結(jié)果:

flatMap方法和map方法類似,不過它支持傳入Optional,使用方法如下所示:

public static void main(String[] args) {
 ImportTemplate importTemplate = getImportTemplateById(1);
 Optional<String> optionalUrl = Optional.ofNullable(importTemplate)
   .flatMap(f -> Optional.ofNullable(f.getUrl()));
 System.out.println(optionalUrl.isPresent());
 System.out.println(optionalUrl.get());
}

public static ImportTemplate getImportTemplateById(int id) {
 return new ImportTemplate(1, "銷售訂單-普通商品導(dǎo)入模版", "o_w-140e3c1f41c94f238196539558e25bf7", null);
}

輸出結(jié)果:

3. 總結(jié)

對于程序員來說,一不注意就會出現(xiàn)NullPointerException異常,避免它的方式也很簡單,比如使用前判斷不能為空:

public static void main(String[] args) {
 ImportTemplate importTemplate = getImportTemplateById(1);
 if (importTemplate != null) {
  System.out.println(importTemplate.getUrl());
 }
}

比如為空時(shí),直接返回(或者返回默認(rèn)值):

public static void main(String[] args) {
 ImportTemplate importTemplate = getImportTemplateById(1);
 if (importTemplate == null) {
  return;
 }
 System.out.println(importTemplate.getUrl());
}

比如,使用本文中的Optional。

使用哪種方式不重要,盡可能地避免NullPointerException異常才重要。

4. 參考

理解、學(xué)習(xí)與使用 Java 中的 Optional

總結(jié)

到此這篇關(guān)于Java中Optional使用的文章就介紹到這了,更多相關(guān)Java Optional使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java中將科學(xué)計(jì)數(shù)法轉(zhuǎn)換普通計(jì)數(shù)法的簡單方法

    java中將科學(xué)計(jì)數(shù)法轉(zhuǎn)換普通計(jì)數(shù)法的簡單方法

    下面小編就為大家?guī)硪黄猨ava中將科學(xué)計(jì)數(shù)法轉(zhuǎn)換普通計(jì)數(shù)法的簡單方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2016-12-12
  • Java中對List集合的常用操作詳解

    Java中對List集合的常用操作詳解

    下面小編就為大家?guī)硪黄狫ava中對List集合的常用操作詳解。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2016-07-07
  • springboot實(shí)現(xiàn)分頁功能的完整代碼

    springboot實(shí)現(xiàn)分頁功能的完整代碼

    Spring Boot是一個(gè)快速開發(fā)框架,它提供了很多便捷的功能,其中包括分頁查詢,下面這篇文章主要給大家介紹了關(guān)于springboot實(shí)現(xiàn)分頁功能的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-04-04
  • 解決eclipse上傳svn忽略target文件夾的坑

    解決eclipse上傳svn忽略target文件夾的坑

    這篇文章主要介紹了解決eclipse上傳svn忽略target文件夾的坑,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • 關(guān)于break和continue以及l(fā)abel的區(qū)別和作用(詳解)

    關(guān)于break和continue以及l(fā)abel的區(qū)別和作用(詳解)

    下面小編就為大家?guī)硪黄P(guān)于break和continue以及l(fā)abel的區(qū)別和作用(詳解)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-05-05
  • springboot 按月分表的實(shí)現(xiàn)方式

    springboot 按月分表的實(shí)現(xiàn)方式

    本文主要介紹了springboot 按月分表的實(shí)現(xiàn)方式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • mybatis之批量添加問題

    mybatis之批量添加問題

    這篇文章主要介紹了mybatis之批量添加問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • Java中使用Filter過濾器的方法

    Java中使用Filter過濾器的方法

    Filter過濾器是javaWeb層面的,它跟Servlet類似,每次前端請求,首先進(jìn)入的是過濾器,我們必須實(shí)現(xiàn)Filter接口,重寫三個(gè)方法,才能使用Filter過濾器,需要的朋友可以參考下
    2021-06-06
  • 詳解Java如何實(shí)現(xiàn)加密或者解密PDF文檔

    詳解Java如何實(shí)現(xiàn)加密或者解密PDF文檔

    PDF文檔加密是一種用于保護(hù)文件內(nèi)容的功能。這篇文章主要介紹了Java實(shí)現(xiàn)加密或者解密PDF文檔的方法,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-03-03
  • 升級springboot3之自動配置導(dǎo)入失效問題及解決

    升級springboot3之自動配置導(dǎo)入失效問題及解決

    這篇文章主要介紹了升級springboot3之自動配置導(dǎo)入失效問題及解決,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07

最新評論