色综合图-色综合图片-色综合图片二区150p-色综合图区-玖玖国产精品视频-玖玖香蕉视频

您的位置:首頁技術(shù)文章
文章詳情頁

Java中Optional的使用指南

瀏覽:17日期:2022-08-17 13:55:11

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

1. 簡單回顧

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

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

package com.zwwhnly.springbootaction.model;import lombok.AllArgsConstructor;import lombok.Data;/** * 導(dǎo)入模版 */@Data@AllArgsConstructorpublic 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時,這段代碼就會拋出NullPointerException異常,如下所示:

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

Java中Optional的使用指南

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

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

項目中類似的判空代碼應(yī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時,調(diào)用of方法會拋NullPointerException異常,但調(diào)用ofNullable方法不會(更符合使用場景),因此推薦使用ofNullable方法:

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

Java中Optional的使用指南

2.2 判斷是否有值

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

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

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

Java中Optional的使用指南

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

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

Java中Optional的使用指南

看下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é)果為:

Java中Optional的使用指南

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

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

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

Java中Optional的使用指南

看下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方法,該方法接收一個Consumer類型的參數(shù),當(dāng)值不為null時,就執(zhí)行,當(dāng)值為null時,就不執(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個方法來自定義默認(rèn)值,用于當(dāng)對象為null時,返回自定義的對象:

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é)果:

Java中Optional的使用指南

再來看下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é)果:

Java中Optional的使用指南

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

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

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

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

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

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時,拋出自定義的異常,使用方法如下所示:

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é)果:

Java中Optional的使用指南

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

Optional類提供了filter方法來過濾數(shù)據(jù),該方法接收一個Predicate參數(shù),返回匹配條件的數(shù)據(jù),如果不匹配條件,返回一個空的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é)果:

Java中Optional的使用指南

2.9 轉(zhuǎn)換值

Optional類提供了以下2個方法來轉(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é)果:

Java中Optional的使用指南

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é)果:

Java中Optional的使用指南

3. 總結(jié)

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

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

比如為空時,直接返回(或者返回默認(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)容請搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 美女131爽爽爽做爰中文视频 | 男女性高爱潮免费网站 | www片| 国产精品久久久一区二区三区 | 亚洲综合色dddd26 | 国产精品a人片在线观看 | 特级毛片aaaa免费观看 | 亚洲精品99久久一区二区三区 | 欧美一区二区在线观看视频 | 日韩一区二区不卡中文字幕 | 九色视频在线观看免费 | 在线免费公开视频 | 图片区偷拍区小说区 | 国产成人在线视频播放 | 久青草视频在线 | 久久久久久久岛国免费观看 | 视频二区在线 | 国产精品成久久久久三级 | 成 人 黄 色 视频 免费观看 | 国产a精品三级 | 人与拘一级a毛片 | 你懂的国产精品 | 日韩一级免费视频 | 成年男女拍拍拍免费视频 | aa级毛片毛片免费观看久 | 国产三级做爰在线观看 | 香港a毛片免费全部播放 | 久热精品男人的天堂在线视频 | 成人自拍视频 | 久久国产成人福利播放 | 色偷偷88欧美精品久久久 | 欧美6699在线视频免费 | 成年人国产视频 | 亚洲综合干 | 亚洲在线免费观看视频 | 中文在线日韩 | a毛片全部播放免费视频完整18 | 97国产在线播放 | 国产大片线上免费观看 | 99久久精品免费看国产一区二区 | 狠狠色狠狠色综合久久一 |