<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
JAVA在1.8版本推出Optional,官方檔案將其描述為可能包含或不包含非空值的容器物件,目前Optional用於避免程式出現異常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; }
測試程式碼
// 在建立時因為沒有初始化Team物件的Department屬性,導致後續呼叫空指標 public void testCompany(){ Employee employee = new Employee(); employee.setEmployeeName("zhangsan"); employee.setTeam(new Team("xxx產品組")); System.out.println(employee.getTeam().getDepartment().getCompany().getCompanyName()); }
這時如果我們採用傳統方式一般判空程式碼如下
public void testCompanyAvoidNPE(){ Employee employee = new Employee(); employee.setEmployeeName("zhangsan"); employee.setTeam(new Team("xxx產品組")); Team team = employee.getTeam(); if (team == null){ System.out.println("異常拉,引數為空!"); return; } Department department = team.getDepartment(); if (department == null){ System.out.println("異常拉,引數為空!"); return; } Company company = department.getCompany(); if (company == null){ System.out.println("異常拉,引數為空!"); return; } String companyName = company.getCompanyName(); System.out.println(companyName); }
顯然這種判空程式碼造成了業務程式碼膨脹,程式碼可讀性極低,所以在這種場景下我們需要學習1.8推出的判空容器物件Optional。
建立 Optional 物件
JAVA提供了三個靜態方法用於構建Optional物件如下所示
返回值 | 方法和描述 |
---|---|
static <T> Optional<T> | empty() 返回一個空的 Optional範例。 |
static <T> Optional<T> | of(T value) 返回具有 Optional的當前非空值的Optional。 |
static <T> Optional<T> | ofNullable(T value) 返回一個 Optional指定值的Optional,如果非空,則返回一個空的 Optional 。 |
public void createOptionalObject(){ System.out.println(Optional.empty()); // 傳null報空指標 // System.out.println(Optional.of(null)); System.out.println(Optional.of(new String("1111"))); // 傳null呼叫Optional.empty() System.out.println(Optional.ofNullable(null)); System.out.println(Optional.ofNullable(new Content("111","測試內容"))); } class Content { private String id; private String value; public Content() { } public Content(String id, String value) { this.id = id; this.value = value; } // 省略get,set方法 }
執行結果如下
Optional.empty
Optional[1111]
Optional.empty
Optional[Content{id='111', value='測試內容'}]
在真正使用時建議使用ofNullable,因為它能處理空值或者非空值,程式碼如下
public static <T> Optional<T> ofNullable(T value) { return value == null ? empty() : of(value); }
常用功能方法
方法名 | 返回值 | 功能描述 |
---|---|---|
isPresent() | boolean | 判斷Optional物件是否存在,存在true不存在false |
ifPresent(Consumer<? super T> consumer) | void | 如果Optional物件存在執行consumer消費型介面,不存在不執行 |
get | T | 返回Optional物件封裝的物件T資料,注意實際物件可能為空會丟擲異常 |
orElse(T other) | T | 如果Optional物件存在則返回封裝的物件資料,如果不存在返回T other資料,相當於不存在給預設值 |
orElseGet(Supplier<? extends T> other) | T | 是orElse方法的升級版,區別在於orElse方法傳入的是一個固定預設值,而此方法是一個供給型函數方法,如果Optional物件為空則執行other的方法邏輯 |
orElseThrow(Supplier<? extends X> exceptionSupplier) | <X extends Throwable>T | 一樣是orElse方法的升級版,當Optional物件為空執行exceptionSupplier方法,最後丟擲異常 |
filter(Predicate<? super T> predicate) | Optional<T> | 當Optional物件滿足predicate斷言函數中的匹配規則則返回,否則返回空Optional |
map(Function<? super T,? extends U> mapper) | <U> Optional<U> | 能夠將Optional的物件值處理轉換為另一個範例物件值,並生成新型別的Optional物件,如果生成的新物件為null,則返回一個空Optional物件 |
flatMap(Function<? super T,Optional<U>> mapper) | <U> Optional<U> | 和map類似,不過map操作的是具體物件,而flatMap返回的是Optional封裝過的物件 |
程式碼演示如下
public void testOptionFunction(){ //===============================isPresent()================================ // false System.out.println(Optional.empty().isPresent()); // Optional[Content{id='222', value='測試'}] System.out.println(Optional.ofNullable(new Content("222","測試"))); //===============================ifPresent()================================ // 不為空列印:Content{id='222', value='測試'} 為空不執行 Optional.ofNullable(new Content("222","測試")).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='測試'} System.out.println(Optional.ofNullable(new Content("222","測試")).get()); //===============================orElse()================================ // Content{id='0', value='預設'} System.out.println(Optional.empty().orElse(new Content("0","預設"))); //===============================orElseGet()================================ // Content{id='333', value='測試orElseGet'} System.out.println(Optional.empty().orElseGet(() -> { Content content = new Content("333", "測試orElseGet"); return content; })); // Content{id='222', value='測試'} System.out.println(Optional.ofNullable(new Content("222", "測試")).orElseGet(() -> { Content content = new Content("444", "測試orElseGet"); return content; })); //===============================orElseThrow()================================ // java.lang.Exception: 引數為空 try { Optional.empty().orElseThrow(()->{ return new Exception("引數為空"); }); } catch (Exception e) { e.printStackTrace(); } //===============================filter()================================ // "555".equals(e.getId()); Optional[Content{id='555', value='測試'}] // "5565".equals(e.getId()); Optional.empty System.out.println(Optional.ofNullable(new Content("555", "測試")).filter(e -> { return "5565".equals(e.getId()); })); }
map和flatMap
public void testOptionMapFunction(){ Optional<Content> optionalContent = Optional.ofNullable(new Content("777","測試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(); // 不同點在這裡,一個是可以轉換為另一個範例物件,一個是轉換為Optional包裝物件 return Optional.of(e); }); // 最終效果實現效果類似 System.out.println(optionalContent1); System.out.println(optionalContent2); }
這個顯然是不對的,如果使用方式如下所示,其實和null的直接判空沒有區別
public static void main(String[] args) { Optional<Content> optionalContent = Optional.ofNullable(null); // 直接報錯 optionalContent.get(); } // 升級寫法 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); // 非空時執行消費型介面裡面的邏輯 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 -> { // 做一些業務 // 返回值可以為任意型別值,可以返回字串,不過orElseGet需要返回字串保持一致即可 return e; }).orElseGet(() -> { // 做一些業務 return new Content("0", "預設值"); }); System.out.println(content); }
減少繁瑣的非空判斷
如前面提到的testCompanyAvoidNPE方法中的例子,就可以採用Optional來簡化
public void testCompanyAvoidNPE2(){ Employee employee = new Employee(); employee.setEmployeeName("zhangsan"); employee.setTeam(new Team("xxx產品組")); // 這裡相當於是鏈式操作 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); }
設定預設值兜底
// 原始方法 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的最終目的是避免程式中出現null物件異常的情況,所以我們封裝方法的時候可以採用Optional 作為方法的返回值型別,但也要注意Optional雖好但不要濫用,適當使用即可。
以上就是Java Optional的判空操作詳解的詳細內容,更多關於Java Optional判空操作的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45