了解纯方法@Contract

时间:2019-05-31 15:35:31

标签: java intellij-idea

我最近从Eclipse切换到IntelliJ,并迅速引入了@Contract批注,我立即喜欢这些批注背后的概念(“在调用已批注方法的方法中发现问题” )。我的第一个想法是使用它们来定义getterutility方法,而pure注释参数似乎符合要求:

  

pure属性适用于不更改其对象状态而仅返回新值的方法。如果未使用其返回值,则除非方法调用引发异常(不将异常视为副作用),否则删除其调用不会影响程序状态或更改语义。

不过,我对上述内容的真正含义感到困惑。

  • 提到的对象是否引用通过方法参数或类字段传递的对象?再者,什么可以作为更改,更改对象引用,内容或可能同时包含两者?

  • 在纯方法内调用更改这些对象的状态的方法是否违反合同?类似于调用构造函数的构建器方法。

  • 什么时候客观地认为将方法标记为纯净的最佳实践?我知道这似乎是一个主观的问题,但必须建立有关何时执行此操作的社区准则(可以参考)

2 个答案:

答案 0 :(得分:1)

一个例子可能正在澄清。考虑以下代码:

class X {
  public void main(String[] ss) {
    ss[0].toUpperCase(java.util.Locale.ENGLISH);
  }
}

String.toUpperCase()调用不会更改调用的对象ss[0],也不会更改提供的参数java.util.Locale.ENGLISH。它返回一个新对象,但是该对象未在代码中使用。该调用不会更改程序中正在使用的任何对象的状态。因此,删除该调用不会更改程序的行为。 (严格来说,它的运行速度会稍快一些,但这不被视为语义上的相关更改。)

请注意,使用空数组调用main方法时,它将引发异常。删除呼叫后,将不会发生。但是出于@Contract注释的目的,异常不被视为副作用。可以将异常视为返回值的一种。

因此String.toUpperCase()方法可以注释为纯方法。在IntelliJ IDEA中,许多地方都专门处理了纯方法。例如,如果未使用的变量是通过纯方法初始化的,则快速修复程序“知道”可以在删除变量时安全地删除初始化程序。

字母通常是纯净的,void方法通常不是纯净的。但是也有例外,例如junit.framework.Assert.fail()voidpure,因为它没有副作用。据我所知,尚无官方指南。

答案 1 :(得分:1)

  

提到的对象是否引用通过方法参数或类字段传递的对象?

调用该方法的实例的传递对象和字段。

  

此外,什么才是更改,更改对象引用,内容或可能两者兼而有之?

两者。任何更改均符合资格。

  

在纯方法内调用更改这些对象的状态的方法是否违反合同?

是的。杂质具有传染性:从另一种方法调用非纯方法也会使后者成为非纯方法。

关键部分是这样:

  

如果未使用其返回值,则除非方法调用引发异常(不将异常视为副作用),否则删除其调用不会影响程序状态或更改语义。

除了例外之外,另一种查看方式是:只要内联该方法不会改变程序的语义,该方法就是纯净的。