Objects.requireNonNull 方法说明
在寫代碼的時候,Idea經(jīng)常會提醒我們可以使用這個方法來進行參數(shù)非空檢查, 這個方法的源碼也非常簡單, 如下所示:
/*** Checks that the specified object reference is not {@code null}. This* method is designed primarily for doing parameter validation in methods* and constructors, as demonstrated below:* <blockquote><pre>* public Foo(Bar bar) {* this.bar = Objects.requireNonNull(bar);* }* </pre></blockquote>** @param obj the object reference to check for nullity* @param <T> the type of the reference* @return {@code obj} if not {@code null}* @throws NullPointerException if {@code obj} is {@code null}*/ public static <T> T requireNonNull(T obj) {if (obj == null)throw new NullPointerException();return obj; }這個方法是 Objects 類的一個靜態(tài)方法, Objects 類是一個 Java 靜態(tài)類, 里面包含了很多 Java 工具方法, 其方法都是靜態(tài)方法, 其類的說明文檔如下:
/*** This class consists of {@code static} utility methods for operating* on objects. These utilities include {@code null}-safe or {@code* null}-tolerant methods for computing the hash code of an object,* returning a string for an object, and comparing two objects.** @since 1.7*/ public final class Objects {... }可以看出, 這個類還包括了很多關(guān)于類操作的使用工具方法, 例如比較兩個類是否相等, 計算類的 Hash Code 等方法, 這個類以后有機會進行學(xué)習(xí)和介紹.
回到 requireNonNull() 這個方法, 其源碼實現(xiàn)非常簡單, 只是進行了一個簡單的判斷, 如果所要判斷的元素為 null, 則返回空指針異常 NullPointerException, 否則直接返回對應(yīng)的對象.
這看上去好像是一個多余的操作, 因為如果我們試圖去調(diào)用一個空對象的方法, 也會拋出 NullPointerException 運行時異常, 那么我們?yōu)槭裁匆啻艘慌e進行這樣的一次檢查呢? 這一問題在 StackOverflow 上有人進行了解答 Why should one use Objects.requireNonNull?.
看了他們的回答, 總結(jié)為以下幾點:
首先, 從這個方法的名稱可以看出, 這個方法使用的場景是, 我們使用一個對象的方法時, 正常的運行狀態(tài)應(yīng)該能保證這個對象的引用非空, 如果這個對象為空了, 那一定是其他某個地方出錯了, 所以我們應(yīng)該拋出一個異常, 我們不應(yīng)該在這里處理這個非空異常.
其次, 這里涉及到一個很重要的編程思想, 就是 Fail-fast 思想, 翻譯過來就是, 讓錯誤盡可能早的出現(xiàn), 不要等到我們很多工作執(zhí)行到一半之后才拋出異常, 這樣很可能使得一部分變量處于異常狀態(tài), 出現(xiàn)更多的錯誤. 這也是 requireNonNull 這個方法的設(shè)計思想, 讓錯誤盡早出現(xiàn). 使用這個方法, 我們明確的拋出異常, 發(fā)生錯誤時, 我們立刻拋出異常.
StackOverflow 中的一個回答舉了一個具體的例子來回答這個問題, 例如有下面這樣一個類:
public class Dictionary {private final List<String> words;private final LookupService lookupService;public Dictionary(List<String> words) {this.words = this.words;this.lookupService = new LookupService(words);}public boolean isFirstElement(String userData) {return lookupService.isFirstElement(userData);} }public class LookupService {List<String> words;public LookupService(List<String> words) {this.words = words;}public boolean isFirstElement(String userData) {return words.get(0).contains(userData);} }這里, 兩個類是包含的關(guān)系, 傳入的 List 參數(shù)沒有做非空檢查. 如果我們一不小心在 Dictionary 的構(gòu)造方法中傳入了 null, 如下所示:
Dictionary dictionary = new Dictionary(null); // exception thrown lately : only in the next statement boolean isFirstElement = dictionary.isFirstElement("anyThing");我們在構(gòu)造時沒有任何異常, 但是當我們調(diào)用方法時, 會拋出 NPE:
Exception in thread "main" java.lang.NullPointerExceptionat LookupService.isFirstElement(LookupService.java:5)at Dictionary.isFirstElement(Dictionary.java:15)at Dictionary.main(Dictionary.java:22)JVM 告訴我們, 在執(zhí)行 return words.get(0).contains(userData) 這條語句時, 發(fā)生了異常, 但是這個異常非常不明確, 從報錯信息來看, 有多種可能會導(dǎo)致這個異常發(fā)生, 是因為 words 為空, 還是 words.get(0) 為空? 或者兩者都為空? 這都是不明確的. 同時, 我們也無法確定是在這兩個類的哪個環(huán)節(jié)出了錯, 這些都是不明確的, 給我們程序 debug 造成了很大的困難.
然而, 當我們使用如下方式實現(xiàn):
public Dictionary(List<String> words) {this.words = Objects.requireNonNull(words);this.lookupService = new LookupService(words); }按照這種實現(xiàn)方式, 在我們執(zhí)行構(gòu)造方法時, 就會明確拋出錯誤.
// exception thrown early : in the constructor Dictionary dictionary = new Dictionary(null);// we never arrive here boolean isFirstElement = dictionary.isFirstElement("anyThing"); Exception in thread "main" java.lang.NullPointerExceptionat java.util.Objects.requireNonNull(Objects.java:203)at com.Dictionary.(Dictionary.java:15)at com.Dictionary.main(Dictionary.java:24)這樣我們進行 debug 時就明確很多, 少走很多彎路.
除此之外, 這個方法的作用也是一個明確和不明確的區(qū)別, 使用這個方法表示我們明確進行了這個判斷, 其實與我們自己使用 if-else 進行判斷是一樣的, 只是這個工具類簡化了這樣的操作, 讓我們的代碼看上去更加簡潔, 可讀性更強.
此外, requireNonNull 方法有一個重載方法, 可以提供一個報錯信息, 以供我們 debug 的時候顯示. 我們使用這個引用的時候, 應(yīng)當保證非空, 如果不然, 會拋出異常告訴我們其他地方出錯了, 這里出現(xiàn)了空指針異常. 這個方法重載的實現(xiàn)如下:
/*** Checks that the specified object reference is not {@code null} and* throws a customized {@link NullPointerException} if it is. This method* is designed primarily for doing parameter validation in methods and* constructors with multiple parameters, as demonstrated below:* <blockquote><pre>* public Foo(Bar bar, Baz baz) {* this.bar = Objects.requireNonNull(bar, "bar must not be null");* this.baz = Objects.requireNonNull(baz, "baz must not be null");* }* </pre></blockquote>** @param obj the object reference to check for nullity* @param message detail message to be used in the event that a {@code* NullPointerException} is thrown* @param <T> the type of the reference* @return {@code obj} if not {@code null}* @throws NullPointerException if {@code obj} is {@code null}*/ public static <T> T requireNonNull(T obj, String message) {if (obj == null)throw new NullPointerException(message);return obj; }例如, 我們在 Android 中可以按照如下方式使用:
String username = Objects.requireNonNull(textInputLayoutUsername.getEditText(), "TextInputLayout must have an EditText as child").getText().toString();這是一個從 TextInpuLayout 獲取用戶輸入內(nèi)容的方法, 通常使用 TextInputLayout 包裹一個 EditText 來接收用戶輸入, 因此我們需要通過 TextInputLayout 的 getEditText() 方法來獲取對應(yīng)的 EditText, 如果我們布局有問題, 則該方法可能返回 null, 因此我們可以通過上述方法, 拋出一個明確異常, 如果運行時出現(xiàn)問題, 我們也可以很快知道是因為我們 TextInputLayout 無法獲取 EditText 而出錯的.
總結(jié)
以上是生活随笔為你收集整理的Objects.requireNonNull 方法说明的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Maven搭建Nexus私服
- 下一篇: 单片机外部中断实验C语言程序,STC89