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

What is the purpose of @CompatibleWith annotation from Guava?

来自 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).

For example, Collection.contains(java.lang.Object) would be annotated as follows:

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:

这是 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 作为参数类型有什么好处?为什么他们在 getIfPresent 中使用了 @CompatibleWith 注释,而不是在 Cache 的 get 方法中?

getIfPresent 操作允许 object 类型的 "too broad" 是安全的(您不会从缓存中获得任何带有来自 getIfPresent(42) 的字符串键的内容)。另一方面,假设 get(Object, Callable) 允许 插入 错误类型的 object (例如 42 而不是字符串 "foo" ) 会损坏底层 collection,这就是为什么你有编译时检查不允许它。

话虽如此,这段代码:

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

很可能是错误的,像 Error Prone 这样的框架将其作为可能的错误发出信号是有意义的。

关于 "use Object not generic type in safe operations" 约定(不仅在 Guava 中使用,而且在 JDK collections 框架中使用)的更详细说明在 this old, but still relevant blog post "Why does Set.contains() take an Object, not an E?" 中进行了解释,你在哪里阅读:

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. Isn't this stupid and evil?

稍后回答标题中的问题:

The real difference is that add() can cause "damage" to the collection when called with the wrong type, and contains() and remove() cannot.

结论也有关系:

Static analysis plays an extremely important role in the construction of bug-free software.

这是有道理的,因为作者 Kevin Bourrillion 也是 Guava 的首席开发人员。