简体   繁体   English

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

[英]What is the purpose of @CompatibleWith annotation from Guava?

From the documentation of com.google.errorprone.annotations.CompatibleWith : 来自com.google.errorprone.annotations.CompatibleWith的文档:

Declares that a parameter to a method must be "compatible with" one of the type parameters in the method's enclosing class, or on the method itself. 声明方法的参数必须与方法的封闭类中的一个类型参数“兼容”,或者与方法本身“兼容”。 "Compatible with" means that there can exist a "reference casting conversion" from one type to the other (JLS 5.5.1). “与...兼容”意味着可以存在从一种类型到另一种类型的“参考转换”(JLS 5.5.1)。

For example, Collection.contains(java.lang.Object) would be annotated as follows: 例如,Collection.contains(java.lang.Object)将注释如下:

 interface Collection<E> { boolean contains(@CompatibleWith("E") Object o); } 

To indicate that invocations of Collection.contains(java.lang.Object) must be passed an argument whose type is compatible with the generic type argument of the Collection instance: 要指示必须为Collection.contains(java.lang.Object)的调用传递一个类型与Collection实例的泛型类型参数兼容的参数:

Here is a usage from com.google.common.cache.Cache : 以下是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;
...

What is the benefit of having @CompatibleWith("E") Object instead of E as the type of the parameter? 使用@CompatibleWith("E") Object而不是E作为参数的类型有什么好处? And why did they use the @CompatibleWith annotation in the getIfPresent but not in the get method from Cache? 又为什么使用@CompatibleWith标注在getIfPresent但不是在get从缓存的方法?

It's safe for getIfPresent operation to allow objects of "too broad" type (you don't get anything from cache with string keys from getIfPresent(42) ). getIfPresent操作允许“太宽”类型的对象是安全的(你没有从缓存中获取任何来自getIfPresent(42)字符串键)。 On the other hand, for hypothetical get(Object, Callable) allowing inserting an object of wrong type (eg. 42 instead of a string "foo" ) would damage the underlying collection, that's why you have compile time checking won't allow it. 另一方面,假设get(Object, Callable)允许插入错误类型的对象(例如42而不是字符串"foo" )会损坏底层集合,这就是为什么你有编译时检查不允许它。

Having said that, this code: 话虽如此,这段代码:

Cache<String, Foo> cache = CacheBuilder.newBuilder()
// and later
Foo value = cache.getIfPresent(42);

is most probably wrong, and it makes sense for framework like Error Prone to signal that as a possible bug. 很可能是错误的,并且像Error Prone这样的框架有意义地表明这是一个可能的错误。

More detailed clarification about "use Object not generic type in safe operations" convention (which isn't used only in Guava, but also in JDK collections framework) is explained in this old, but still relevant blog post "Why does Set.contains() take an Object, not an E?" 关于“在安全操作中使用对象而非通用类型”约定(在Guava中不使用,但在JDK集合框架中也没有使用)的更详细说明在这个旧的但仍然相关的博客文章“为什么Set.contains”中有解释。拿一个物体,而不是一个E?“ , where you read: ,你在哪里读:

Why should code like the following compile? 为什么代码应该如下编译?

 Set<Long> set = new HashSet<Long>(); set.add(10L); if (set.contains(10)) { // we won't get here! } 

We're asking if the set contains the Integer ten; 我们问的是该集合是否包含整数十; it's an "obvious" bug, but the compiler won't catch it because Set.contains() accepts Object . 这是一个“明显的”错误,但编译器不会捕获它,因为Set.contains()接受Object Isn't this stupid and evil? 这不是愚蠢和邪恶吗?

and later answers the question in title: 然后回答标题中的问题:

The real difference is that add() can cause "damage" to the collection when called with the wrong type, and contains() and remove() cannot. 真正的区别在于,当使用错误的类型调用时, add()会导致集合“损坏”,而contains()remove()则不能。

The conclusion is also relevant: 结论也是相关的:

Static analysis plays an extremely important role in the construction of bug-free software. 静态分析在构建无bug软件中起着极其重要的作用。

Which makes sense, because the author, Kevin Bourrillion, is also lead developer of Guava. 这是有道理的,因为作者Kevin Bourrillion也是Guava的首席开发人员。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM