我想為值容器提供一些訪問器(即引擎蓋下的 java.lang.Map)。
在實作這樣的訪問器時
public Optional<Integer> getSomeValueThatMayBeNullOrAnInteger() {
Integer nullable = this.get("keyToANullableInteger", Integer.class); // is casting to given Class
return Optional.ofNullable(nullable);
}
... ' ofNullable ' 被標記為'不安全的空型別轉換'。
為什么是這樣?引數 ofNullable 沒有標記為@NonNull。是不是因為使用了empty()或of()并且 of() 正在檢查 NonNull?這是一個 Eclipse 錯誤,因為在檢查可能性時會忽略empty()嗎?
有人可以向我解釋一下,也許可以告訴我,如果有另一種方法可以解決這個警告,比如使用@SuppressWarnings("null")。謝謝
uj5u.com熱心網友回復:
java核心中缺少無效注釋
每種型別都有無效狀態。因此,在 中Optional<Integer>,提到的兩種型別都具有無效狀態-是@NonNull Optional<@NonNull Integer>嗎?大概答案是微不足道的:是的。
擁有一個“可為空的可選”是沒有意義的(如果你有這些,請先停止并修復它),并且可選的 typearg 是微不足道的@NonNull(你不能有一個值為 的 Optional.SOME null)。
但是,日食不知道。此外,java 核心類不是 nullity annotated。
據推測,您已將您的課程標記為“默認為 -everything is nonnull-”,否則您需要@NonNull對所有難以處理的內容進行標記。因此,eclipse 認為你的方法的回傳型別是@NonNull Optional<@NonNull Integer>.
但是,Optional.ofNullable方法(在 class 中java.util.Optional)只是回傳@WhoKnows Optional<@WhoKnows T>- juOptional 類沒有標記為“默認為非空的所有內容”,方法本身也沒有注釋,@NonNull因為 java 核心類根本沒有這樣的注釋。因此,eclipse 警告你,告訴你:嘿,Optional.ofNullable可能會回傳null(我們知道它不會,但 eclipse 怎么知道呢?),你只是逐字回傳,但你的方法承諾永遠不會回傳null,所以這是一個潛在的問題。
如何使用無效注釋
您需要一種方法讓您的無效檢查器(在您的情況下為 Eclipse)知道所有內容的無效狀態。包括您正在使用的庫,因此,至少包括java.*. 這意味著您需要一個稱為“外部注釋”的概念 - 一個“填補空白”的檔案,可以這么說,java.*以及其他所有內容。對于初學者,它會列出ofNullable靜態方法 injava.util.Optional應被視為使用 注釋@NonNull。
如果沒有這樣的系統,那將是一種悲慘、悲慘的體驗——在無效注釋上半途而廢意味著你會得到無窮無盡的警告,就像你現在得到的警告一樣。引導您洗掉警告(這會使功能變得毫無意義)或注釋您的大多數方法,@SuppressWarnings("null")這也會使功能變得毫無意義。
我最后一次檢查是很久以前的事了,沒有這樣的檔案或系統可用,但我相信 eclipse 至少添加了“外部注釋”的概念。我會在網上搜索并嘗試找到一個至少包含所有/大部分 java.* API 的 EA 檔案并使用它。
選邊!
Optional是一種將無效狀態提升到型別系統中的方法。
注釋也是一種方法。
不要同時使用兩者。
關于無效系統的有用事實
Optional不向后兼容。采取java.util.Map的.get()方法。它目前回傳V. 如果你覺得 Optional 是正確的答案,那么這個方法是不正確的,因為它應該回傳Optional<V>。但是,更改它是向后不兼容的,Java 極不可能做到這一點。因此,Optional永遠不會到達他們的完美世界,其中 Optional 到處都被用作事實上的機制。- 注釋可以向后兼容,因此作為答案顯然更勝一籌。不幸的是,至少有 9 個相互競爭的基于注釋的無效系統,它們的作業方式都大不相同。例如,有些是基于型別使用的,有些則不是。
- 大多數基于注釋的框架沒有
@PolyNull概念(只有 checkerframework 有)。這意味著它們都無法代表某些現有方法的無效狀態。 - Optional 沒有正確組合并且沒有 poly null 概念并且不能擁有它,所以這是另一個原因
Optional將永遠無法null在 java 中完全替換。
這會讓你在哪里
Nullity 注釋很笨重(沒有標準化,缺少外部注釋檔案)。Optional是一個白日夢(現有的 API 無法修改以使用它)。那么,這讓你何去何從?
大多數情況下,只要接受null就可以了。關閉基于注釋的檢查,停止使用Optional這樣的東西。
您現在可以做一些事情,而 java API 已經在做一些事情,因為它完全向后兼容:
_使用更好的 API。
例如,看看 的 javadoc java.util.Map。有computeIfAbsent,getOrDefault和其他一些方法主要意味著您根本不需要任何基于型別的 null 來使用 Map 而不必打擾null. 例如,您不必撰寫以下代碼:
Map<String, List<String>> example = ...;
List<String> list = example.get(key);
if (list == null) {
list = new ArrayList<>();
example.put(key, list);
}
list.add("Test");
相反,您可以只寫:
Map<String, List<String>> example = ...;
example.computeIfAbsent(key, k -> new ArrayList<>()).add("Test");
你不必寫:
Map<String, Integer> example = ...;
int v = 0;
// 2 calls - ugly
if (example.containsKey(key)) v = example.get(key);
// or:
Integer vRaw = example.get(key);
if (vRaw != null) v = vRaw.intValue();
你可以只寫:
Map<String, Integer> example = ...;
int v = example.getOrDefault(key, 0);
您可以將相同的原則應用于您撰寫的代碼。例如:
public int getSomeValue(int defaultValue) {
Integer nullable = this.get("keyToANullableInteger", Integer.class);
return nullable == null ? defaultValue : nullable.intValue();
}
public Integer getSomeValueOrNull() {
return this.get("keyToANullableInteger", Integer.class);
}
public int getSomeValue() {
Integer n = this.get("keyToANullableInteger", Integer.class);
if (n == null) throw new NullPointerException("key not present in data store");
return n.intValue();
}
呼叫者不可能對這里什么可以和不可以為空感到困惑。(您可能不需要全部 3 個,請考慮一下您的 API 設計)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/487728.html
