前言
相信不少小伙伴已經被java的NPE(Null Pointer Exception)所謂的空指針異常搞的頭昏腦漲, 有大佬說過“防止 NPE,是程序員的基本修養。”但是修養歸修養,也是我們程序員最頭疼的問題之一,那么我們今天就要盡可能的利用Java8的新特性 Optional來盡量簡化代碼同時高效處理NPE(Null Pointer Exception 空指針異常)
認識 Optional
1、ofNullable 、orElse、isPresent 和 ifPresent
Java 8 提供了判空寫法:
Optional.ofNullable(對象).orElse(為空時的邏輯).ifPresent(不為空是的邏輯);
boolean isNull = Optional.ofNullable(對象).isPresent(); // 如果為空返回 false;不為空返回 true
ofNullable 中的對象是一個可為空的對象(這個對象可以包含任意類型:Integer、Object、List、Map 等等),如果為空則執行 orElse 里面的邏輯,不為空則執行 ifPresent 里面的邏輯;也可以直接通過 isPresent() 來判斷當前對象是否為空。直接上例子吧:
//求字符串 s 的長度( 為空的時候返回0 ) String str = getKey(); if (StringUtils.isBlank(str)) { return 0; } else { return str.length(); } // 新版 JDK 用法 return Optional.ofNullable(str).orElse("").length(); // 或者 if (Optional.ofNullable(str).isPresent()) { return str.length(); } // 或者 Optional.ofNullable(str).ifPresent(s -> System.out.println("長度"+s.length());
循環遍歷List 集合
// 原來常規寫法 List<String> list = getList(); if (list != null) { for(String s: list){ System.out.println(s); } } // 新版 JDK 寫法 Optional.ofNullable(list).orElse(new ArrayList<>()).forEach(o -> System.out.println(o));
2、filter
用於對給定的對象進行過濾
filter()方法大致意思是,接受一個對象,然后對他進行條件過濾,如果條件符合則返回Optional對象本身,如果不符合則返回空Optional
Person person=new Person(); person.setAge(2); Optional.ofNullable(person).filter(p -> p.getAge()>50)
再看一個根據基本的電子郵箱驗證來決定接受或拒絕 User(用戶) 的示例
@Test public void whenFilter_thenOk() { User user = new User("anna@gmail.com", "1234"); Optional<User> result = Optional.ofNullable(user) .filter(u -> u.getEmail() != null && u.getEmail().contains("@")); assertTrue(result.isPresent()); }
如果通過過濾器測試,result 對象會包含非空值。
3、map
map()方法將對應Funcation函數式接口中的對象,進行二次運算,封裝成新的對象然后返回在Optional中
Person person1=new Person(); person.setAge(2); // 返回具體內容 String optName = Optional.ofNullable(person).map(p -> person.getName()).orElse("name為空"); // 返回到 optional 中 Optional<Object> optName = Optional.ofNullable(person).map(p -> Optional.ofNullable(p.getName()).orElse("name為空"));
4、orElseThrow()
這個我個人在實戰中也經常用到這個方法,方法作用的話就是如果為空,就拋出你定義的異常,如果不為空返回當前對象,在實戰中所有異常肯定是要處理好的,為了代碼的可讀性
//簡單的一個查詢 Member member = memberService.selectByPhone(request.getPhone()); Optional.ofNullable(member).orElseThrow(() -> new ServiceException("沒有查詢的相關數據"));
差異對比
1、orElse() 和 orElseGet() 的不同之處
乍一看,這兩種方法似乎起着同樣的作用。然而事實並非如此。我們創建一些示例來突出二者行為上的異同。
@Test public void givenEmptyValue_whenCompare_thenOk() { // 第一種情況 User user = null; // 第二種情況 User user = new User("john@gmail.com", "1234"); logger.debug("Using orElse"); User result = Optional.ofNullable(user).orElse(createNewUser()); logger.debug("Using orElseGet"); User result2 = Optional.ofNullable(user).orElseGet(() -> createNewUser()); } private User createNewUser() { logger.debug("Creating New User"); return new User("extra@gmail.com", "1234"); }
打印輸出結果如下:
// 第一種情況 Using orElse creating user Using orElseGet creating user // 第二種情況 Using orElse creating user Using orElseGet
這個示例中,兩個 Optional 對象都包含非空值,兩個方法都會返回對應的非空值。不過,orElse() 方法仍然創建了 User 對象。與之相反,orElseGet() 方法不創建 User 對象。
在執行較密集的調用時,比如調用 Web 服務或數據查詢,這個差異會對性能產生重大影響。
且需要注意:orElse 內部可以直接寫對應的方法或函數;orElseGet 內部必須要有對應的參數即使空也需要寫一個空的括號,注意對比下:
User result = Optional.ofNullable(user).orElse(createNewUser());
User result2 = Optional.ofNullable(user).orElseGet(() -> createNewUser());