Lombok @SneakyThrows 注解:简化异常操作

一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/

截止目前, 星球 内专栏累计输出 72w+ 字,讲解图 3103+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2400+ 小伙伴加入学习 ,欢迎点击围观

Lombok @SneakyThrows 注解Lombok @SneakyThrows 注解

大家好,我是小哈~

本小节中,我们来学习 Lombok 库中的 @SneakyThrows 注解。

什么是 @SneakyThrows ?

@SneakyThrows 用来 “偷偷地” 抛出检查型异常(checked exception),而无需显式地在方法签名中声明 throws 或者使用 try-catch。对于需要捕获或声明的异常,@SneakyThrows 注解可以让方法绕过这一步。

示例代码

为了方便你理解它的作用,先来看一段示例代码:

import java.io.UnsupportedEncodingException;

/**
 * @author: 犬小哈
 * @date: 2024/11/5 23:09
 * @version: v1.0.0
 * @description: TODO
 **/
public class SneakyThrowsExample {

    /**
     * 字节转字符串,且指定了字符编码为 UTF-8
     * @param bytes
     * @return
     */
    public static String utf8ToString(byte[] bytes) {
        try {
            return new String(bytes, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) {
        System.out.println(utf8ToString("犬小哈教程".getBytes()));
    }
}

new String(bytes, "UTF-8") 需要显示的进行 try-catch 异常捕获,或者如下所示,通过 throws 将异常抛出去,让调用者去处理:

    /**
     * 字节转字符串,且指定了字符编码为 UTF-8
     * @param bytes
     * @return
     */
    public static String utf8ToString(byte[] bytes) throws UnsupportedEncodingException {
        return new String(bytes, "UTF-8");
    }

有了 Lombok 的 @SneakyThrows 注解后,代码就可以精简成下面这样:

import lombok.SneakyThrows;

/**
 * @author: 犬小哈
 * @date: 2024/11/5 23:09
 * @version: v1.0.0
 * @description: TODO
 **/
public class SneakyThrowsExample {

    /**
     * 字节转字符串,且指定了字符编码为 UTF-8
     * @param bytes
     * @return
     */
    @SneakyThrows
    public static String utf8ToString(byte[] bytes) {
        return new String(bytes, "UTF-8");
    }

    public static void main(String[] args) {
        System.out.println(utf8ToString("犬小哈教程".getBytes()));
    }
}

在上面的代码中,方法中没有主动 try-catch 异常,也没有在方法签名中声明 throws ,而是在方法上添加了@SneakyThrows 注解,此注解会在编译期自动将抛出异常的工作做好,从而让开发者在代码中避免显式的 try-catch 块或 throws 声明。

为了验证这一点,可以看看 /target/classes 文件夹中编译后的代码,如下:

查看 @SneakyThrows 编译后的代码查看 @SneakyThrows 编译后的代码

优缺点

  • 优点

    • 减少了方法签名中的异常声明,保持代码简洁。

    • 避免了过多的样板代码(如 try-catch 块)。

    • 在某些情况下,提升了代码的可读性,尤其是对于 Lambda 表达式,示例代码如下:

      List<String> list = Arrays.asList("file1.txt", "file2.txt");
      list.forEach(@SneakyThrows file -> {
          Files.readAllLines(Paths.get(file));
      });
      
  • 缺点

    • 可读性与维护性:尽管简洁,@SneakyThrows 可能会降低代码的可读性,特别是对于团队开发来说,后续维护人员需要了解注解的行为及其影响。
    • 隐式异常抛出@SneakyThrows 隐藏了异常抛出的细节,可能导致程序在运行时抛出未经预料的异常,增加了调试的复杂性。
    • 错误处理:这种 “偷懒” 的方式可能导致开发者忽视良好的错误处理实践。如果一个方法默默抛出异常,调用者在使用时无法有效地处理异常。

何时应慎用?

在生产环境中,@SneakyThrows 应该谨慎使用。虽然它减少了样板代码,但也容易掩盖程序的潜在问题。对于关键系统,显式声明异常可以帮助程序员更好地理解代码的边界和行为。

例如,在设计公共 API 时,使用 @SneakyThrows 可能会使接口使用者难以预料方法可能抛出的异常类型。最好在这种情况下显式声明异常,确保代码的透明度和文档性。

结语

@SneakyThrows 是一个便利但有争议的工具,它可以显著减少代码量,提高开发效率,但也容易导致代码不够直观。在日常开发中,建议在清楚其行为及影响的前提下使用它。适度使用 @SneakyThrows,在适当的场景下,它是提升代码简洁度的好帮手;但在需要严格控制异常处理的地方,显式声明和处理异常仍然是更好的选择。