iT邦幫忙

2024 iThome 鐵人賽

DAY 5
0

Java的學習初期,我曾經無法理解人稱 Java 8 三大神器之一的stream()魅力,覺得用迴圈與if判斷的寫法才是最好用的,但隨著開發的熟悉度上升,這些寫法也逐漸融入我日常開發的方法,這次就來看一些Java的 Functional API吧。本次以Optional為主進行介紹。

在Java的世界中,NullPointerException一直是開發者痛恨的狀況,主要原因有二:

  1. NullPointerException沒有意義,即使知道程式碼中的哪一行爆出NullPointerException,這件事本身很多時候是對解決問題沒有幫助的。因為導致NullPointerException的原因通常都在那之前。
  2. null無法與其他資料結構並存,null與空物件不一樣,使得開發者為了預防不知道何時會冒出的NullPointerExcpetion,必須經常寫 if (xxx ! = null) 。

這時可以考慮使用的工具是Java Optional,他可以幫助開發者解決惱人的NPE問題。基本的使用方法如下:


Optional<Student> student = Optional.of(studentService.findByName(name));
Optional<Student> studentNullable = Optional.ofNullable(studentService.findByName(name));

if (studentNullable.isPresent()) {
    Student s = studentNullable.get();
}

前兩行的功能是建構一個Optional物件,主要的差別是 Optional.of() 不接受內容為Null物件,如果內容為Null會直接爆出NullPointerException,這麼做的好處是避免造成一個Null到處傳遞,最後在一個你想都想不到的地方跑出NPE。

Optional.ofNullable()則是一個可接受Null的物件。第三行則是判斷是否為Null,第四行判斷如果不是Null的話就取值。

在這邊先提醒一下,isPresent()用來判斷的只是Null,並不像其他isEmpty()之類的,可以判斷空物件、空字串之類的,isPresent()就只是拿來處理Null。

我知道你應該是這麼想的:如果Optional只能拿來判斷Null,我還不如直接寫 ≠ null,裡面還可以做更多事,要取得內容還得先呼叫.get(),真的很麻煩。

我知道你已經想轉台了。但請先等等,我一開始也是這麼覺得的,但後來我發覺Optional的功能其實沒有那麼糟。看看Optional是怎麼處理例外的吧。

Student studentNullable = Optional.ofNullable(studentService.findByName(name))
											.orElse(new Student());
Student studentNullable2 = Optional.ofNullable(st)
											.orElseGet( () -> new Student(0,"Admin",0));
Student studentNullable3 = Optional.ofNullable(studentNullable)
											.orElseThrow(() -> new IllegalArgumentException("Student not exist"));

以下展現了三種Student物件處理Null的方法,Optional允許我們只要在一個鏈狀結構中處理Null就可以不必包Optional,省去了.get()的方法。

第一行是用來判斷內容是否為Null,若是Null則回傳一個空的新物件。

第二行與第一行類似,只是第二行使用了Java 的Lambda語法去建立一個新物件並回傳到studentNullable2

第三行則是最常用的,只要為Null當下就拋出NPE,完全零容忍,像是這邊就拋出一個自定義的例外,告訴我們說該Student不存在。

還覺得不夠嗎?那是時候來介紹另外一個API - stream()了。

stream()是Java工程師用來處理複雜邏輯處理的一個工具,Optional的另一個大優勢就是可以接上它,因此你可以寫出更多的功能,比方說以下例子。

Optional.ofNullable(st1)
        .filter(student -> student.getAge()> 18)
        .filter(student -> student.getName().equals("Joe"))
        .isPresent(); // 過濾資料是否符合18以上 名字叫做Joe的人
Family motherName = Optional.ofNullable(st2)
        .map(s -> s.getFamily())
        .filter( f -> f.getMotherName().equals("Mary"))
    .orElseThrow(() -> new IllegalObjectStatusException("NotFound")); 
// 找出學生家庭的母親姓名,如果是Mary就回傳Family 否則跳出例外
        

另外值得一提的是,在第二個例子中假設Family類別為null時,也不會回報NPE,則是遵循撰寫的Optional語法執行orElseThrow()拋出自定義例外。

以上就是Optional與Stream的小小分享,明天見了。

參考資料:

https://openhome.cc/zh-tw/java/functional-api/stream/


上一篇
[DAY 4] Java 的清潔隊員(GC)
下一篇
[Day 6] 快速建好一個SpringBoot專案
系列文
週日時在做什麼?有沒有空?可以來寫SpringBoot嗎?15
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言