String
在Java中是不可变的。从广义上讲,下面的片段是“错误的”。
String s = "hello world!";
s.toUpperCase(); // "wrong"!!
System.out.println(s); // still "hello world!"!!!
尽管这样做是“错误的”,但代码的编译和运行可能会使许多初学者感到困惑,他们要么必须被告知错误是什么,要么通过查阅文档来自己找出答案。
阅读文档是理解API的一个基本部分,但我想知道是否可以通过额外的编译时检查来补充这一点。特别是,我想知道是否可以使用Java的注释框架来强制执行某些方法返回的值不会被忽略。然后,API设计器/库作者将在其方法中使用此注释来记录不应忽略的返回值。
一旦API得到了这个注释(或者可能是另一种机制)的补充,那么每当用户编写上面这样的代码时,它就不会编译(或者使用严厉的警告)。
所以这能做到吗,你会怎么做这样的事情呢?
附录:动机
显然,在一般情况下,Java应该允许忽略方法的返回值。方法的返回值,如List.add
(总是true
),System.setProperty
(以前的值),可能大多数情况下都可以被安全地忽略。
但是,也有许多方法的返回值不应被忽略。这样做几乎总是程序员的错误,或者不是API的适当使用。其中包括以下内容:
String
、BigInteger
等)返回操作结果,而不是对调用的实例进行变异。InputStream.read(byte[])
返回读取的字节数,不应假定为数组的整个长度)。目前,我们可以编写忽略这些返回值的代码,并让它们在没有警告的情况下编译和运行。静态分析检查器/bug查找器/样式增强器/etc几乎可以肯定地将这些标记为可能的代码气味,但如果可以通过API本身(可能通过注释)强制执行,则似乎是合适的/理想的。
一个类几乎不可能确保它总是被“正确地”使用,但是它可以帮助引导客户端正确使用它(参见:有效Java第2版,第58项:对于可恢复条件使用检查过的异常,对于编程错误使用运行时异常,以及项目62:记录每个方法引发的所有异常)。有一个注释来强制客户端不要忽略某些方法的返回值,并让编译器在编译时以错误或警告的形式强制执行它,这似乎与这种想法是一致的。
附录2:片段
以下是一次初步尝试,简洁地说明了我想要实现的目标:
@interface Undiscardable { }
//attachable to methods to indicate that its
//return value must not be discarded
public class UndiscardableTest {
public static @Undiscardable int f() {
return 42;
}
public static void main(String[] args) {
f(); // what do I have to do so this generates
// compilation warning/error?
System.out.println(f()); // this one would be fine!
}
}
上面的代码编译并运行良好(如ideone.com所示)。我怎样才能不这样做呢?如何将我想要的语义分配给@Undiscardable
发布于 2012-03-08 19:59:21
您还可以查看jsr305。它定义了一个@CheckReturnValue注释:
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.annotation.meta.When;
@Documented
@Target( { ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.TYPE,
ElementType.PACKAGE })
@Retention(RetentionPolicy.RUNTIME)
public @interface CheckReturnValue {
When when() default When.ALWAYS;
}
它与findbug兼容,并在某人忘记处理返回值时生成警告。
我必须说,我喜欢能够指导静态代码分析的注释。
发布于 2010-09-01 02:39:07
我不确定是否可行--尤其是以可移植的方式--但是看看罗马数字,用我们的Java (GitHub代码)来自禤浩焯·库恩。他使用注释处理 和Sun的javac
专用API通过访问源代码来进行替换,从而向Java添加罗马数字文字。
也许您可以使用类似的方法来:
请不要错过禤浩焯的帖子中的以下内容:
你也可能喜欢
参考文献
相关问题
发布于 2010-09-01 00:28:38
在一个问题中:您希望有一个类似于@Deprecated
的注释,它可以帮助编译器/IDE在调用方法时发出警告/错误,而不需要分配其结果?如果不修改Java源代码和编译器,就无法实现这一点。必须对特定的方法进行注释,编译器必须知道它们。在不修改源代码和/或编译器的情况下,您可以最大限度地创建一种IDE插件/设置,它可以识别情况并相应地生成错误/警告。
Update:您可以在它周围编写一个框架/插件,它相应地检查被调用的方法和错误。您只希望在运行时有可用的注释。您可以通过使用@Retention
(RetentionPolicy.RUNTIME)
注释注释来做到这一点。然后,您可以使用Method#getAnnotation()
来确定这个注释是否可用。下面是一个这样的框架如何完成这一工作的启动示例:
package com.example;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
public class Test {
public static void main(String[] args) throws Exception {
if (Test.class.getMethod("f", new Class[0]).getAnnotation(Undiscardable.class) != null) {
System.err.println("You should not discard the return value of f()!");
} else {
f();
}
System.out.println(f());
}
public static @Undiscardable int f() {
return 42;
}
}
@Retention(RetentionPolicy.RUNTIME)
@interface Undiscardable {}
不过,要让编译器完成这一任务,您必须做更多的工作。
https://stackoverflow.com/questions/3614150
复制相似问题