首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用注释确保方法返回的值不被丢弃。

使用注释确保方法返回的值不被丢弃。
EN

Stack Overflow用户
提问于 2010-09-01 00:14:41
回答 6查看 12K关注 0票数 34

String在Java中是不可变的。从广义上讲,下面的片段是“错误的”。

代码语言:javascript
运行
复制
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的适当使用。其中包括以下内容:

  • 方法对不可变类型(例如,StringBigInteger等)返回操作结果,而不是对调用的实例进行变异。
  • 方法的返回值是其行为的关键部分,不应被忽略,但人们有时也会这样做(例如,InputStream.read(byte[])返回读取的字节数,不应假定为数组的整个长度)。

目前,我们可以编写忽略这些返回值的代码,并让它们在没有警告的情况下编译和运行。静态分析检查器/bug查找器/样式增强器/etc几乎可以肯定地将这些标记为可能的代码气味,但如果可以通过API本身(可能通过注释)强制执行,则似乎是合适的/理想的。

一个类几乎不可能确保它总是被“正确地”使用,但是它可以帮助引导客户端正确使用它(参见:有效Java第2版,第58项:对于可恢复条件使用检查过的异常,对于编程错误使用运行时异常,以及项目62:记录每个方法引发的所有异常)。有一个注释来强制客户端不要忽略某些方法的返回值,并让编译器在编译时以错误或警告的形式强制执行它,这似乎与这种想法是一致的。

附录2:片段

以下是一次初步尝试,简洁地说明了我想要实现的目标:

代码语言:javascript
运行
复制
@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

EN

回答 6

Stack Overflow用户

发布于 2012-03-08 19:59:21

您还可以查看jsr305。它定义了一个@CheckReturnValue注释:

代码语言:javascript
运行
复制
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兼容,并在某人忘记处理返回值时生成警告。

Guavas使用它:http://code.google.com/p/guava-libraries/source/browse/guava/src/com/google/common/base/Splitter.java

我必须说,我喜欢能够指导静态代码分析的注释。

票数 13
EN

Stack Overflow用户

发布于 2010-09-01 02:39:07

我不确定是否可行--尤其是以可移植的方式--但是看看罗马数字,用我们的Java (GitHub代码)来自禤浩焯·库恩。他使用注释处理 Sun的javac专用API通过访问源代码来进行替换,从而向Java添加罗马数字文字。

也许您可以使用类似的方法来:

  • 在源代码中查找对带注释的方法的调用
  • 检查是否指定了结果(海事组织将不容易)
  • 生成编译器警告(如果不是)

请不要错过禤浩焯的帖子中的以下内容:

你也可能喜欢

参考文献

相关问题

票数 8
EN

Stack Overflow用户

发布于 2010-09-01 00:28:38

在一个问题中:您希望有一个类似于@Deprecated的注释,它可以帮助编译器/IDE在调用方法时发出警告/错误,而不需要分配其结果?如果不修改Java源代码和编译器,就无法实现这一点。必须对特定的方法进行注释,编译器必须知道它们。在不修改源代码和/或编译器的情况下,您可以最大限度地创建一种IDE插件/设置,它可以识别情况并相应地生成错误/警告。

Update:您可以在它周围编写一个框架/插件,它相应地检查被调用的方法和错误。您只希望在运行时有可用的注释。您可以通过使用@Retention (RetentionPolicy.RUNTIME)注释注释来做到这一点。然后,您可以使用Method#getAnnotation()来确定这个注释是否可用。下面是一个这样的框架如何完成这一工作的启动示例:

代码语言:javascript
运行
复制
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 {}

不过,要让编译器完成这一任务,您必须做更多的工作。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3614150

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档