Java?Optional的判空操作詳解
Optional判空
JAVA在1.8版本推出Optional,官方文檔將其描述為可能包含或不包含非空值的容器對(duì)象,目前Optional用于避免程序出現(xiàn)異常NullPointerException。
代碼模擬
// 下面所有類省略set,get方法
public class Employee {
private String employeeName;
private Team team;
}
public class Team {
private String teamName;
private Department department;
public Team(String teamName) {
this.teamName = teamName;
}
}
public class Department {
private String departmentName;
private Company company;
}
public class Company {
private String companyName;
}測(cè)試代碼
// 在創(chuàng)建時(shí)因?yàn)闆]有初始化Team對(duì)象的Department屬性,導(dǎo)致后續(xù)調(diào)用空指針
public void testCompany(){
Employee employee = new Employee();
employee.setEmployeeName("zhangsan");
employee.setTeam(new Team("xxx產(chǎn)品組"));
System.out.println(employee.getTeam().getDepartment().getCompany().getCompanyName());
}這時(shí)如果我們采用傳統(tǒng)方式一般判空代碼如下
public void testCompanyAvoidNPE(){
Employee employee = new Employee();
employee.setEmployeeName("zhangsan");
employee.setTeam(new Team("xxx產(chǎn)品組"));
Team team = employee.getTeam();
if (team == null){
System.out.println("異常拉,參數(shù)為空!");
return;
}
Department department = team.getDepartment();
if (department == null){
System.out.println("異常拉,參數(shù)為空!");
return;
}
Company company = department.getCompany();
if (company == null){
System.out.println("異常拉,參數(shù)為空!");
return;
}
String companyName = company.getCompanyName();
System.out.println(companyName);
}顯然這種判空代碼造成了業(yè)務(wù)代碼膨脹,代碼可讀性極低,所以在這種場(chǎng)景下我們需要學(xué)習(xí)1.8推出的判空容器對(duì)象Optional。
Optional常用方法
創(chuàng)建 Optional 對(duì)象
JAVA提供了三個(gè)靜態(tài)方法用于構(gòu)建Optional對(duì)象如下所示
| 返回值 | 方法和描述 |
|---|---|
| static <T> Optional<T> | empty() 返回一個(gè)空的 Optional實(shí)例。 |
| static <T> Optional<T> | of(T value) 返回具有 Optional的當(dāng)前非空值的Optional。 |
| static <T> Optional<T> | ofNullable(T value) 返回一個(gè) Optional指定值的Optional,如果非空,則返回一個(gè)空的 Optional 。 |
public void createOptionalObject(){
System.out.println(Optional.empty());
// 傳null報(bào)空指針
// System.out.println(Optional.of(null));
System.out.println(Optional.of(new String("1111")));
// 傳null調(diào)用Optional.empty()
System.out.println(Optional.ofNullable(null));
System.out.println(Optional.ofNullable(new Content("111","測(cè)試內(nèi)容")));
}
class Content {
private String id;
private String value;
public Content() {
}
public Content(String id, String value) {
this.id = id;
this.value = value;
}
// 省略get,set方法
}
執(zhí)行結(jié)果如下
Optional.empty
Optional[1111]
Optional.empty
Optional[Content{id='111', value='測(cè)試內(nèi)容'}]
在真正使用時(shí)建議使用ofNullable,因?yàn)樗芴幚砜罩祷蛘叻强罩?,代碼如下
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
常用功能方法
| 方法名 | 返回值 | 功能描述 |
|---|---|---|
| isPresent() | boolean | 判斷Optional對(duì)象是否存在,存在true不存在false |
| ifPresent(Consumer<? super T> consumer) | void | 如果Optional對(duì)象存在執(zhí)行consumer消費(fèi)型接口,不存在不執(zhí)行 |
| get | T | 返回Optional對(duì)象封裝的對(duì)象T數(shù)據(jù),注意實(shí)際對(duì)象可能為空會(huì)拋出異常 |
| orElse(T other) | T | 如果Optional對(duì)象存在則返回封裝的對(duì)象數(shù)據(jù),如果不存在返回T other數(shù)據(jù),相當(dāng)于不存在給默認(rèn)值 |
| orElseGet(Supplier<? extends T> other) | T | 是orElse方法的升級(jí)版,區(qū)別在于orElse方法傳入的是一個(gè)固定默認(rèn)值,而此方法是一個(gè)供給型函數(shù)方法,如果Optional對(duì)象為空則執(zhí)行other的方法邏輯 |
| orElseThrow(Supplier<? extends X> exceptionSupplier) | <X extends Throwable>T | 一樣是orElse方法的升級(jí)版,當(dāng)Optional對(duì)象為空?qǐng)?zhí)行exceptionSupplier方法,最后拋出異常 |
| filter(Predicate<? super T> predicate) | Optional<T> | 當(dāng)Optional對(duì)象滿足predicate斷言函數(shù)中的匹配規(guī)則則返回,否則返回空Optional |
| map(Function<? super T,? extends U> mapper) | <U> Optional<U> | 能夠?qū)ptional的對(duì)象值處理轉(zhuǎn)換為另一個(gè)實(shí)例對(duì)象值,并生成新類型的Optional對(duì)象,如果生成的新對(duì)象為null,則返回一個(gè)空Optional對(duì)象 |
| flatMap(Function<? super T,Optional<U>> mapper) | <U> Optional<U> | 和map類似,不過map操作的是具體對(duì)象,而flatMap返回的是Optional封裝過的對(duì)象 |
代碼演示如下
public void testOptionFunction(){
//===============================isPresent()================================
// false
System.out.println(Optional.empty().isPresent());
// Optional[Content{id='222', value='測(cè)試'}]
System.out.println(Optional.ofNullable(new Content("222","測(cè)試")));
//===============================ifPresent()================================
// 不為空打印:Content{id='222', value='測(cè)試'} 為空不執(zhí)行
Optional.ofNullable(new Content("222","測(cè)試")).ifPresent(e->{
System.out.println("不為空打?。?+e);
});
//===============================get()================================
// NoSuchElementException: No value present
try {
System.out.println(Optional.empty().get());
}catch (Exception e){
e.printStackTrace();
}
// Content{id='222', value='測(cè)試'}
System.out.println(Optional.ofNullable(new Content("222","測(cè)試")).get());
//===============================orElse()================================
// Content{id='0', value='默認(rèn)'}
System.out.println(Optional.empty().orElse(new Content("0","默認(rèn)")));
//===============================orElseGet()================================
// Content{id='333', value='測(cè)試orElseGet'}
System.out.println(Optional.empty().orElseGet(() -> {
Content content = new Content("333", "測(cè)試orElseGet");
return content;
}));
// Content{id='222', value='測(cè)試'}
System.out.println(Optional.ofNullable(new Content("222", "測(cè)試")).orElseGet(() -> {
Content content = new Content("444", "測(cè)試orElseGet");
return content;
}));
//===============================orElseThrow()================================
// java.lang.Exception: 參數(shù)為空
try {
Optional.empty().orElseThrow(()->{
return new Exception("參數(shù)為空");
});
} catch (Exception e) {
e.printStackTrace();
}
//===============================filter()================================
// "555".equals(e.getId()); Optional[Content{id='555', value='測(cè)試'}]
// "5565".equals(e.getId()); Optional.empty
System.out.println(Optional.ofNullable(new Content("555", "測(cè)試")).filter(e -> {
return "5565".equals(e.getId());
}));
}map和flatMap
public void testOptionMapFunction(){
Optional<Content> optionalContent = Optional.ofNullable(new Content("777","測(cè)試Map"));
Optional<Content> optionalContent1 = optionalContent.map(e -> {
String id = e.getId();
String value = e.getValue();
return e;
});
Optional<Content> optionalContent2 = optionalContent.flatMap(e -> {
String id = e.getId();
String value = e.getValue();
// 不同點(diǎn)在這里,一個(gè)是可以轉(zhuǎn)換為另一個(gè)實(shí)例對(duì)象,一個(gè)是轉(zhuǎn)換為Optional包裝對(duì)象
return Optional.of(e);
});
// 最終效果實(shí)現(xiàn)效果類似
System.out.println(optionalContent1);
System.out.println(optionalContent2);
}
使用Optional一定比null好嗎
這個(gè)顯然是不對(duì)的,如果使用方式如下所示,其實(shí)和null的直接判空沒有區(qū)別
public static void main(String[] args) {
Optional<Content> optionalContent = Optional.ofNullable(null);
// 直接報(bào)錯(cuò)
optionalContent.get();
}
// 升級(jí)寫法
public static void main(String[] args) {
Optional<Content> optionalContent = Optional.ofNullable(null);
// 非空判斷
if (optionalContent.isPresent()){
System.out.println(optionalContent.get());
}
}
null的直接判空
public static void main(String[] args) {
Content content = new Content();
if (content != null){
System.out.println(content);
}
}
正確寫法如下所示
public static void main(String[] args) {
Optional<Content> optionalContent = Optional.ofNullable(null);
// 非空時(shí)執(zhí)行消費(fèi)型接口里面的邏輯
optionalContent.ifPresent(content -> {
System.out.println(content);
});
}到這里有人可能說,如果if{}else{}里面都需要寫邏輯如何處理呢
public static void main(String[] args) {
Optional<Content> optionalContent = Optional.ofNullable(null);
Content content = optionalContent.map(e -> {
// 做一些業(yè)務(wù)
// 返回值可以為任意類型值,可以返回字符串,不過orElseGet需要返回字符串保持一致即可
return e;
}).orElseGet(() -> {
// 做一些業(yè)務(wù)
return new Content("0", "默認(rèn)值");
});
System.out.println(content);
}
Optional 使用場(chǎng)景
減少繁瑣的非空判斷
如前面提到的testCompanyAvoidNPE方法中的例子,就可以采用Optional來簡(jiǎn)化
public void testCompanyAvoidNPE2(){
Employee employee = new Employee();
employee.setEmployeeName("zhangsan");
employee.setTeam(new Team("xxx產(chǎn)品組"));
// 這里相當(dāng)于是鏈?zhǔn)讲僮?
String companyName = Optional.ofNullable(employee)
.map(employee1 -> employee1.getTeam())
.map(team -> team.getDepartment())
.map(department -> department.getCompany())
.map(company -> company.getCompanyName())
.orElse("no company");
System.out.println(companyName);
}
設(shè)置默認(rèn)值兜底
// 原始方法
public String setDefaultValue1(Content content){
if (ObjectUtils.isEmpty(content)){
return "0";
}
if (StringUtils.isEmpty(content.getId())){
String id = "0";
content.setId(id);
}
return content.getId();
}
// 采用Optional
public String setDefaultValue2(Content content){
String id = Optional.ofNullable(content)
.map(content1 -> content1.getId())
.orElse("0");
return id;
}
Optional 盡量只用作方法的返回類型
注意我們采用Optional的最終目的是避免程序中出現(xiàn)null對(duì)象異常的情況,所以我們封裝方法的時(shí)候可以采用Optional 作為方法的返回值類型,但也要注意Optional雖好但不要濫用,適當(dāng)使用即可。
以上就是Java Optional的判空操作詳解的詳細(xì)內(nèi)容,更多關(guān)于Java Optional判空操作的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java實(shí)現(xiàn)的猜數(shù)字游戲示例
這篇文章主要介紹了Java實(shí)現(xiàn)的猜數(shù)字游戲,涉及Java數(shù)學(xué)運(yùn)算與判斷相關(guān)操作技巧,需要的朋友可以參考下2018-06-06
解決IntelliJ IDEA中鼠標(biāo)拖動(dòng)選擇為矩形區(qū)域問題
這篇文章主要介紹了解決IntelliJ IDEA中鼠標(biāo)拖動(dòng)選擇為矩形區(qū)域問題,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10
Spring中的AutowireCandidateResolver的具體使用詳解
這篇文章主要介紹了Spring中的AutowireCandidateResolver的具體使用詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04
java操作oracle數(shù)據(jù)庫(kù)示例
這篇文章主要介紹了java操作oracle數(shù)據(jù)庫(kù)示例,需要的朋友可以參考下2014-04-04
spring的TransactionalEventListener事務(wù)感知源碼解析
這篇文章主要為大家介紹了spring的TransactionalEventListener事務(wù)感知源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09
Java進(jìn)行日期解析與格式化的實(shí)現(xiàn)代碼
使用 Java 搭配 Apache Commons Lang3 和 Natty 庫(kù),可以實(shí)現(xiàn)靈活高效的日期解析與格式化,本文將通過相關(guān)示例為大家講講具體的實(shí)踐操作,需要的可以了解下2025-05-05

