前言
文字已收錄至我的GitHub倉庫,歡迎Star:github.com/bin39232820…
種一棵樹最好的時間是十年前,其次是現在
我知道很多人不玩qq了,但是懷舊一下,歡迎加入六脈神劍Java菜鳥學習群,群聊號碼:549684836 鼓勵大家在技術的路上寫部落格
絮叨
今天 開始寫Java8新特性系列,怎麼說呢,主要有幾個新東西
- Lambda表示式
- 函式式介面
- 方法引用
- Stream流
- Optional類
- default關鍵字
這個四個的主要作用 簡化程式碼編寫,提高效能等等,但是也會給維護帶來麻煩,因為不懂的人去看,真心累,但是寫起來是真的香,今天打算講標題上的。今天打算講講這個防止空指標異常的Optional類,前面幾節可以參考下面連結
?你不知道的Java內部類
?你必須知道的Java泛型
?Java8新特性之Lambda表示式,函式式介面,方法引用和default關鍵字
文字力求簡單講清每個知識點,希望大家看完能有所收穫
預介紹
思考: 呼叫一個方法得到了返回值卻不能直接將返回值作為引數去呼叫別的方法。
原來解決方案: 我們首先要判斷這個返回值是否為null,只有在非空的前提下才能將其作為其他方法的引數。這正是一些類似Guava的外部API試圖解決的問題。一些JVM程式語言比如Scala、Ceylon等已經將對在核心API中解決了這個問題。 我們來看個例子
是不是感覺這樣寫的話,寫法會好很多呢?接下來我們好好看看這個Optional
Optional
Optional先來看看屬性和構造方法
// 1、建立出一個Optional容器,容器裡邊並沒有裝載著物件
private static final Optional<?> EMPTY = new Optional<>();
// 2、代表著容器中的物件
private final T value;
// 3、私有構造方法
private Optional() {
this.value = null;
}
// 4、得到一個Optional容器,Optional沒有裝載著物件
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
// 5、私有構造方法(帶引數),引數就是具體的要裝載的物件,如果傳進來的物件為null,丟擲異常
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
// 5.1、如果傳進來的物件為null,丟擲異常
public static <T> T requireNonNull(T obj) {
if (obj == null)
throw new NullPointerException();
return obj;
}
// 6、建立出Optional容器,並將物件(value)裝載到Optional容器中。
// 傳入的value如果為null,丟擲異常(呼叫的是Optional(T value)方法)
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
// 建立出Optional容器,並將物件(value)裝載到Optional容器中。
// 傳入的value可以為null,如果為null,返回一個沒有裝載物件的Optional物件
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
複製程式碼
所以可以得出建立Optional容器有兩種方式:
- 呼叫ofNullable()方法,傳入的物件可以為null
- 呼叫of()方法,傳入的物件不可以為null,否則丟擲NullPointerException 寫個方法測試一下哈哈
of
ofNullable
Optional容器簡單的方法
// 得到容器中的物件,如果為null就丟擲異常
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
// 判斷容器中的物件是否為null
public boolean isPresent() {
return value != null;
}
// 如果容器中的物件存在,則返回。否則返回傳遞進來的引數
public T orElse(T other) {
return value != null ? value : other;
}
複製程式碼
這三個方法是Optional類比較常用的方法,並且是最簡單的。(因為引數不是函式式介面)
來看用法
所以這個就是我們用來再專案中校空的,用的還挺多的
Optional容器進階用法(主要是因為函數語言程式設計,簡化程式碼)
首先來看看ifPresent(Consumer<? super T> consumer)方法
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(value);
}
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
複製程式碼
orElseGet和orElseThrow方法
原始碼
// 如果物件存在,則直接返回,否則返回由Supplier介面的實現用來生成預設值
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
@FunctionalInterface
public interface Supplier<T> {
T get();
}
// 如果存在,則返回。否則丟擲supplier介面建立的異常
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
複製程式碼
用法
public static void main(String[] args) {
User user = new User();
user.setName("六脈神劍");
test(user);
}
public static void test(User user) {
Optional<User> optional = Optional.ofNullable(user);
// 如果存在user,則直接返回,否則建立出一個新的User物件
User user1 = optional.orElseGet(() -> new User());
// 舊寫法
if (user != null) {
user = new User();
}
}
複製程式碼
filter方法
原始碼
// 如果容器中的物件存在,並且符合過濾條件,返回裝載物件的Optional容器,否則返回一個空的Optional容器
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}
// 介面
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
複製程式碼
用法
public static void test(User user) {
Optional<User> optional = Optional.ofNullable(user);
// 如果容器中的物件存在,並且符合過濾條件,返回裝載物件的Optional容器,否則返回一個空的Optional容器
Optional<User> optional = Optional.ofNullable(user);
User user1 = optional.filter((value) -> "六脈神劍".equals(value.getName())).orElse(null);
System.out.println(user1.getName());
}
複製程式碼
map
原始碼
// 如果容器的物件存在,則對其執行呼叫mapping函式得到返回值。然後建立包含mapping返回值的Optional,否則返回空Optional。
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Optional.ofNullable(mapper.apply(value));
}
}
// 介面
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
複製程式碼
用法
public static void test(User user) {
Optional<User> optional = Optional.ofNullable(user);
// 如果容器的物件存在,則對其執行呼叫mapping函式得到返回值。然後建立包含mapping返回值的Optional,否則返回空Optional。
optional.map(user1 -> user1.getName()).orElse("六脈神劍");
}
// 上面一句程式碼對應著最開始的老寫法:
public String tradition(User user) {
if (user != null) {
return user.getName();
}else{
return "六脈神劍";
}
}
複製程式碼
flatMap
原始碼
// flatMap方法與map方法類似,區別在於apply函式的返回值不同。map方法的apply函式返回值是? extends U,而flatMap方法的apply函式返回值必須是Optional
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Objects.requireNonNull(mapper.apply(value));
}
}
複製程式碼
總結
再來感受一下Optional的魅力
public static void main(String[] args) {
User user = new User();
user.setName("六脈神劍");
System.out.println(test(user));
}
// 以前的程式碼1.0
public static String test2(User user) {
if (user != null) {
String name = user.getName();
if (name != null) {
return name.toUpperCase();
} else {
return null;
}
} else {
return null;
}
}
// 以前的程式碼2.0
public static String test3(User user) {
if (user != null && user.getName() != null) {
return user.getName().toUpperCase();
} else {
return null;
}
}
// 現在的程式碼
public static String test(User user) {
return Optional.ofNullable(user)
.map(user1 -> user1.getName())
.map(s -> s.toUpperCase()).orElse(null);
}
複製程式碼
filter,map或flatMap一個函式,函式的引數拿到的值一定不是null。所以我們通過filter,map 和 flatMap之類的函式可以將其安全的進行變換,最後通過orElse系列,get,isPresent 和 ifPresent將其中的值提取出來。
結尾
好了,今天的optional就講那麼多了。大家發現沒有 泛型 和函式式介面一定要熟悉,如果不熟悉來學這個確實有點難度哈,明天把Stream 這個大頭講完 1.8算是講完了,其實不難,只要理解了,你自然會用上哈。
日常求贊
好了各位,以上就是這篇文章的全部內容了,能看到這裡的人呀,都是人才。
創作不易,各位的支援和認可,就是我創作的最大動力,我們下篇文章見
六脈神劍 | 文 【原創】如果本篇部落格有任何錯誤,請批評指教,不勝感激 !