Guava的@CompatibleWith注释的目的是什么?

亚历山德鲁·塞维林(Alexandru Severin):

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注释中使用注释getIfPresentget

Xaerxess:

对于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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章