文章9 | 阅读 3681 | 点赞0
@SneakyThrows
可用于偷偷抛出checked exception
,而无需在方法上的throws子句中声明需要抛出的异常。
由lombok
生成的代码,不会忽略,不会包装,不会替换或以其他方式修改抛出的checked exception
,而是将 checked exception
看做unchecked exception
,不处理,直接扔掉。
那么lombok
是如何工作的呢?
在JVM(类文件)级别上,无论方法throw
什么异常,lombok
都可以抛出所有异常(无论是否是检查时异常),如下面一个简单的示例:
public class SneakyThrowsTest {
public static void main(String[] args) {
throwException();
}
@SneakyThrows
public static void throwException() {
String str = null;
String[] split = str.split(",");
System.out.println(split);
}
}
// 编译后:
public class SneakyThrowsTest {
public SneakyThrowsTest() {}
public static void main(String[] args) {
throwException();
}
public static void throwException() {
try {
String str = null;
String[] split = ((String)str).split(",");
System.out.println(split);
} catch (Throwable var2) {
throw var2;
}
}
}
看到示例,可能就很好解释,为什么lombok
都可以抛出所有异常,catch (Throwable var2)
放在方法体的开始和结束,可以到所有的异常。
其实lombok
并未为我们提供更多配置,如下所示:
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
@Retention(RetentionPolicy.SOURCE)
public @interface SneakyThrows {
// 指定准确的异常类型
Class<? extends Throwable>[] value() default java.lang.Throwable.class;
}
public class SneakyThrowsTest {
public static void main(String[] args) {
throwException();
}
@SneakyThrows(value = NullPointerException.class)
public static void throwException(){
String str = null;
String[] split = str.split(",");
System.out.println(split);
}
}
// 编译后:
public class SneakyThrowsTest {
public SneakyThrowsTest() {}
public static void main(String[] args) {
throwException();
}
public static void throwException() {
try {
String str = null;
String[] split = ((String)str).split(",");
System.out.println(split);
} catch (NullPointerException var2) {
throw var2;
}
}
}
当我们制定了异常之后,lombok
就会只捕捉我们指定的一种或者几种类型的异常,当然如果我们指定的类型没有被捕捉到,就会被抛到上一层。
当然我们使用的时候如果使用注解的情况下,还是不要指定异常类型了。
public class SneakyThrowsTest {
public static void main(String[] args) {
throwException();
}
@SneakyThrows(value = FileNotFoundException.class)
public static void throwException(){
File file = new File("filePath");
@Cleanup InputStream inputStream = new FileInputStream(file);
}
}
当我们准确指定unchecked exception
时,你会发现在IDEA中编译并不会通过,但是在你不指定准确异常类型时,比如使用以下方式来注解的话,却可以正常编译通过:
public class SneakyThrowsTest {
public static void main(String[] args) {
throwException();
}
@SneakyThrows
public static void throwException(){
File file = new File("filePath");
@Cleanup InputStream inputStream = new FileInputStream(file);
}
}
首先,我在实际开发中使用@SneakyThrows
并不是太多,在处理一些业务时使用起来并不灵活。但是在一些情况下你可以使用,比如在一些不太可能发生异常的地方,但是你又必须cache checked exception
的地方使用这个@SneakyThrows annotation
会显得代码比较规整,易读。
synchronized done right: Don’t expose your locks.
@Synchronized
是synchronized
方法修饰符的更安全的变体。与synchronized
一样,注释只能用于静态和实例方法。@Synchronized
的操作类似于synchronized
关键字,但它锁定在不同的对象上。
关键字synchronized
锁定this
,但@Synchronized
锁定在名为$lock
的字段上,并且该字段是私有的。
(如果该字段不存在,则会为你创建该字段。)如果注释静态方法,则注释会锁定名为$LOCK
的静态字段。
public class SynchronizedTest {
private static final Logger log = LoggerFactory.getLogger(SynchronizedTest.class);
private static final Object $LOCK = new Object[0];
private final Object $lock = new Object[0];
public SynchronizedTest() { }
public static void staticMethodTest() {
Object var0 = $LOCK;
synchronized($LOCK) {
log.info("this is static method test.");
}
}
public void commonMethodTest() {
Object var1 = this.$lock;
synchronized(this.$lock) {
log.info("this is common method test.");
}
}
}
如果自动生成$lock
或$LOCK
,则会使用空的Object[]
数组初始化锁字段,而不仅仅是新的Object()
。Lombok
这样做是主要是因为new object()
不可序列化的,但空的Object[]
数组是可以实现序列化的。
因此,使用@Synchronized不会阻止对象序列化。
在类中至少有一个方法使用注解@Synchronized
,意味着会有一个锁字段,但是如果稍后删除这些添加@Synchronized
注解的方法,则此锁字段也会被同步删除。
这意味着你预定的serialVersionUID
就会会发生变化。
如果您打算通过java
的序列化机制长期存储这些对象,所以建议始终在类中添加固定的serialVersionUID
。
添加了固定的serialVersionUID
之后,再从方法中删除所有@Synchronized
注释的方法将不会破坏序列化与反序列化。
当然,你也可以自己创建这些锁。如果你已经自己创建了$lock
和$LOCK
字段,那么lombok
不会再为你生成这些锁字段。
另外,你还可以选择锁定另一个字段(非$lock
和$LOCK
字段),方法是将其指定为@Synchronized注释的参数。
在此用法变体中,不会自动创建字段,所以必须自己显式创建这些自定义的锁,否则将会在编译期发出错误。
public class SynchronizedTest {
private static final Logger log = LoggerFactory.getLogger(SynchronizedTest.class);
private final Object customLock = new Object();
public SynchronizedTest() {}
public void specifiedLockTest() {
Object var1 = this.customLock;
synchronized(this.customLock) {
log.info("this is specified lock test.");
}
}
}
为什么在注解@Synchronized
中通过value
属性指定自定义的锁名称时,而不会自动生成此自定义的锁字段字段:因为否则在字段名称中输入错误将导致很难找到错误!
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/weixin_41540822/article/details/86606587
内容来源于网络,如有侵权,请联系作者删除!