1. 概述
本文将深入讲解如何使用 @Contract
注解。通过这个注解,我们可以为方法定义必须遵守的契约规则。该注解由 IntelliJ IDEA 的开发公司 JetBrains 推出,能让编辑器直接识别代码中调用方法时的潜在问题。
2. Maven 依赖配置
最新版本的 annotations
库可在 Maven 中央仓库 获取。 在 pom.xml
中添加依赖:
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>24.0.1</version>
</dependency>
3. value 属性详解
@Contract
注解包含两个属性:value
和 pure
。 value
属性用于描述方法输入与输出之间的约束关系,这是注解的核心功能,首次出现在 IntelliJ 14 版本。
3.1. 契约语法规则
契约由因果关系子句组成,格式为:"A -> B"。 表示当输入满足 A 时,输出必然是 B。例如 "_ -> null"
表示方法对任何输入都返回 null。
输入约束支持以下类型:
-
_
:任意值 -
null
:空值 -
!null
:非空值 -
true
:布尔值 true -
false
:布尔值 false
输出约束除支持上述类型外,还支持:
-
fail
:方法抛出异常 -
new
:返回新对象(必须非空且不同于堆中已有对象) -
this
:返回调用对象本身(不适用于静态方法) -
param1
,param2
:返回第1/2个参数的值
⚠️ new
、this
和 param1
关键字仅支持 IntelliJ 2018.2+ 版本。多个约束可组合使用,但需确保不冲突。
3.2. 编写第一个契约
先看简单示例:创建 Person
类,添加链式调用方法:
public class Person {
String name;
@Contract("_ -> this")
Person withName(String name) {
this.name = name;
return this;
}
}
无论输入什么,方法都返回对象本身,因此使用 @Contract("_ -> this")
是合理的。
再看复杂契约:字符串拼接方法,当第二个参数为 null 时返回 null,否则返回拼接结果:
@Contract("_, null -> null; null, _ -> param2; _, !null -> !null")
String concatenateOnlyIfSecondArgumentIsNotNull(String head, String tail) {
if (tail == null) {
return null;
}
if (head == null) {
return tail;
}
return head + tail;
}
契约解读:
- 第二参数为 null → 返回 null
- 第一参数为 null → 返回第二参数值
- 第二参数非空 → 返回非空结果
3.3. 代码检查效果
契约错误会导致两类问题:
- 契约语法错误
- 调用方出现不可达代码
通过 Code → Inspect Code 可触发检查:
示例1:错误契约
@Contract(" -> fail")
void doNothingWithWrongContract() {}
示例2:冗余代码检测
String concatenation = concatenateOnlyIfSecondArgumentIsNotNull("1234", "5678");
if (concatenation != null) { // 此条件永远为 true
System.out.println(concatenation);
}
检查结果:
Condition 'concatenation != null' is always 'true'
✅ 契约让 IntelliJ 能智能识别冗余的空值检查。此外,IntelliJ 会自动为标准库方法推断契约,例如为 isEmpty()
添加 @Contract("null->true")
。
4. pure 属性详解
pure
属性声明方法无可见副作用。 当纯函数的返回值未被使用时,可安全移除调用。注意:
- 控制台输出不算可见副作用
- 可能暴露其他线程状态的方法不能标记为 pure
示例:字符串替换操作
@Contract(pure = true)
String replace(String string, char oldChar, char newChar) {
return string.replace(oldChar, newChar);
}
可同时使用 value
和 pure
:
@Contract(value = "true -> false; false -> true", pure = true)
boolean not(boolean input) {
return !input;
}
⚠️ 截至 IntelliJ 2023.1,pure
属性暂无对应代码检查功能,默认值为 false
。
6. 总结
本文系统介绍了 @Contract
注解的使用方法。将其加入工具箱能显著提升代码质量,特别是通过 value
属性快速发现死代码。但需注意:该注解仅用于静态分析,对编译结果无影响。
完整代码示例见 GitHub 仓库