java core中缺少nullity注释
每种类型都有一个空状态.因此,在Optional<Integer>
中,提到的两种类型都具有空状态-是@NonNull Optional<@NonNull Integer>
吗?大概答案很简单:是的.
有一个"nullable optional"(如果有,请先停止并修复),并且optional的typearg为@NonNull
(不能有值为null
的optional.SOME).
然而,eclipse doesn't know that.此外,java核心类are not nullity annotated.
想必,您已经将类标记为"default to-everything is nonnull-",否则您需要对所有笨拙的对象加@NonNull
.因此,eclipse认为方法的返回类型是@NonNull Optional<@NonNull Integer>
.
然而,Optional.ofNullable
方法(在类java.util.Optional
中)只返回@WhoKnows Optional<@WhoKnows T>
-j.u.Optional类没有标记为"默认为所有非空",方法本身也没有用@NonNull
注释,因为java核心类根本没有这样的注释.因此,eclipse正在警告您,告诉您:嘿,Optional.ofNullable
可能返回null
(我们知道不会,但eclipse怎么会知道呢?),您只是逐字返回,但your方法promise 永远不会返回null
,所以这是一个潜在的问题.
如何使用nullity批注
您有一种方法可以让空值判断器(在您的例子中是eclipse)知道everything的空值状态.包括您正在使用的库,所以至少包括java.*
个.这意味着您需要一个称为"外部注释"的概念,可以说,这个文件"填补了java.*
和其他所有内容的空白".首先,它会列出java.util.Optional
中的ofNullable
静态方法应该被视为用@NonNull
注释.
如果没有这样一个系统,这将是一个悲惨的、悲惨的经历——在无效注释上走到一半,意味着你将得到无休止的警告.这会导致您删除警告(这会使功能变得毫无意义)或用@SuppressWarnings("null")
注释大多数方法,这也会使功能变得毫无意义.
我上一次判断是在很久以前,当时没有这样的文件或系统可用,但我相信eclipse至少添加了"外部注释"的概念.我会搜索web并try 查找包含所有/大部分java的EA文件.*API,并使用它.
Select 一边!
Optional
是将空状态提升到类型系统中的一种方法.
注释也是一种方法.
不要同时使用两者.
关于无效系统的有用事实
Optional
不向后兼容.以java.util.Map
的.get()
法为例.它当前返回V
.如果您认为正确答案是可选的,那么这个方法是不正确的,因为它应该返回Optional<V>
.然而,更改它是向后不兼容的,java极不可能做到这一点.因此,Optional
will never到达了他们的完美世界,在那里,Optional到处都被用作事实上的机制.
- 注释可以向后兼容,因此作为一个答案,它显然更优越.不幸的是,至少有9个相互竞争的基于注释的空值系统,它们的工作方式完全不同.例如,有些是基于类型使用的,有些不是.
- 大多数基于注释的框架没有
@PolyNull
概念(只有checkerframework有).这意味着它们都无法表示某些现有方法的空状态.
- Optional不能正确组合,没有poly null概念,也不能使其具有poly null,因此这是
Optional
永远无法在java中完全替换null
的另一个原因.
你还剩下什么
Nullity注释非常笨拙(未标准化,缺少外部注释文件).Optional
是一个白日梦(不能修改现有的API来使用它).那你现在的处境如何?
大多数情况下,只要接受null
就可以了.关闭基于注释的判断,停止对此类内容使用Optional
.
您现在可以做一些事情,而且java API已经在做一些事情,因为它完全向后兼容:
_Work on nicer APIs.
例如,看看java.util.Map
的javadoc.有computeIfAbsent
、getOrDefault
和其他一些方法,它们主要意味着您不需要任何基于类型的空值就可以使用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();
}
调用者不可能对此处可以和不可以为null的内容感到困惑.(您可能不需要全部3个,请考虑一下您的API设计).