使用注解写出更优雅的代码,以CFFU为例

前言

CFFU中有很多良好的代码实践,如果你追求更优雅、更健壮的代码,不妨学习一下CFFU中使用到的代码注解。

1. @CheckReturnValue

这个注解表示:被标记的方法(或类、包)返回的值必须被使用

如果调用了方法但没有使用返回值,静态代码分析工具(例如 Error Prone、SpotBugs 等)会提示警告或错误。

这样可以避免一些常见 bug ------ 比如你以为方法会修改对象状态,但实际上它返回了一个新的对象,而你却忽略了返回值。

应用场景

很多方法看起来会修改对象,但实际上 不会修改原对象,而是返回一个新对象

比如 String.concat

java 复制代码
String str = "hello";
str.concat(" world");  // ❌ 返回值被忽略,这行代码其实没做任何事情
System.out.println(str); // 仍然是 "hello"

正确写法应该是:

java 复制代码
String str = "hello";
str = str.concat(" world"); // ✅ 使用返回值
System.out.println(str); // "hello world"

如果开发者忘记处理返回值,程序逻辑就可能出错,而且编译器本身不会报错。

再来看下,CompletableFutureUtils#mSupplyAsync

java 复制代码
@CheckReturnValue(explanation = "should use the returned CompletableFuture; otherwise, prefer simple method `mRunAsync`")
@SafeVarargs
public static <T> CompletableFuture<List<T>> mSupplyAsync(Supplier<? extends T>... suppliers) {
    return mSupplyAsync(ASYNC_POOL, suppliers);
}

如果调用方忘记使用返回值,IDEA、其他静态检查工具会提示这里可能有bug。

函数式编程的思想要求函数没有副作用,大部分按照此思想编写的代码都应用加上这个注解。

2. 空指针相关注解

使用 @Nullable(以及配套的 @NonNull@NotNull)的好处是:

  1. 增强可读性:一眼就能知道值是否可能为空。
  2. 减少 bug:静态分析工具能提前发现空指针风险。
  3. 改进 API 设计:让调用者更清楚如何正确使用方法。
  4. 提升健壮性:避免线上出现 NPE。
  5. IDE 智能支持:自动提示 null-check。

实践中,常常默认所有返回值、参数不为空,Google的研究发现,只有5%的情况下需要使用空指针,所以推荐使用 ParametersAreNonnullByDefault 等注解。

如果你使用的 Java8 以上的版本,推荐使用 JSpecify,其目前已经成为标准了。

3. @CheckForNull

  • 表示:返回值、参数或字段 可能为 null

  • 但和 @Nullable 不同:

    • @CheckForNull 一般只用于返回值
    • 它强调:调用者必须主动检查 null,否则就可能出错。

4. @Blocking

org.jetbrains.annotations 提供了许多有用的注解,并且在IDE中可以轻松使用。

这个注解表示当前方法为阻塞方法,比如 CompletableFuture#join

5. @Contract

这个注解是一个非常好用的方法,推荐熟练使用。

@Contract 注解可以用于指定方法的输入输出关系和行为预期。通过这种方式,开发者可以更清晰地表达方法的意图,并帮助工具进行更深入的代码分析和错误检测。

@Contract 注解的常见属性包括:

  1. value:定义方法参数和返回值之间的关系。例如,@Contract("null -> false") 表示如果输入参数为 null,那么返回值一定是 false
  2. pure:一个布尔值,表示该方法是纯函数(pure function),即方法不修改任何状态或对象的属性,且返回值仅依赖于输入参数。

使用 @Contract 注解可以帮助开发人员在代码中捕获潜在的错误,并使代码更具可维护性。

比如 CompletableFutureUtils#allFailFastOf

java 复制代码
@Contract(pure = true)
public static CompletableFuture<Void> allFailFastOf(CompletionStage<?>... cfs)

这里的 pure 表示当不使用方法返回结果时,不会对现有代码作任何影响。

也就是说,你不需要知道方法内部实现,只需要关注方法返回结果即可。

需要注意的是,这里的 pure 并不是严格的纯函数,可以放宽为允许内部记录日志(如 logger.info)。也不能保证输入相同时,每次返回的结果都一样。

相关推荐
Java牛马2 小时前
SpringBoot Starter 依赖相关总结
java·spring·springboot·starter·自动装配·依赖
吴声子夜歌2 小时前
Java面试——Spring Cloud原理及应用(二)
java·spring cloud·面试
SomeB1oody2 小时前
【RustyML入门】6.3. 并行归约
开发语言·后端·机器学习·rust·教程
东小西2 小时前
【SAA实战】第 1 篇:ReactAgent 入门——先撸个"会调工具的助手"跑起来
java·人工智能·spring
Profile排查笔记3 小时前
指纹浏览器哪个好?从 Profile、代理、权限和自动化能力判断是否适合
前端·人工智能·后端·自动化
用户938515635073 小时前
用 AI 结对编程从 0 搭一个"单词后台管理系统":Next.js + Supabase + Drizzle + shadcn/ui 全记录
后端·postgresql·next.js
mqiqe3 小时前
AgentScope Java 2.0 协议集成全景解析:A2A、AG-UI、Agent Protocol 三大开放协议实战指南
java·开发语言·ui
脉动数据行情3 小时前
Java 实现台股 TWSE/TPEx 行情采集(个股 + K 线)
java·开发语言·twse·tpex·台股
爱学习的小邓同学4 小时前
Golang --- (1)第一个Golang程序
开发语言·后端·golang
小灰灰搞电子5 小时前
Rust+Slint 实现的“DNA双螺旋”加载动画源码分享
后端·rust·slint·加载动画