1. 程式人生 > 其它 >記一次線上環境空指標異常排查

記一次線上環境空指標異常排查

前言

現在,很多小夥伴都在日常開發中使用lambda表示式,我也經常用,我們線上環境的程式碼更是廣泛使用,而且我之前還給大家分享過一些常用的lambda表示式,因為lambda確實很好用,用起來也確實很方便,但是各位小夥伴在使用過程中一定要做好資料校驗,避免線上環境出現出現空指標異常,今天我們就來分享下我這一天排查線上環境發現的一個空指標異常(NPE),這個問題確確實實是那種你不遇到,你根本不知道的異常。話不多說,我們直接開始吧。

問題分析

我們先看這樣一段程式碼:

public static void main(String[] args) {
        TestVo testVo = new TestVo();
        List<TestVo> testVoList = Lists.newArrayList(testVo);
        Map<String, Integer> collectMap = testVoList.stream().collect(Collectors.toMap(TestVo::getName, TestVo::getAge));
        System.out.println(collectMap);
    }

這段程式碼沒有什麼複雜的業務邏輯,咋看沒有任何問題,我當初也是這麼想的,但是經過我的實際測試,以上程式碼有兩處潛在的空指標異常。

第一處大家應該都可以看出來,就是testVoList為空的時候,所以在日常開發i中,如果是從資料庫查出來的list,一定要做空指標判斷;

另一處我開始也沒看出來,直到我做了很多次測試以後,才發現這個隱藏的NPE。我們先說結論,toMap方法如果後一個引數(即TestVo::getAge,對應我們map的值)為空,整個lambda就會報空指標異常:

詳細分析異常,你會發現,toMap方法在執行過程中會呼叫merge方法,merge方法要求value不能為空:

所以各位小夥伴在以後的開發中一定要儘可能避免這兩種空指標異常的出現,對於第二種空指標可以通過下面這種方式避免:

Map<String, Integer> collectMap = testVoList.stream().collect(Collectors.toMap(TestVo::getName,
                t -> {
                    if (t.getAge() == null) {
                        return 0;
                    } else {
                        return t.getAge();
                    }
                }));

對於上面的程式碼,如果把age的型別改成int,就不會報錯,因為基本型別int的初始化是0。所以,這裡其實還隱含了第三種空指標異常,包裝類轉基本型別的空指標異常。

如果你的程式碼中有,包裝類轉成基本型別的情況,請務必做好空指標判斷,否則也是會有空指標異常的,比如像像下面這段程式碼:

Integer a = null;
int b = a;

直接執行,就是空指標異常:

所以,各位小夥伴在使用基本型別與包裝類的時候,一定要儘可能保持型別一致,如果用包裝類就都用包裝類,非要做轉換的話,就務必做好資料校驗。另外,由於基本型別和包裝類對java來說是兩種型別,所以下面的方法對java來說是兩個方法,也就是我們說的過載:

private void testInt(Integer i) {
    System.out.println(i + i);
}

private void testInt(int i) {
    System.out.println(i * i);
}

但這種過載對呼叫方來說是極其不友好的,我在我們線上環境還真的遇到過,呼叫哪個方法取決你傳的是基本型別還是包裝類(誰在實際開發中會關注這個?),所以各位小夥伴一定要避免類似這種方法過載,這種程式碼一旦出現問題,那就真的把你往死裡坑。

總結

作為一個後端開發人員,減少NPE錯誤是我們最基本的追求,所以各位小夥伴在實際開發過程中一定要儘可能避免,因為一旦發生NPE異常,不僅對使用者互動不夠友好,排查問題也不方便,而且從個人角度來說,不論你能力有多強,貢獻有多大,如果你開發的一個核心功能因為沒有做資料校驗,最後導致NPE異常,影響系統正常執行,那你怕要背上一個p1甚至p0工單,搞不好還會被開除,這樣你不覺得冤嗎?總之就是,日常開發過程中要盡一切可能避免NPE異常,不犯這種低階錯誤,你的職場發展才能走的更順利。