終於和 null say 拜拜了,我超開心

你好呀,我是沉默王二,一個和黃家駒同樣身高,和劉德華同樣顏值的程序員。從 10 年前我開始寫第一行 Java 代碼至今,一直以爲 null 在 Java 中是一個最特殊的存在,它既是好朋友,能夠把不須要的變量置爲 null 從而釋放內存,提升性能;它又是敵人,由於它和大名鼎鼎且煩不勝煩的 NullPointerException(NPE)如影隨形,而 NPE 的發明人 Tony Hoare 曾在 2009 年認可:「Null References 是一個荒唐的設計,就好像我賭輸掉了十億美圓」。css

你看,null 居然是一個亦敵亦友的傢伙。java

一般,爲了表示列表中的元素不存在,咱們首先想到的就是返回 null,這種想法很合理,合理到沒法反駁。咱們來模擬一個實際的應用場景,假設小二如今要從數據庫中獲取一個姓名的列表,而後將姓名打印到控制檯,對應的代碼以下。git

public class NullDemo {
    public static void main(String[] args) {
        List<String> names = getNamesFromDB();
        if (names != null) {
            for (String name : names) {
                System.out.println(name);
            }
        }
    }

    public static List<String> getNamesFromDB() {
        // 模擬此時沒有從數據庫獲取到對應的姓名。
        return null;
    }
}
複製代碼

因爲 getNamesFromDB() 方法返回了 null 來做爲沒有姓名列表的標誌,那就意味着在遍歷列表的時候要先對列表判空,不然將會拋出 NPE 錯誤,不信你把 if (names != null) 去掉試試,立馬給你顏色看。程序員

Exception in thread "mainjava.lang.NullPointerException
    at com.cmower.dzone.stopdoing3things.NullDemo.main(NullDemo.java:12)
複製代碼

那假如小二在遍歷的時候不想判空又不想代碼拋出 NPE 錯誤,他該怎麼作呢?閉上你的大眼睛好好想想。web

嗯,報告,我想出來了,建議小二從數據庫中獲取姓名的時候返回長度爲 0 的列表,來表示未找到數據的狀況。代碼示例以下所示:數據庫

public class Null2Length0Demo {
    public static void main(String[] args) {
        List<String> names = getNamesFromDB();
        for (String name : names) {
            System.out.println(name);
        }
    }

    public static List<String> getNamesFromDB() {
        // 模擬此時沒有從數據庫獲取到對應的姓名。
        return Collections.emptyList();
    }
}
複製代碼

注:Collections.emptyList() 用於返回一個不可變的空列表,能理解吧?假如不能理解的話,我再寫一個返回可變的空列表的示例,你對比着感覺一下就理解了。微信

public class Null2Length0MutableDemo {
    public static void main(String[] args) {
        List<String> names = getNamesFromDB();
        for (String name : names) {
            System.out.println(name);
        }
    }

    public static List<String> getNamesFromDB() {
        // 模擬此時沒有從數據庫獲取到對應的姓名。
        return new ArrayList<>();
    }
}
複製代碼

new ArrayList<>() 返回的就是可變的,意味着你還能夠改變這個列表的元素,好比說增長,刪除是不可能的了,由於自己就沒有元素可刪。app

你看,Collections.emptyList()new ArrayList<>() 均可以替代 null,來減小打印列表時沒必要要的判空以及那個討厭的傢伙——NPE。性能

除了我這個想法以外,你還能想到其餘的解決方案嗎?來,再次閉上你的大眼睛,替小二想想,沒準你還能想到一個—— Java 8 新增的 Optional 類,一個容器類,能夠存聽任意類型的元素,若是值存在則
isPresent() 方法會返回 true;Optional 類提供了不少專業的方法而不用顯式進行空值檢查,從而巧妙地消除了 NPE。ui

來,先讀示例爲快!

public class Null2OptionalDemo {
    public static void main(String[] args) {
        Optional<List<String>> list = getNamesFromDB();
        list.ifPresent(names -> {
            for (String name : names) {
                System.out.println(name);
            }
        });
    }

    public static Optional<List<String>> getNamesFromDB() {
        boolean hasName = true;
        if (hasName) {
            String [] names = {"沉默王二""一枚有趣的程序員""微信搜索關注我"};
            return Optional.of(Arrays.asList(names));
        }
        return Optional.empty();
    }
}
複製代碼

看得不太懂?我來負責任地介紹一下,大家握個手。

假如數據庫中存在姓名,則使用 Optional.of() 對返回值進行包裝,從而返回一個 Optional 類型的對象。爲何不用構造方法呢,由於構造方法是 private 的(源碼以下所示)。

private Optional(T value) {
    this.value = value;
}
複製代碼

那爲何要用 Optional.of() 呢?嗯,good question。繼續上源碼。

public static <T> Optional<T> of(T value) {
    return new Optional<>(Objects.requireNonNull(value));
}
複製代碼

1)若是 value 爲 null,那麼 Objects.requireNonNull(value) 就會拋出 NPE(嗯哼,總歸是要碰面的,但好歹不用咱們程序員主動 check 了)。

2)若是 value 不爲 null,則經過 new 關鍵字建立正常的 Optional 對象。

假如數據庫中不存在姓名呢?使用 Optional.empty() 做爲返回值。來,繼續上源碼。

public static<T> Optional<T> empty() {
    @SuppressWarnings("unchecked")
    Optional<T> t = (Optional<T>) EMPTY;
    return t;
}
複製代碼

嗯哼,EMPTY 是什麼玩意?

private static final Optional<?> EMPTY = new Optional<>(null);
複製代碼

居然是 Optional 類的一個私有常量(static + final)。怎麼此刻個人腦子裏想起了安徒生先生的寓言故事——皇帝的新衣,嗯,甭管了,反正「底層終究是醜陋的」。

這樣的話,就可使用 Optional 對象的 ifPresent() 方法來判斷值是否存在,若是隻須要處理值存在的狀況,就可使用 Lambda 表達式的方式直接打印姓名。

list.ifPresent(names -> {
    for (String name : names) {
        System.out.println(name);
    }
});
複製代碼

有點簡單粗暴,對不對?但無論怎麼說,終於能夠在表象上和 null,NPE 說拜拜了,作人嘛,開心點。

好了,我親愛的讀者朋友,以上就是本文的所有內容了,能看到這裏的就是最優秀的程序員。原創不易,莫要白票,請你爲本文點贊個吧,這將是我寫做更多優質文章的最強動力。

若是你以爲文章對你有點幫助,請微信搜索「 沉默王二 」第一時間閱讀,回覆【666】【1024】更有我爲你精心準備的 500G 高清教學視頻(已分門別類),以及大廠技術牛人整理的面經一份,本文源碼已收錄在碼雲傳送門~

相關文章
相關標籤/搜索