【问题标题】:Const correctness in Java using Annotations?使用注释的Java中的常量正确性?
【发布时间】:2011-02-06 09:29:32
【问题描述】:

是否存在允许我将 Java 方法注释为 @Const 的现有库,以便编译器(我假设使用 apt)在更新字段或调用非 @Const 方法时标记错误场地;并将参数注释为@Const,以便接受方法不能调用其任何非@Const 方法,或更新其任何字段?

(基本上,尝试使用注释向 Java 添加 const 正确性;上面的问题中没有涉及一些明显的细节,例如分配给/来自 @Const 类型的参数等)

我找到了这个:http://confluence.atlassian.com/pages/viewpage.action?pageId=182158080,但它似乎只作为 IDEA 的一部分提供。

根据下面的澄清请求,这里有示例代码来说明我的意思:

class Person {
  private String name;
  private String address;

  @Const public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  ... etc. for address
}

现在,如果我定义一个方法,例如:

void processPerson(@Const Person p)

p.getName() 这样的行在processPerson 中是可以的,因为getName 被标记为@Const 方法。但是从processPerson 中调用p.setName() 会被标记为错误。

请注意,这与final 有很大不同:如果参数被定义为final Person p,任何对p 的赋值都是非法的,但是修改p 所指的内容仍然是完全有效的(或者使用p.setName(...) 或者更直接地使用p.name = ...

【问题讨论】:

  • 您是否尝试为此目的使用final 关键字?它有什么问题?
  • 最终方法是不能被覆盖的方法。那是不同的。
  • 最后一个参数意味着方法不能重新分配引用;但它仍然可以修改参数引用的对象。这(a)不是我想要的,(b)完全没用(至少在我看来)。
  • @M,它并不是完全没用,但如果你写一些示例代码,也许会更容易理解你的意思?
  • 是的,你是对的。你真的可以在内部修改对象。我个人对此类任务使用无框架解决方案:如果它是集合,我使用Collection.unmodifireableList() 等包装它,如果它是我自己的类,我要么实现不允许在类本身中修改的逻辑,要么更好地使用方面包装对象。方面可以使用方面框架之一(如 AspectJ)或使用动态代理来实现。我理解您希望拥有能够自动执行此操作的框架,并祝您好运。

标签: java annotations constants


【解决方案1】:

【讨论】:

    【解决方案2】:

    看看Checker Framework,它基本上有检查器,试图通过可扩展的类型注释系统 [JSR-308] 检测软件缺陷 [JSR-305]。

    它有一个不变性检查器(实际上是 2 个),它允许您使用 @Mutable、@Immutable 和 @Readonly 等不变性注释来注释代码。此工具区分不可变实例和只读引用。

    喜欢这个框架并且主要将它用于空检查,但我正在尝试开始更多地使用不变性检查器和实习检查器。

    将参数注释为@Const,以便接受方法不能调用其任何非@Const 方法,或更新其任何字段?

    看起来像:

    void addFriend(@ReadOnly Friend friend) { this.friends.add(friend); }
    

    允许我将 Java 方法注释为 @Const,以便编译器(使用 apt 我假定)在更新字段或在字段上调用非 @Const 方法时将标记错误;和

    问题中的示例如下所示:

    public String getName(@ReadOnly Person this) {
      return name;
    }
    

    这里的@ReadOnly 表示接收者(正在调用其方法的this 实例)应该被修改。尽管有明显的额外参数,该方法仍然照常调用:

    @ReadOnly Person person = new Person();
    person.getName();
    

    【讨论】:

    • 这是完美的,谢谢!多年来一直在寻找这样的东西,很高兴终于在 Java 8 中拥有它。非常强大的东西,带有 Eclipse 插件以及 Maven、Ant、Gradle 等插件,供其他感兴趣的人使用。只有一个建议是,对于任何因功能重叠而感到困惑的人来说,IGJ 注释看起来比 Javari 检查器更具表现力。恕我直言,Javari 可能应该被忽略。 (还 - 编辑了正确方法上的接收器注释的答案。)
    【解决方案3】:

    我附议@AlexR 评论,这可以使用 AspectJ 来完成,类似以下内容:

    public aspect ConstAspect{
    declare warning : withincode(* *(..,@Const (*),.. ) ) : "Calling Const Method..";
    }
    

    这不符合您的要求,但我基本上想展示一种方法,在上述情况下,任何在参数上具有 @Const 的方法都带有警告标记。有了更好的连接点,所有关注点都可以标记为错误。

    【讨论】:

      【解决方案4】:

      const 在 C++ 中。 Java 显然是故意放弃它的。现在,在没有真正经验的情况下长大的人 const 认为这是个好主意。

      一旦您将一种方法标记为const,它就会像癌症一样传播,很快您就会发现自己几乎是const。最好有not-const

      完全没用。它只是在学术上吸引人,对实际程序中的任何人都没有帮助。

      【讨论】:

      • 这是非常非常有争议的。我在我的 C++ 程序中经常使用const,但我不记得它传播了。将 getter 标记为 const 并对访问运算符(如 operator[])进行 const 重载确实有助于防止意外修改对象。
      • 我认为 const 也很好(8 年的 C++ 经验)。关于传播 - 方法的异常规范怎么样?它确实像癌症一样传播,但 Java 开发人员设法忍受它。
      • const 像癌症一样传播是件的事情。 const 正确的内容越多,您的代码就越安全,不会被滥用。
      • @EliasVasylenko 我可以理解为什么从编码的角度来看它很烦人,因为它使签名看起来相当长。我认为方法参数应始终被视为const,除非明确标记为mutable。然后你可以通过改进设计让你的代码看起来更少冗长:)。
      • @Navneeth 绝对!我完全同意这一点。不过,在这个问题的背景下,我认为在想要选择一个合理的默认值和希望我们假设的注释处理器选择加入而不是选择退出之间存在张力。我个人会避免使用仅在特殊注释的 absence 时更改我的代码语义的系统。对于非 Java 语言,是的,我认为使用可变性关键字会是更好的选择。默认情况下,该字段是私有的和最终的,等等......
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多