主頁 > 企業開發 > Optional原始碼決議與實踐

Optional原始碼決議與實踐

2022-09-29 12:01:30 企業開發

1 導讀

NullPointerException在開發程序中經常遇到,稍有不慎小BUG就出現了,如果避免這個問題呢,Optional就是專門解決這個問題的類,那么Optional如何使用呢?讓我們一起探索一下吧!

2 原始碼決議

2.1 Optional定義

Optional類是Java8為了解決null值判斷問題而創建的容器類,在java.util 下,使用Optional類可以避免顯式的null值判斷,避免null導致的NullPointerException,首先,Optional是一個容器,它可以保存型別T的值,也可以為null的容器物件,Optional容器只能存一個值,

2.2 Optional的屬性

1)原始碼:
  1. /**
  2. * Common instance for {@code empty()}.
  3. */
  4. private static final Optional<?> EMPTY = new Optional<>();
  5. /**
  6. * If non-null, the value; if null, indicates no value is present
  7. */
  8. private final T value;

根據原始碼可以看到Optional有兩個屬性,一個是為空值準備的EMPTY和泛型值value;

2.3 Optional的方法

Optional除toString()、hashCode() 、equals()等Object的方法外,還包含以下方法,

2.3.1 私有構造方法
  1. /**
  2. * Constructs an empty instance.
  3. *
  4. * @implNote Generally only one empty instance, {@link Optional#EMPTY},
  5. * should exist per VM.
  6. */
  7. private Optional() {
  8. this.value = null;
  9. }
  10. /**
  11. * Constructs an instance with the value present.
  12. *
  13. * @param value the non-null value to be present
  14. * @throws NullPointerException if value is null
  15. */
  16. private Optional(T value) {
  17. this.value = Objects.requireNonNull(value);
  18. }

分別是創建一個空實體和構造一個具有當前值的實體,

2.3.2 創建方法
1)原始碼
  1. public static<T> Optional<T> empty() {
  2. @SuppressWarnings("unchecked")
  3. Optional<T> t = (Optional<T>) EMPTY;
  4. return t;
  5. }
  6. public static <T> Optional<T> of(T value) {
  7. return new Optional<>(value);
  8. }
  9. public static <T> Optional<T> ofNullable(T value) {
  10. return value == null ? empty() : of(value);
  11. }
2)方法說明
  • empty(): 創建一個空的 Optional 實體
  • of(T t) : 創建一個 Optional 實體,當 t為null時拋出例外
  • ofNullable(T t): 創建一個 Optional 實體,但當 t為null時不會拋出例外,而是回傳一個空的實體

3)測驗代碼

  1. public static void main(String[] args) {
  2. Integer value1 = null;
  3. Integer value2 = 1;
  4. try {
  5. Optional<Integer> optional1 = Optional.empty();
  6. System.out.println("optional1創建了");
  7. }catch (Exception e){
  8. System.out.println("optional1失敗了");
  9. }
  10. try {
  11. Optional<Integer> optional2 = Optional.of(value1);
  12. System.out.println("optional2創建了");
  13. }catch (Exception e){
  14. System.out.println("optional2失敗了");
  15. }
  16. try {
  17. Optional<Integer> optional3 = Optional.ofNullable(value1);
  18. System.out.println("optional3創建了");
  19. }catch (Exception e){
  20. System.out.println("optional3失敗了");
  21. }
  22. try {
  23. Optional<Integer> optional4 = Optional.of(value2);
  24. System.out.println("optional4創建了");
  25. }catch (Exception e){
  26. System.out.println("optional4失敗了");
  27. }
  28. try {
  29. Optional<Integer> optional5 = Optional.ofNullable(value2);
  30. System.out.println("optional5創建了");
  31. }catch (Exception e){
  32. System.out.println("optional5失敗了");
  33. }
  34. }

4)運行結果

2.3.3 值獲取方法
1)原始碼
  1. public T get() {
  2. if (value == null) {
  3. throw new NoSuchElementException("No value present");
  4. }
  5. return value;
  6. }
2)方法說明

get(): 如果Optional不為空,則回傳該Optional容器中的值,否則拋出NoSuchElementExceptio ,

3)測驗代碼
  1. public static void main(String[] args) {
  2. Integer value1 = null;
  3. Integer value2 = 1;
  4. Optional<Integer> optional1 = Optional.ofNullable(value1);
  5. Optional<Integer> optional2 = Optional.of(value2);
  6. try {
  7. Integer result=optional1.get();
  8. System.out.println("optional1的值是:"+result);
  9. }catch (Exception e){
  10. System.out.println("optional1的值獲取失敗,原因:"+e.getMessage());
  11. }
  12. try {
  13. Integer result=optional2.get();
  14. System.out.println("optional2的值是:"+result);
  15. }catch (Exception e){
  16. System.out.println("optional2的值獲取失敗,原因:"+e.getMessage());
  17. }
  18. }
4)運行結果

2.3.4 判斷方法
1)原始碼
  1. public boolean isPresent() {
  2. return value != null;
  3. }
  4. public void ifPresent(Consumer<? super T> consumer) {
  5. if (value != null)
  6. consumer.accept(value);
  7. }
  8. public T orElse(T other) {
  9. return value != null ? value : other;
  10. }
  11. public T orElseGet(Supplier<? extends T> other) {
  12. return value != null ? value : other.get();
  13. }
  14. public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
  15. if (value != null) {
  16. return value;
  17. } else {
  18. throw exceptionSupplier.get();
  19. }
  20. }
2)方法說明
  • isPresent(): 判斷optional是否為空,如果空則回傳false,否則回傳true
  • ifPresent(Consumer c): 如果optional不為空,則將optional中的物件傳給Comsumer函式
  • orElse(T other): 如果optional不為空,則回傳optional中的物件;如果為null,則回傳 other 這個物件,
  • orElseGet(Supplier other): 如果optional不為空,則回傳optional中的物件;如果為null,否則呼叫其他函式并回傳呼叫的結果
  • orElseThrow(Supplier exception): 如果optional不為空,則回傳optional中的物件;如果為null,則拋出Supplier函式生成的例外
3)測驗代碼
  1. public static void main(String[] args) {
  2. Integer value1 = null;
  3. Integer value2 = 1;
  4. Optional<Integer> optional1 = Optional.ofNullable(value1);
  5. Optional<Integer> optional2 = Optional.of(value2);
  6. try {
  7. if(optional1.isPresent()){
  8. System.out.println("optional1的isPresent結果不為空");
  9. }else{
  10. System.out.println("optional1的isPresent結果為空");
  11. }
  12. }catch (Exception e){
  13. System.out.println("optional1的isPresent判空失敗,原因:"+e.getMessage());
  14. }
  15. try {
  16. if(optional2.isPresent()){
  17. System.out.println("optional2的isPresent結果不為空");
  18. }else{
  19. System.out.println("optional2的isPresent結果為空");
  20. }
  21. }catch (Exception e){
  22. System.out.println("optional2的isPresent判空失敗,原因:"+e.getMessage());
  23. }
  24. optional1.ifPresent(t->{
  25. int i =t+1;
  26. System.out.println("optional1處理后的值是"+i);
  27. });
  28. optional2.ifPresent(t->{
  29. int i =t+1;
  30. System.out.println("optional2處理后的值是"+i);});
  31. Integer value3 = 2;
  32. Integer result = optional1.orElse(value3);
  33. System.out.println("optional1執行orElse處理后的值是"+result);
  34. result = optional2.orElse(value3);
  35. System.out.println("optional2執行orElse處理后的值是"+result);
  36. result = optional1.orElseGet(()-> new Integer(-1));
  37. System.out.println("optional1執行orElseGet處理后的值是"+result);
  38. result = optional2.orElseGet(()-> new Integer(-1));
  39. System.out.println("optional2執行orElseGet處理后的值是"+result);
  40. try {
  41. result = optional1.orElseThrow (()-> new RuntimeException("值是空的"));
  42. System.out.println("optional1執行orElseThrow處理后的值是"+result);
  43. }catch (Exception e){
  44. System.out.println("optional1的orElseThrow拋出例外:"+e.getMessage());
  45. }
  46. try {
  47. result = optional2.orElseThrow (()-> new RuntimeException("值是空的"));
  48. System.out.println("optional2執行orElseThrow處理后的值是"+result);
  49. }catch (Exception e){
  50. System.out.println("optional2的orElseThrow拋出例外:"+e.getMessage());
4)運行結果

2.3.5 過濾方法
1)原始碼
  1. public Optional<T> filter(Predicate<? super T> predicate) {
  2. Objects.requireNonNull(predicate);
  3. if (!isPresent())
  4. return this;
  5. else
  6. return predicate.test(value) ? this : empty();
  7. }
2)方法說明

filter(Predicate p): 如果optional不為空,則執行Predicate p,如果p的結果為true,則回傳原本的optional,否則回傳空的optional

3)測驗代碼
  1. public static void main(String[] args) {
  2. Integer value1 = 5;
  3. Integer value2 = 6;
  4. Optional<Integer> optional1 = Optional.ofNullable(value1);
  5. Optional<Integer> optional2 = Optional.of(value2);
  6. Optional<Integer> result =optional1.filter(t->t > 5);
  7. System.out.println("optional1的filter后的值:"+result);
  8. result =optional2.filter(t->t > 5);
  9. System.out.println("optional2的filter后的值:"+result);
4)運行結果

2.3.6 映射方法
1)原始碼
  1. public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
  2. Objects.requireNonNull(mapper);
  3. if (!isPresent())
  4. return empty();
  5. else {
  6. return Optional.ofNullable(mapper.apply(value));
  7. }
  8. }
  9. public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
  10. Objects.requireNonNull(mapper);
  11. if (!isPresent())
  12. return empty();
  13. else {
  14. return Objects.requireNonNull(mapper.apply(value));
  15. }
  16. }
2)方法說明
  • map(Function<t, u=""> mapper): 如果存在一個值,則對其應用提供的映射函式,如果結果非空,則回傳描述結果的Optional, 否則回傳一個空的Optional,
  • flatMap(Function< T,Optional> mapper): 如果有值,則對其應用提供的可選映射函式,回傳結果,否則回傳空的可選函式, 這個方法類似于map(Function),但是提供的映射器的結果已經是一個可選的,如果呼叫,flatMap不會用額外的可選的包裝它,
  • 區別:map會自動將u放到optional中,而flatMap則需要手動給u創建一個optional
3)測驗代碼
  1. public static void main(String[] args) {
  2. User user1 = null;
  3. User user2 = new User("user2名字",19);
  4. Optional<User> optional1 = Optional.ofNullable(user1);
  5. Optional<User> optional2 = Optional.of(user2);
  6. System.out.println("=========map==========");
  7. System.out.println("optional1的map前的值:"+optional1);
  8. Optional<String> result =optional1.map(t->t.getName());
  9. System.out.println("optional1的map后的值:"+result);
  10. System.out.println("optional2的map前的值:"+optional2);
  11. result =optional2.map(t->t.getName());
  12. System.out.println("optional2的map后的值:"+result);
  13. System.out.println("===========flatMap========");
  14. System.out.println("optional1的flatMap前的值:"+optional1);
  15. Optional<Integer> result2 =optional1.flatMap(t->Optional.ofNullable(t.getAge()));
  16. System.out.println("optional1的flatMap后的值:"+result2);
  17. System.out.println("optional2的flatMap前的值:"+optional2);
  18. result2 =optional2.flatMap(t->Optional.ofNullable(t.getAge()));
  19. System.out.println("optional2的flatMap后的值:"+result2);
  20. }
  21. public class User {
  22. String name;
  23. Integer age;
  24. public User(String name,Integer age){
  25. this.name = name;
  26. this.age=age;
  27. }
  28. public String getName() {
  29. return name;
  30. }
  31. public Integer getAge() {
  32. return age;
4)運行結果

3 應用實體

3.1 錯誤用法

  • 由于Optional并沒有實作Serializable介面,所以不能作為類的屬性,
  • 不要把Optional作為方法的引數,
  • 把if(x!=null)直接換成Optional.ofNullable(x).isPresent(),這樣有過度編碼的嫌疑,
  • 直接使用Optional.get()的回傳值進行操作,String result =Optional.ofNullable(null).get().toString();這樣還是會拋出例外的,

3.2 建議用法

A類有屬性B類,B類有屬性C類,C類有name這個欄位,
使用Optional之前:

  1. if(atest!=null){
  2. Btest btest =atest.getBtest();
  3. if(btest!=null){
  4. Ctest ctest = btest.getCtest();
  5. if (ctest != null) {
  6. name =ctest.getName();
  7. }
  8. }
  9. }

使用Optional之后:

  1. name = Optional.ofNullable(atest).map(t->t.getBtest()).map(t->t.getCtest()).map(t->t.getName()).orElse("默認值");

代碼是不是看上去更整潔了呢?

4 總結

通過對Optional原始碼決議和用例測驗代碼的運行結果,可以看出使用Optional可以優化null值判斷代碼,讓代碼變得更加優雅和整潔,


自猿其說Tech-JDL京東物流技術與資料智能部
作者:陳昌浩

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/509818.html

標籤:其他

上一篇:mapboxgl加載tiff

下一篇:JSON APIs and Ajax

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • IEEE1588PTP在數字化變電站時鐘同步方面的應用

    IEEE1588ptp在數字化變電站時鐘同步方面的應用 京準電子科技官微——ahjzsz 一、電力系統時間同步基本概況 隨著對IEC 61850標準研究的不斷深入,國內外學者提出基于IEC61850通信標準體系建設數字化變電站的發展思路。數字化變電站與常規變電站的顯著區別在于程序層傳統的電流/電壓互 ......

    uj5u.com 2020-09-10 03:51:52 more
  • HTTP request smuggling CL.TE

    CL.TE 簡介 前端通過Content-Length處理請求,通過反向代理或者負載均衡將請求轉發到后端,后端Transfer-Encoding優先級較高,以TE處理請求造成安全問題。 檢測 發送如下資料包 POST / HTTP/1.1 Host: ac391f7e1e9af821806e890 ......

    uj5u.com 2020-09-10 03:52:11 more
  • 網路滲透資料大全單——漏洞庫篇

    網路滲透資料大全單——漏洞庫篇漏洞庫 NVD ——美國國家漏洞庫 →http://nvd.nist.gov/。 CERT ——美國國家應急回應中心 →https://www.us-cert.gov/ OSVDB ——開源漏洞庫 →http://osvdb.org Bugtraq ——賽門鐵克 →ht ......

    uj5u.com 2020-09-10 03:52:15 more
  • 京準講述NTP時鐘服務器應用及原理

    京準講述NTP時鐘服務器應用及原理京準講述NTP時鐘服務器應用及原理 安徽京準電子科技官微——ahjzsz 北斗授時原理 授時是指接識訓通過某種方式獲得本地時間與北斗標準時間的鐘差,然后調整本地時鐘使時差控制在一定的精度范圍內。 衛星導航系統通常由三部分組成:導航授時衛星、地面檢測校正維護系統和用戶 ......

    uj5u.com 2020-09-10 03:52:25 more
  • 利用北斗衛星系統設計NTP網路時間服務器

    利用北斗衛星系統設計NTP網路時間服務器 利用北斗衛星系統設計NTP網路時間服務器 安徽京準電子科技官微——ahjzsz 概述 NTP網路時間服務器是一款支持NTP和SNTP網路時間同步協議,高精度、大容量、高品質的高科技時鐘產品。 NTP網路時間服務器設備采用冗余架構設計,高精度時鐘直接來源于北斗 ......

    uj5u.com 2020-09-10 03:52:35 more
  • 詳細解讀電力系統各種對時方式

    詳細解讀電力系統各種對時方式 詳細解讀電力系統各種對時方式 安徽京準電子科技官微——ahjzsz,更多資料請添加VX 衛星同步時鐘是我京準公司開發研制的應用衛星授時時技術的標準時間顯示和發送的裝置,該裝置以M國全球定位系統(GLOBAL POSITIONING SYSTEM,縮寫為GPS)或者我國北 ......

    uj5u.com 2020-09-10 03:52:45 more
  • 如何保證外包團隊接入企業內網安全

    不管企業規模的大小,只要企業想省錢,那么企業的某些服務就一定會采用外包的形式,然而看似美好又經濟的策略,其實也有不好的一面。下面我通過安全的角度來聊聊使用外包團的安全隱患問題。 先看看什么服務會使用外包的,最常見的就是話務/客服這種需要大量重復性、無技術性的服務,或者是一些銷售外包、特殊的職能外包等 ......

    uj5u.com 2020-09-10 03:52:57 more
  • PHP漏洞之【整型數字型SQL注入】

    0x01 什么是SQL注入 SQL是一種注入攻擊,通過前端帶入后端資料庫進行惡意的SQL陳述句查詢。 0x02 SQL整型注入原理 SQL注入一般發生在動態網站URL地址里,當然也會發生在其它地發,如登錄框等等也會存在注入,只要是和資料庫打交道的地方都有可能存在。 如這里http://192.168. ......

    uj5u.com 2020-09-10 03:55:40 more
  • [GXYCTF2019]禁止套娃

    git泄露獲取原始碼 使用GET傳參,引數為exp 經過三層過濾執行 第一層過濾偽協議,第二層過濾帶引數的函式,第三層過濾一些函式 preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'] (?R)參考當前正則運算式,相當于匹配函式里的引數 因此傳遞 ......

    uj5u.com 2020-09-10 03:56:07 more
  • 等保2.0實施流程

    流程 結論 ......

    uj5u.com 2020-09-10 03:56:16 more
最新发布
  • 使用Django Rest framework搭建Blog

    在前面的Blog例子中我們使用的是GraphQL, 雖然GraphQL的使用處于上升趨勢,但是Rest API還是使用的更廣泛一些. 所以還是決定回到傳統的rest api framework上來, Django rest framework的官網上給了一個很好用的QuickStart, 我參考Qu ......

    uj5u.com 2023-04-20 08:17:54 more
  • 記錄-new Date() 我忍你很久了!

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 大家平時在開發的時候有沒被new Date()折磨過?就是它的諸多怪異的設定讓你每每用的時候,都可能不小心踩坑。造成程式意外出錯,卻一下子找不到問題出處,那叫一個煩透了…… 下面,我就列舉它的“四宗罪”及應用思考 可惡的四宗罪 1. Sa ......

    uj5u.com 2023-04-20 08:17:47 more
  • 使用Vue.js實作文字跑馬燈效果

    實作文字跑馬燈效果,首先用到 substring()截取 和 setInterval計時器 clearInterval()清除計時器 效果如下: 實作代碼如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta ......

    uj5u.com 2023-04-20 08:12:31 more
  • JavaScript 運算子

    JavaScript 運算子/運算子 在 JavaScript 中,有一些運算子可以使代碼更簡潔、易讀和高效。以下是一些常見的運算子: 1、可選鏈運算子(optional chaining operator) ?.是可選鏈運算子(optional chaining operator)。?. 可選鏈操 ......

    uj5u.com 2023-04-20 08:02:25 more
  • CSS—相對單位rem

    一、概述 rem是一個相對長度單位,它的單位長度取決于根標簽html的字體尺寸。rem即root em的意思,中文翻譯為根em。瀏覽器的文本尺寸一般默認為16px,即默認情況下: 1rem = 16px rem布局原理:根據CSS媒體查詢功能,更改根標簽的字體尺寸,實作rem單位隨螢屏尺寸的變化,如 ......

    uj5u.com 2023-04-20 08:02:21 more
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 08:01:50 more
  • 如何在 vue3 中使用 jsx/tsx?

    我們都知道,通常情況下我們使用 vue 大多都是用的 SFC(Signle File Component)單檔案組件模式,即一個組件就是一個檔案,但其實 Vue 也是支持使用 JSX 來撰寫組件的。這里不討論 SFC 和 JSX 的好壞,這個仁者見仁智者見智。本篇文章旨在帶領大家快速了解和使用 Vu ......

    uj5u.com 2023-04-20 08:01:37 more
  • 【Vue2.x原始碼系列06】計算屬性computed原理

    本章目標:計算屬性是如何實作的?計算屬性快取原理以及洋蔥模型的應用?在初始化Vue實體時,我們會給每個計算屬性都創建一個對應watcher,我們稱之為計算屬性watcher ......

    uj5u.com 2023-04-20 08:01:31 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:01:10 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:00:32 more