對於 Java 參數傳入 null 判斷思考

版權聲明:本文章原創於 RamboPan ,未經允許,請勿轉載。

對於 Java 參數傳入 null 判斷思考


最近重溫了《Effective Java》之後,在日常工作中寫代碼時感覺也會慢一點,多一點思考這樣是不是比較合理。

在一個常見的情況下遲疑了下:在定義方法時,經常需要傳入非基本類型的參數。

	//定義一個簡單的類
	class Hello{
		public void say(){
			System.out.print("Hello");
		}
	}

	//類似這種情況,需要傳入一個對象進行它的操作
	public void test01(Hello hello) {
		hello.say();
	}

按理說我們會在這裏進行一個判斷,判斷是否是空,以防我們在後續使用它的方法時出現空指針。就像這樣進行一次判斷。

	//類似這樣的情況,傳一個簡單的參數
	//對字符進行判斷一下,如果無效就不進行下一步操作
	public void test01(Hello hello) {
		if(hello == null){
			……
			return;
		}
		hello.say();
	}

一:按照一些編程書中的意見,我們最好不要做這些容錯機制,如果是第一次調用該方法時,參數傳入錯誤就直接報錯,而不是後面發現沒有輸出 “Hello” 這個字符的時候再來尋找哪裏的問題,這樣就減少了調試的成本。

二:但是這樣一想,要是這段代碼自己測着沒什麼問題,其他懂代碼的同事用了之後肯定也會懂。但如果這段代碼在你自己的程序裏,其他應用傳入錯誤參數時,讓你的程序崩潰了,雖然是別人的問題,但是你說是你慌一點還是別人慌一點 …… 🙃

所以感覺這還是要區分場景的,比如在前一種情況下,就是需要直接把問題暴露出來,而在後一種情況,類似於需要保證程序的健壯性,那麼還是需要做容錯的處理。


在寫一個工具類的時候想到有些 Java 框架,在內部使用時,就進行了非空判斷的操作。
比如 RxJava 中有個判斷工具。

	//如果不爲空則直接返回該對象
	public static <T> T checkNull(T t){
		if(t == null)
			throw new NullPointerException("空指針啦,親");
			
		return t;	
	}
	
	//這樣寫也是可以的,只是在沒法嵌套在其他函數參數中。
	public static <T> void checkNull(T t){
		if(t == null)
			throw new NullPointerException("空指針啦,親");
	}

	//======================= 示範 ===================

	//定義一個簡單的類
	class Hello{
		public void say(){
			System.out.print("Hello");
		}
	}

	//類似這種情況,需要傳入一個對象進行它的操作
	public void test01(Hello hello) {
		hello.say();
	}

	//這種是使用帶返回的 checkNull ,可以進行嵌套使用
	public void checkNull01(){
		Hello hello = new Hello();
		test01(checkNull(hello));
	}

	//這種是不帶返回的 checkNull ,不能進行嵌套使用,就是多了一行 …… 
	public void checkNull02(){
		Hello hello = new Hello();
		checkNull(hello);
		test01(hello);
	}

其實這種的好處就是在調試期間,如果出錯的話,肯定會第一時間找到出錯位置,就是類似上面說的第一種情況。

既然要做這種判斷非空的工具,那就做一個通用的方法,再做幾個簡單封裝的方法,是常規思路嘛。比如這裏我們可以加入需要的 Exception 類型,出錯的 String 提示,大概就要這樣調用效果。

	//定義一個簡單的類
	class Hello{
		public void say(){
			System.out.print("Hello");
		}
	}

	//測試
	public void test01() {
		Hello hello = new Hello();
		hello = checkNull(hello,NullPointerException.class,"空指針啦,親");
	}

第一個是需要檢測的對象,第二個是異常的類型,第三個就是提示語。
雖然我們這裏是只檢測是否爲空,按理說就應該拋空指針,你還要拋什麼其他的花樣 ?好奇的你肯定會問。

雖然直觀上是空指針,但是如果你在一個方法中對成員變量進行判斷,可能這個對象已經完成使命,執行了一些釋放的操作,成員變量已經被置空,那麼此時如果拋出 IllegalStateException 加上說明,比如 “ xx 已經被釋放了,請檢查狀態 ” 是不是更合適一點 ?所以還是靈活一點好。(畢竟泛型帥嘛,啊哈哈哈)

	//通用的接口
   public static <T> T checkNull(T t,Class<? extends Exception> eClazz,String msg){
        if(t == null){
            try {
                Constructor<? extends Exception> eCons = eClazz.getDeclaredConstructor(String.class);
                eCons.setAccessible(true);
                throw eCons.newInstance(msg);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
        return t;
    }

第一個參數是對於對象的判斷,第二個參數是採用泛型限定了 Exception 類及其子類,第三個參數針對錯誤的提示。

因爲前面的一些限定,所以後續的四個 Exception 中沒有再次拋出(比如大部分 Exception 子類,都有單個 String 的構造函數;雖然都是 public,此處也加上了訪問權限設置 ,所以忽略了這些情況)

編譯器沒有提示錯誤,彷彿沒有什麼不對,於是編譯跑起來試試,畢竟看着對和跑得起來是兩回事 …… 果然,編譯的途中出錯了(男人的直覺 😂)。

錯誤: 未報告的異常錯誤CAP#1; 必須對其進行捕獲或聲明以便拋出
其中, CAP#1是新類型變量:
CAP#1從? extends Exception的捕獲擴展Exception

說實話這個真的有點摸不着的頭腦,感覺邏輯上也沒錯啊,這究竟是怎麼肥事 …… 🤔

直接搜這個錯誤,還沒什麼參考,於是把幾個關鍵字都試了一下,看了別人的意見有點啓發。

Exception 分爲 編譯期的錯誤 與 運行時的錯誤 ,像 NullPointerException 這種就屬於運行時的錯誤,如果是 Exception 、 IOException 這種一定是需要自己處理了之後才能通過編譯的。

處理的方式就是兩種,正如報錯的提示:必須對其進行捕捉或者聲明以便拋出。

	//聲明:當其他方法調用此方法時需要它處理異常
	public void say() throws Exception {
		……
	}

	//捕捉:這個方法內部已經處理了,其他方法調用時不需要處理
	public void say(){
		try{
			……
		}catch(Exception e){
			……
		}
	}

現在我們來做個試驗,測試下是不是正如我們猜想的那種:這裏需要拋出一個 RuntimeException ,而不是 Exception。

	public void test01(){
		throw new Expcetion("試一試,好像不行");
	}

提示: Unhandled Exception: java.lang.Exception

如果我們按照兩種處理異常的方式處理一下,那麼就沒有問題了,也能順利通過編譯。

當然,這不是我們要的結果,此處我們想要的就是在運行時,遇到問題直接拋出(就是這麼剛)。

那我們把泛型限定條件改一下: Class<? extends Exception> 改爲 Class<? extends RuntimeException>

然後再進行編譯就沒問題了,當然 Constructor 對應的泛型限定符也需要對應的修改。


分享下平時思考的筆記,如有不對之處,歡迎指出討論。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章