Skip to content

@SneakyThrows

YellowStar5 edited this page Aug 1, 2019 · 1 revision

@SneakyThrows

大胆抛出以前没有人抛出的已检查异常!

概览

@SneakyThrows 可用于偷偷抛出已检查的异常,而无需在方法的 throws 子句中实际声明这一点。当然,应该谨慎使用这种有争议的能力。 lombok生成的代码不会忽略,包装,替换或以其他方式修改抛出的已检查异常;它只是欺骗了编译器。在JVM(类文件)级别上,无论方法的throws子句如何,所有检查与否的异常都可以被抛出,这就是SneakyThrows工作的原理。

当你想要选择退出已检查的异常机制时,常见的用例围绕两种情况:

  • 一个不必要的严格接口,例如 Runnable - 无论是否传播出 run() 方法,检查与否,它都将被传递给Thread的(未处理异常处理程序。捕获已检查的异常和将其包装在某种RuntimeException 中只会模糊问题的真正原因。
  • 一个'不可能'的异常。例如,new String(someByteArray, "UTF-8");声明它可以抛出UnsupportedEncodingException,但是根据JVM规范,UTF-8必须始终可用。这里的 UnsupportedEncodingException 与使用String对象时的 ClassNotFoundError 差不多,你也没有必要捕获这些不可能的异常!

请注意,直接捕获偷偷抛出的已检查类型是不可能的,因为javac不允许你为try体中没有方法声明抛出的异常类型编写对应的catch块。这个问题与上面列出的任何一个用例都没有关系,所以让这个作为警告,你不应该在没有经过深思熟虑的情况下使用 @SneakyThrows 机制!

你可以将任意数量的异常传递给 @SneakyThrows 注解。如果你没有传递任何例外,你可以偷偷地抛出任何异常。

With Lombok

import lombok.SneakyThrows;

public class SneakyThrowsExample implements Runnable {
  @SneakyThrows(UnsupportedEncodingException.class)
  public String utf8ToString(byte[] bytes) {
    return new String(bytes, "UTF-8");
  }
  
  @SneakyThrows
  public void run() {
    throw new Throwable();
  }
}

Vanilla Java

import lombok.Lombok;

public class SneakyThrowsExample implements Runnable {
  public String utf8ToString(byte[] bytes) {
    try {
      return new String(bytes, "UTF-8");
    } catch (UnsupportedEncodingException e) {
      throw Lombok.sneakyThrow(e);
    }
  }
  
  public void run() {
    try {
      throw new Throwable();
    } catch (Throwable t) {
      throw Lombok.sneakyThrow(t);
    }
  }
}

支持的配置键

lombok.sneakyThrows.flagUsage = [ warning | error ](默认:未设置) 如果已配置,Lombok会将 @SneakyThrows 的任何用法标记为警告或错误。

Small Print

因为@SneakyThrows 是一个实现细节的一部分而不是方法签名的一部分,所以当你不调用任何抛出异常的方法时,你试图将此异常在 @SneakyThrows 中声明是会报错的。 (这样做对于 throws 语句来说非常合法,以适应子类)。同样地, @SneakyThrows 不会继承。

对于人群中的不同说法者:开箱即用,Eclipse将为未捕获的异常提供“快速修复”,这些异常在try块中使用 e.printStackTrace() 包含有问题的语句。与仅仅偷偷抛出异常相比,这是非常无效的,Roel和Reinier认为被检查的异常系统远非完美,因此有理由选择退出机制。

如果将 @SneakyThrows 放在构造函数上,则任何对兄弟或父类构造函数的调用都会排除 @SneakyThrows 处理。这是我们无法解决的java限制:对兄弟/超级构造函数的调用必须是构造函数中的第一个语句;它们不能放在 try / catch 块中。

@SneakyThrows对一个空方法,或一个空的构造函数或只调用兄弟/父类构造函数导致没有try / catch块和警告。

Clone this wiki locally