Java中是否有不支持操作的注释?

13

在Java中,有没有任何注释可以将方法标记为不支持?例如,假设我正在编写一个实现java.util.List接口的新类。该接口中的add()方法是可选的,而且我在我的实现中不需要它们,因此我需要执行以下操作:

public void add(Object obj) {
   throw new UnsupportedOperationException("This impl doesn't support add");
}

不幸的是,在这种情况下,直到运行时才会发现实际上不支持此操作。

理想情况下,这应该在编译时捕获,并且这样的注释(例如 @UnsupportedOperation)将提示IDE向该方法的任何用户说:“嘿,您正在使用不受支持的操作”,就像使用 @Deprecated 标志Eclipse突出显示任何使用过时项的用法一样。


1
如果还没有的话,实际上应该有一个,只要基本的JDK类在接口中具有这个荒谬的“可选”操作概念。 - T.J. Crowder
我认为你实现了一个不需要 add() 方法的类,却还在使用 List,这很荒谬。你在这里做错了什么,但我没有足够的信息来判断是什么。 - Erick Robertson
2
@Erick :Java.util.List 的文档明确说明该操作是可选的。实现一个不支持 add() 的只读列表是有效的。 - Guillaume
2
@Erik 请参考java.util.Collections.unmodifiableList(),了解何时使用和接受此方法的示例。 - Jonathan
当您调用 add() 时,那个对象会做什么? - Erick Robertson
2
@Erik(来自Javadoc):“……尝试修改返回的列表,无论是直接还是通过其迭代器,都会导致UnsupportedOperationException。” - Jonathan
4个回答

11

尽管表面上看起来很有用,但实际上并没有太大帮助。你通常如何使用列表?我一般会像这样做:

List<String> list = new XXXList<String>();

已经有一个间接引用了,如果我调用list.add("Hi"),编译器怎么知道这个列表的实现不支持添加元素?

那么这样呢:

void populate(List<String> list) {
    list.add("1");
    list.add("2");
}

现在这更难了: 编译器需要验证所有对该函数的调用是否使用支持add()操作的列表。

所以,很抱歉,无法满足您的要求。


公允观点。但是,我希望编译器能够捕捉到类似您第一个示例的近乎直接的引用。第二个示例我承认比较棘手,但我相信静态代码分析工具应该能够处理您提到的间接引用情况。好吧,感谢您的回答! - Chris Knight
我同意这是可能的(例如Haskell等一些编译器)可以执行此类检查,基本上证明每种类型都在任何地方安全使用。但这是一个非常困难的问题,在这种情况下使用有限。只需小心您传递列表而不添加即可。 :-) - Jonathan
我们先不考虑编译器,那么集成开发环境怎么样呢?(这与@Nullable@NotNull注释并没有太大的区别) - bvdb

4

如果您熟悉AspectJ,您可以使用它来实现。您需要首先创建一个切入点,然后给出一个建议或声明错误/警告连接点以匹配此切入点。当然,您需要自己的@UnsupportedOperation注释接口。以下是有关此内容的简单代码片段。

// This the point-cut matching calls to methods annotated with your 
// @UnsupportedOperation annotation.
pointcut unsupportedMethodCalls() : call(@UnsupportedOperation * *.*(..));

// Declare an error for such calls. This causes a compilation error 
// if the point-cut matches any unsupported calls.
declare error: unsupportedMethodCalls() : "This call is not supported."

// Or you can just throw an exception just before this call executed at runtime
// instead of a compile-time error.
before() : unsupportedMethodCalls() {
    throw new UnsupportedOperationException(thisJoinPoint.getSignature()
        .getName());
}

我不熟悉AspectJ,它是否能够捕获对List的使用,这些使用可以追溯到可能/肯定引用了XXXList(其中XXXListadd()方法已注释为@UnsupportedOperation)? - Jonathan
AspectJ主要使用编译时织入。也就是说,在编译代码时,AspectJ的织入器会根据切面插入一些代码行。如果您能够使用我编写的切面编译列表类,它将正常工作。 - ovunccetin
谢谢,这看起来非常有趣,我一直想进一步研究AspectJ。然而,我看不出它如何解决使用具体对象接口的代码问题,比如Jonathan的第二个例子。 - Chris Knight

2

(2018)虽然在编译时可能无法检测到,但有一种替代方案,即IDE(或其他工具)可以使用注释来警告用户正在使用这样的方法。

实际上,这方面已经有一个票据:JDK-6447051

从技术角度来看,它不应该比检测对@NotNull@Nullable访问器的非法使用更难实现。


很遗憾,工单已关闭 :( - riddle_me_this


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接