【超全指南】Java 8 中使用 Optional 處理 null 對(duì)象
作者:超級(jí)小豆丁
http://www.mydlq.club/article/88/
系統(tǒng)環(huán)境:
Java JDK 版本:1.8
參考地址:
Oracle JDK API 參考文檔
https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html
菜鳥教程-Java 8 Optional 類
https://www.runoob.com/java/java8-optional-class.html
一、Optional 簡(jiǎn)介
Optional 是一個(gè)容器對(duì)象,可以存儲(chǔ)對(duì)象、字符串等值,當(dāng)然也可以存儲(chǔ) null 值。Optional 提供很多有用的方法,能幫助我們將 Java 中的對(duì)象等一些值存入其中,這樣我們就不用顯式進(jìn)行空值檢測(cè),使我們能夠用少量的代碼完成復(fù)雜的流程。
比如它提供了:
of() 方法,可以將值存入 Optional 容器中,如果存入的值是 null 則拋異常。
ofNullable() 方法,可以將值存入 Optional 容器中,即使值是 null 也不會(huì)拋異常。
get() 方法,可以獲取容器中的值,如果值為 null 則拋出異常。
getElse() 方法,可以獲取容器中的值,如果值為 null 則返回設(shè)置的默認(rèn)值。
isPresent() 方法,該方法可以判斷存入的值是否為空。
…等等一些其它常用方法,下面會(huì)進(jìn)行介紹。
可以說(shuō),使用 Optional 可以幫助我們解決業(yè)務(wù)中,減少值動(dòng)不動(dòng)就拋出空指針異常問(wèn)題,也減少 null 值的判斷,提高代碼可讀性等,這里我們介紹下,如果使用這個(gè) Optional 類。

二、Optional 類描述
Optional 類所在包:?java.util.Optional
Optional 類聲明:?public final class Optional extends Object
Optional 類方法: public Optional?filter(Predicate super T> predicate)

三、Optional 常用方法及使用示例
1、靜態(tài)方法 Optional.of()
方法作用:?為指定的值創(chuàng)建一個(gè)指定非 null 值的 Optional。
方法描述:?of 方法通過(guò)工廠方法創(chuàng)建 Optional 實(shí)例,需要注意的是傳入的參數(shù)不能為 null,否則拋出 NullPointerException。
返回類型:?Optional
示例代碼:
調(diào)用兩個(gè) Optional.of() 方法,一個(gè)傳入正常參數(shù),另一個(gè)傳入 null 參數(shù):
public?static?void?main(String[]?args)?{
????//?傳入正常值,正常返回一個(gè)?Optional?對(duì)象
????Optional?optional1?=?Optional.of("mydlq");
????
????//?傳入?yún)?shù)為?null,拋出?NullPointerException.
????Optional?optional2?=?Optional.of(null);
}
運(yùn)行代碼,可以觀察到控制臺(tái)輸出內(nèi)容如下:
Exception?in?thread?"main"?java.lang.NullPointerException
????at?java.util.Objects.requireNonNull(Objects.java:203)
????at?java.util.Optional.(Optional.java:96)
????at?java.util.Optional.of(Optional.java:108)
????at?club.mydlq.OptionalExample.main(OptionalExample.java:12)
可以看到傳入正常參數(shù)正常返回 Optional 對(duì)象,傳入 null 參數(shù)返回 NullPointerException 異常。
2、靜態(tài)方法 Optional.ofNullable()
方法作用:?為指定的值創(chuàng)建一個(gè) Optional 對(duì)象,如果指定的參數(shù)為 null,不拋出異常,直接則返回一個(gè)空的 Optional 對(duì)象。
方法描述:?ofNullable 方法是和 of 方式一樣,都是用于創(chuàng)建 Optional 對(duì)象,只是傳入的參數(shù) null 時(shí),會(huì)返回一個(gè)空的 Optional 對(duì)象,而不會(huì)拋出 NullPointerException 異常。
返回類型:?Optional
示例代碼:
調(diào)用 Optional.ofNullable() 方法,傳入 null 參數(shù):
public?static?void?main(String[]?args)?{
????//?傳入正常值,正常返回一個(gè)?Optional?對(duì)象
????Optional?optional1?=?Optional.ofNullable("mydlq");
????
????//?傳入?null?參數(shù),正常返回?Optional?對(duì)象
????Optional?optional2?=?Optional.ofNullable(null);
}
運(yùn)行代碼,可以觀察到正常傳入值和傳入 null 值時(shí),都沒有拋出異常。
3、對(duì)象方法 isPresent()
方法作用:?如果值存在則方法會(huì)返回 true,否則返回 false。
方法描述:?該方法其實(shí)就是用于判斷創(chuàng)建 Optional 時(shí)傳入?yún)?shù)的值是否為空,實(shí)現(xiàn)代碼就簡(jiǎn)單一行,即?
value != null?所以如果不為空則返回 true,否則返回 false。返回類型:?boolean
示例代碼:
public?static?void?main(String[]?args)?{
????//?傳入正常值,正常返回一個(gè)?Optional?對(duì)象,并使用?isPresent?方法
????Optional?optional1?=?Optional.ofNullable("mydlq");
????System.out.println("傳入正常值返回:"?+?optional1.isPresent());
????//?傳入?yún)?shù)為?null?生成一個(gè)?Optional?對(duì)象,并使用?isPresent?方法
????Optional?optional2?=?Optional.ofNullable(null);
????System.out.println("傳入 null 值返回:"?+?optional2.isPresent());
}
運(yùn)行代碼,可以觀察到控制臺(tái)輸出內(nèi)容如下:
傳入正常值返回:true
傳入 null 值返回:false
可以看到傳入正常參數(shù)時(shí)調(diào)用 Optional 對(duì)象的 isPresent 方法時(shí)返回 true,傳入 null 參數(shù)返回 false。
4、對(duì)象方法 get()
方法作用:?如果 Optional 有值則將其返回,否則拋出 NoSuchElementException 異常。
方法描述:?get 方法內(nèi)部實(shí)現(xiàn)其實(shí)就是判斷 Otpional 對(duì)象中的 value 屬性是否為 null,如果是就拋出 NoSuchElementException 異常,否則返回這個(gè) value 值。
返回類型:?T
示例代碼:
public?static?void?main(String[]?args)?{
????//?傳入正常值,正常返回一個(gè)?Optional?對(duì)象,并使用?get?方法獲取值
????Optional?optional1?=?Optional.ofNullable("mydlq");
????System.out.println(optional1.get());
????//?傳入?yún)?shù)為?null?生成一個(gè)?Optional?對(duì)象,并使用?get?方法獲取值
????Optional?optional2?=?Optional.ofNullable(null);
????System.out.println(optional2.get());
}
運(yùn)行代碼,可以觀察到控制臺(tái)輸出內(nèi)容如下:
傳入正常參數(shù):mydlq
Exception?in?thread?"main"?java.util.NoSuchElementException:?No?value?present
????at?java.util.Optional.get(Optional.java:135)
????at?club.mydlq.OptionalExample.main(OptionalExample.java:14)
可以觀察到傳入正常值的 Optional 調(diào)用 get 方法正常輸出值,通過(guò)空的 optional 對(duì)象使用 get 方法獲取值時(shí),拋出 NoSuchElementException 異常:
5、對(duì)象方法 ifPresent()
方法作用:?如果值存在則使用該值調(diào)用 consumer , 否則不做任何事情。
方法描述:?該方法 ifPresent(Consumer super T> consumer) 中參數(shù)接收的是 Consumer 類,它包含一個(gè)接口方法 accept(),該方法能夠?qū)魅氲闹颠M(jìn)行處理,但不會(huì)返回結(jié)果。這里傳入?yún)?shù)可以傳入 Lamdda 表達(dá)式或 Consumer 對(duì)象及實(shí)現(xiàn) Consumer 接口的類的對(duì)象。
返回類型:?void
示例代碼:
public?static?void?main(String[]?args)?{
????//?創(chuàng)建?Optional?對(duì)象,然后調(diào)用?Optional?對(duì)象的?ifPresent?方法,傳入?Lambda?表達(dá)式
????Optional?optional1?=?Optional.ofNullable("mydlq1");
????optional1.ifPresent((value)?->?System.out.println("Optional 的值為:"?+?value));
????//?創(chuàng)建?Optional?對(duì)象,調(diào)用?Optional?對(duì)象的?ifPresent?方法,傳入實(shí)現(xiàn)?Consumer?匿名內(nèi)部類
????Optional?optional2?=?Optional.ofNullable("mydlq2");
????Consumer?consumer?=?new?Consumer()?{
????????@Override
????????public?void?accept(Object?value)?{
????????????System.out.println("Optional 的值為:"?+?value);
????????}
????};
????optional2.ifPresent(consumer);
}
運(yùn)行代碼,可以觀察到控制臺(tái)輸出內(nèi)容如下:
Optional 的值為:mydlq1
Optional 的值為:mydlq2
可以觀察到,調(diào)用 ifPresent 使用 lambda 或者內(nèi)部匿名類方法,都是為了再執(zhí)行 Optional 對(duì)象的 ifPresent 方法時(shí),執(zhí)行一段代碼邏輯。
6、對(duì)象方法 orElse()
方法作用:?如果該值存在就直接返回, 否則返回指定的其它值。
方法描述:?orElse 方法實(shí)現(xiàn)很簡(jiǎn)單,就是使用三目表達(dá)式對(duì)傳入的參數(shù)值進(jìn)行 null 驗(yàn)證,即?
value != null ? value : other;?如果為 null 則返回 true,否則返回 false。返回類型:?T
示例代碼:
public?static?void?main(String[]?args)?{
????//?傳入正常參數(shù),獲取一個(gè)?Optional?對(duì)象,并使用?orElse?方法設(shè)置默認(rèn)值
????Optional?optional1?=?Optional.ofNullable("mydlq");
????Object?object1?=?optional1.orElse("默認(rèn)值");
????System.out.println("如果值不為空:"+object1);
????//?傳入?null?參數(shù),獲取一個(gè)?Optional?對(duì)象,并使用?orElse?方法設(shè)置默認(rèn)值
????Optional?optional2?=?Optional.ofNullable(null);
????Object?object2?=?optional2.orElse("默認(rèn)值");
????System.out.println("如果值為空:"+object2);
}
運(yùn)行代碼,可以觀察到控制臺(tái)輸出內(nèi)容如下:
如果值不為空:mydlq
如果值為空:默認(rèn)值
可以觀察到,如果 Optional 的值為空,則返回 orElse() 方法設(shè)置的默認(rèn)值,否則返回 Optional 中的值。
7、對(duì)象方法 orElseGet()
方法作用:?如果該值存在就返回值,否則觸發(fā) other,并返回 other 調(diào)用的結(jié)果。
方法描述:?orElseGet 方法和 orElse 方法類似,都是在 Optional 值為空時(shí),返回一個(gè)默認(rèn)操作,只不過(guò) orElse 返回的是默認(rèn)值,而 orElseGet 是執(zhí)行 lambda 表達(dá)式,然后返回 lambda 表達(dá)式執(zhí)行后的結(jié)果。
返回類型:?T
示例代碼:
public?static?void?main(String[]?args)?{
????//?傳入正常參數(shù),獲取一個(gè)?Optional?對(duì)象,并使用?orElse?方法設(shè)置默認(rèn)值
????Optional?optional1?=?Optional.ofNullable("mydlq");
????Object?object1?=?optional1.orElseGet(()?->?{
????????String?defaultVal?=?"執(zhí)行邏輯和生成的默認(rèn)值";
????????return?defaultVal;
????});
????System.out.println("輸出的值為:"+object1);
????//?傳入?null?參數(shù),獲取一個(gè)?Optional?對(duì)象,并使用?orElse?方法設(shè)置默認(rèn)值
????Optional?optional2?=?Optional.ofNullable(null);
????Object?object2?=?optional2.orElseGet(()?->?{
????????String?defaultVal?=?"執(zhí)行邏輯和生成的默認(rèn)值";
????????return?defaultVal;
????});
????System.out.println("輸出的值為:"+object2);
}
運(yùn)行代碼,可以觀察到控制臺(tái)輸出內(nèi)容如下:
輸出的值為:mydlq
輸出的值為:執(zhí)行邏輯和生成的默認(rèn)值
可也觀察到,當(dāng) Optional 值為不為空時(shí)正常返回帶值的 Optional,如果 Optional 為空則返回 orElseGet 方法中 lambda 表達(dá)式執(zhí)行后生成的值。
8、對(duì)象方法 orElseThrow()
方法作用:?如果 Optional 存在該值,返回包含的值,否則拋出由 Supplier 繼承的異常。
方法描述:?orElseThrow 方法其實(shí)就是判斷創(chuàng)建 Optional 時(shí)傳入的參數(shù)是否為 null,如果是非 null 則返回傳入的值,否則拋出 異常。
返回類型:? ?T
示例代碼:
public?static?void?main(String[]?args)?{
????//?傳入正常參數(shù),獲取一個(gè)?Optional?對(duì)象,并使用?orElseThrow?方法
????try?{
????????Optional?optional1?=?Optional.ofNullable("mydlq");
????????Object?object1?=?optional1.orElseThrow(()?->?{
????????????????????System.out.println("執(zhí)行邏輯,然后拋出異常");
????????????????????return?new?RuntimeException("拋出異常");
????????????????}
????????);
????????System.out.println("輸出的值為:"?+?object1);
????}?catch?(Throwable?throwable)?{
????????throwable.printStackTrace();
????}
????
????//?傳入?null?參數(shù),獲取一個(gè)?Optional?對(duì)象,并使用?orElseThrow?方法
????try?{
????????Optional?optional2?=?Optional.ofNullable(null);
????????Object?object2?=?optional2.orElseThrow(()?->?{
????????????????????System.out.println("執(zhí)行邏輯,然后拋出異常");
????????????????????return?new?RuntimeException("拋出異常");
????????????????}
????????);
????????System.out.println("輸出的值為:"?+?object2);
????}?catch?(Throwable?throwable)?{
????????throwable.printStackTrace();
????}
}
運(yùn)行代碼,可以觀察到控制臺(tái)輸出內(nèi)容如下:
值為不為空輸出的值:mydlq
執(zhí)行邏輯,然后拋出異常
java.lang.RuntimeException:?拋出異常
????at?club.mydlq.OptionalExample.lambda$main$1(OptionalExample.java:25)
????at?java.util.Optional.orElseThrow(Optional.java:290)
????at?club.mydlq.OptionalExample.main(OptionalExample.java:23)
可以觀察到,當(dāng)創(chuàng)建 Optional 時(shí)如果傳入的參數(shù)為空則執(zhí)行 Lambda 表達(dá)式代碼邏輯后拋出異常信息,否則返回傳入的參數(shù)值。
擴(kuò)展:Java8 Stream:2萬(wàn)字20個(gè)實(shí)例,玩轉(zhuǎn)集合的篩選、歸約、分組、聚合
9、對(duì)象方法 map()
方法作用:?如果有值,則對(duì)其執(zhí)行調(diào)用映射函數(shù)得到返回值。如果返回值不為 null,則創(chuàng)建包含映射返回值的 Optional 作為 map 方法返回值,否則返回空 Optional。
方法描述:?map 方法主要用于獲取某個(gè)對(duì)象中的某個(gè)屬性值的 Optional 對(duì)象時(shí)使用。map 方法調(diào)用時(shí),首先驗(yàn)證傳入的映射函數(shù)是否為空,如果為空則拋出異常。然后,再檢測(cè) Optional 的 value 是否為空,如果是,則返回一個(gè)空 value 的 Optional 對(duì)象。如果傳入的映射函數(shù)和 Optinal 的 value 都不為空,則返回一個(gè)帶 value 對(duì)象屬性的 Optional 對(duì)象。
返回類型:?Optional
示例代碼:
示例1:?創(chuàng)建 Map 集合,存儲(chǔ)一些鍵值對(duì)信息,通過(guò) Optional 操作 Map 獲取值,然后觀察:
public?static?void?main(String[]?args)?{
????//?創(chuàng)建?map?對(duì)象
????Map?userMap?=?new?HashMap<>();
????userMap.put("name1",?"mydlq");
????userMap.put("name2",?null);
????//?傳入?Map?對(duì)象參數(shù),獲取一個(gè)?Optional?對(duì)象,獲取?name1?屬性
????Optional?optional1?=?Optional.of(userMap).map(value?->?value.get("name1"));
????//?傳入?Map?對(duì)象參數(shù),獲取一個(gè)?Optional?對(duì)象,獲取?name2?屬性
????Optional?optional2?=?Optional.of(userMap).map(value?->?value.get("name2"));
????//?獲取?Optional?的值
????System.out.println("獲取的 name1 的值:"?+?optional1.orElse("默認(rèn)值"));
????System.out.println("獲取的 name2 的值:"?+?optional2.orElse("默認(rèn)值"));
}
運(yùn)行代碼,可以觀察到控制臺(tái)輸出內(nèi)容如下:
獲取的 Optional 的值:mydlq
獲取的 Optional 的值:默認(rèn)值
示例2:?創(chuàng)建一個(gè)用戶類,使用 Optional 操作用戶對(duì)象,獲取其 name 參數(shù),結(jié)合 Optional 的 map 方法獲取值,進(jìn)行觀察:
public?class?User?{
????private?String?name;
????
????public?User(String?name)?{
????????this.name?=?name;
????}
????public?String?getName()?{
????????return?name;
????}
????public?void?setName(String?name)?{
????????this.name?=?name;
????}
}
使用 Optional 的 map 方法對(duì)值處理:
public?static?void?main(String[]?args)?{
????//?創(chuàng)建一個(gè)對(duì)象,設(shè)置姓名屬性而不設(shè)置性別,這時(shí)候性別為?null
????User?user1?=?new?User("測(cè)試名稱");
????User?user2?=?new?User();
????//?使用?Optional?存儲(chǔ)?User?對(duì)象
????Optional?optional1?=?Optional.ofNullable(user1);
????Optional?optional2?=?Optional.ofNullable(user2);
????//?獲取對(duì)象的?name?屬性值
????String?name1?=?optional1.map(User::getName).orElse("未填寫");
????String?name2?=?optional2.map(User::getName).orElse("未填寫");
????//?輸出結(jié)果
????System.out.println("獲取的名稱:"?+?name1);
????System.out.println("獲取的名稱:"?+?name2);
}
運(yùn)行代碼,可以觀察到控制臺(tái)輸出內(nèi)容如下:
獲取的名稱:測(cè)試名稱
獲取的名稱:未填寫
總結(jié):
通過(guò)上面兩個(gè)示例觀察到,通過(guò) Optional 對(duì)象的 map 方法能夠獲取映射對(duì)象中的屬,創(chuàng)建 Optional 對(duì)象,并以此屬性充當(dāng) Optional 的值,結(jié)合 orElse 方法,如果獲取的屬性的值為空,則設(shè)置個(gè)默認(rèn)值。
10、對(duì)象方法 flatMap()
方法作用:?如果值存在,返回基于 Optional 包含的映射方法的值,否則返回一個(gè)空的 Optional。
方法描述:?flatMap 方法和 map 方法類似,唯一的不同點(diǎn)就是 map 方法會(huì)對(duì)返回的值進(jìn)行 Optional 封裝,而 flatMap 不會(huì),它需要手動(dòng)執(zhí)行 Optional.of 或 Optional.ofNullable 方法對(duì) Optional 值進(jìn)行封裝。
返回類型:?Optional
示例代碼:
public?static?void?main(String[]?args)?{
????//?創(chuàng)建?map?對(duì)象
????Map?userMap?=?new?HashMap<>();
????userMap.put("name",?"mydlq");
????userMap.put("sex",?"男");
????//?傳入?Map?對(duì)象參數(shù),獲取一個(gè)?Optional?對(duì)象
????Optional 運(yùn)行代碼,可以觀察到控制臺(tái)輸出內(nèi)容如下:
獲取的 Optional 的值:mydlq
根據(jù)結(jié)果觀察,可以看到 flatMap 和 map 方法沒有什么區(qū)別,但是仔細(xì)看,代碼中調(diào)用 flatMap 后,需要手動(dòng)執(zhí)行 of 或 ofNullable 方法創(chuàng)建了 Optional 對(duì)象。
11、對(duì)象方法 filter()
方法作用:?如果有值并且滿足斷言條件返回包含該值的 Optional,否則返回空 Optional。
方法描述:?filter 方法通過(guò)傳入的限定條件對(duì) Optional 實(shí)例的值進(jìn)行過(guò)濾,如果 Optional 值不為空且滿足限定條件就返回包含值的 Optional,否則返回空的 Optional。這里設(shè)置的限定條件需要使用實(shí)現(xiàn)了 Predicate 接口的 lambda 表達(dá)式來(lái)進(jìn)行配置。
返回類型:?Optional
示例代碼:
public?static?void?main(String[]?args)?{
????//?創(chuàng)建一個(gè)測(cè)試的?Optional?對(duì)象
????Optional?optional?=?Optional.ofNullable("mydlq");
????//?調(diào)用?Optional?的?filter?方法,設(shè)置一個(gè)滿足的條件,然后觀察獲取的?Optional?對(duì)象值是否為空
????Optional?optional1?=optional.filter((value)?->?value.length()?>?2);
????System.out.println("Optional 的值不為空::"?+?optional.isPresent());
????//?調(diào)用?Optional?的?filter?方法,設(shè)置一個(gè)不滿足的條件,然后觀察獲取的?Optional?對(duì)象值是否為空
????Optional?optional2?=optional.filter((value)?->?value.length()?<2);
????System.out.println("Optional 的值不為空::"?+?optional2.isPresent());
}
運(yùn)行代碼,可以觀察到控制臺(tái)輸出內(nèi)容如下:
Optional 的值不為空:true
Optional 的值不為空:false
根據(jù)結(jié)果可以觀察到,可以通過(guò) filter 設(shè)置一個(gè)條件來(lái)判斷 Optional 的值,如果滿足條件就返回帶值的 Optional,否則返回空的 Optional。
四、Optional 常用示例組合
在介紹一欄中已經(jīng)說(shuō)過(guò) Optional 是個(gè)容器,它可用保存類型的 T 的值,即使 T 為 null 也可以使用 Optional 存儲(chǔ),這樣我就不用顯示進(jìn)行空值檢測(cè),防止空指針異常。
上面也介紹了 Optional 的各種方法,在實(shí)際使用中這些方法常常組合使用。且很多方法也常與 Lambda 表達(dá)式結(jié)合,獲取我們想要的結(jié)果的值。
下面是常用的示例,可以作為參考:
對(duì)集合中的對(duì)象屬性進(jìn)行過(guò)濾
創(chuàng)建一個(gè) User 對(duì)象實(shí)體類,里面包含 name 屬性:
public?class?User?{
????private?String?name;
????public?User(String?name)?{
????????this.name?=?name;
????}
????public?String?getName()?{
????????return?name;
????}
????public?void?setName(String?name)?{
????????this.name?=?name;
????}
}
創(chuàng)建一個(gè)使用 main 方法的類,創(chuàng)建幾個(gè) User 對(duì)象且設(shè)置不同的值,有的對(duì)象為 null 有的屬性不設(shè)置,然后通過(guò) Optional 獲取 name 屬性值加入集合,進(jìn)行測(cè)試:
import?java.util.ArrayList;
import?java.util.List;
import?java.util.Optional;
public?class?OptionalExample?{
????/**
?????*?測(cè)試的?main?方法
?????*/
????public?static?void?main(String[]?args)?{
????????//?創(chuàng)建一個(gè)測(cè)試的用戶集合
????????List?userList?=?new?ArrayList<>();
????????//?創(chuàng)建幾個(gè)測(cè)試用戶
????????User?user1?=?new?User("abc");
????????User?user2?=?new?User("efg");
????????User?user3?=?null;
????????//?將用戶加入集合
????????userList.add(user1);
????????userList.add(user2);
????????userList.add(user3);
????????//?創(chuàng)建用于存儲(chǔ)姓名的集合
????????List?nameList?=?new?ArrayList();
????????//?循環(huán)用戶列表獲取用戶信息,值獲取不為空且用戶以?a?開頭的姓名,
????????//?如果不符合條件就設(shè)置默認(rèn)值,最后將符合條件的用戶姓名加入姓名集合
????????for?(User?user?:?userList)?{
????????????nameList.add(Optional.ofNullable(user).map(User::getName).filter(value?->?value.startsWith("a")).orElse("未填寫"));
????????}
????????//?輸出名字集合中的值
????????System.out.println("通過(guò) Optional 過(guò)濾的集合輸出:");
????????nameList.stream().forEach(System.out::println);
????}
}
輸出運(yùn)行結(jié)果:
通過(guò) Optional 過(guò)濾的集合輸出:
abc
未填寫
未填寫
通過(guò)上面,可以觀察到,使用 Optional 有時(shí)候可以很方便的過(guò)濾一些屬性,而且它的方法可以通過(guò)鏈?zhǔn)秸{(diào)用,方法間相互組合使用,使我們用少量的代碼就能完成復(fù)雜的邏輯。
、
順便給大家推薦一個(gè)GitHub項(xiàng)目,這個(gè) GitHub 整理了上千本常用技術(shù)PDF,絕大部分核心的技術(shù)書籍都可以在這里找到,GitHub地址:
https://github.com/javadevbooks/books電子書已經(jīng)更新好了,你們需要的可以自行下載了,記得點(diǎn)一個(gè)star,持續(xù)更新中...
