从com.google.errorprone.annotations.CompatibleWith文档中:
声明方法的参数必须与该方法的封闭类或方法本身的类型参数之一“兼容”。“与...兼容”表示可以存在从一种类型到另一种类型的“引用转换”(JLS 5.5.1)。
例如,对Collection.contains(java.lang.Object)进行如下注释:
interface Collection<E> { boolean contains(@CompatibleWith("E") Object o); }
为了指示必须向Collection.contains(java.lang.Object)的调用传递一个其类型与Collection实例的泛型类型参数兼容的参数:
这是com.google.common.cache.Cache的用法:
public interface Cache<K, V> {
V getIfPresent(@CompatibleWith("K") Object key);
V get(K key, Callable<? extends V> loader) throws ExecutionException;
...
拥有@CompatibleWith("E") Object
而不是E
作为参数类型的好处是什么?为什么他们在Cache 的方法中而不是@CompatibleWith
注释中使用注释?getIfPresent
get
对于getIfPresent
操作来说,允许“太宽”类型的对象是安全的(使用的字符串键从缓存中不会得到任何东西getIfPresent(42)
)。另一方面,由于假设get(Object, Callable)
允许插入错误类型的对象(例如,42
代替字符串"foo"
)会损坏基础集合,所以这就是为什么您在进行编译时检查时不允许这样做的原因。
话虽如此,这段代码:
Cache<String, Foo> cache = CacheBuilder.newBuilder()
// and later
Foo value = cache.getIfPresent(42);
这很可能是错误的,对于像“容易出错”这样的框架,将其表示为可能的错误是有意义的。
在此旧的但仍然相关的博客文章“为什么Set.contains(不仅在Guava中使用,而且在JDK集合框架中也没有使用)约定,对“在安全操作中使用对象不是通用类型”约定进行了更详细的说明。)拿一个物件,而不是E?” ,您在其中阅读:
为什么要像下面的代码那样编译?
Set<Long> set = new HashSet<Long>(); set.add(10L); if (set.contains(10)) { // we won't get here! }
我们要问集合中是否包含整数十;这是一个“明显的”错误,但编译器由于
Set.contains()
接受而无法捕获它Object
。这不是愚蠢和邪恶吗?
然后回答标题中的问题:
真正的区别在于,
add()
可以造成“伤害”到集合时,与错误的类型调用,contains()
而remove()
不能。
结论也很重要:
静态分析在构建无错误的软件中扮演着极其重要的角色。
这是有道理的,因为作者Kevin Bourrillion也是Guava的首席开发人员。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句