文章目录
try catch return 问题及 throw
1.当我们对throw的对象进行try catch之后
public void re(int i) {
if (i > 5){
this.i = i;
}else {
try {
throw new Exception("数据非法!");
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("123");
}
结果显示:123被输出
java.lang.Exception: 数据非法!
at com.zsxfa.java.Ex3.re(ExcTest1.java:21)
at com.zsxfa.java.ExcTest1.main(ExcTest1.java:10)
123
2. 不对throw的对象进行try catch操作
public void re(int i) throws Exception {
if (i > 5) {
this.i = i;
}else {
throw new Exception("数据非法!");
System.out.println("123");
}
结果显示:编译不通过
public void re(int i) throws Exception {
if (i > 5) {
this.i = i;
}else {
throw new Exception("数据非法!");
}
System.out.println("123");
结果显示:异常抛出,123不会输出
java.lang.Exception: 数据非法!
at com.zsxfa.java.Ex2.re(ExcTest.java:30)
at com.zsxfa.java.ExcTest.main(ExcTest.java:11)
数据非法!
拓展
try{
return;
}catch(){
}finally{
}
return;
上面的代码的执行顺序是这样的:
代码段首先进入try语句,因无异常抛出,代码将要return的内容保存在内存中,然后执行finally,因finally中无可执行内容,再转回try中执行return,整个代码段执行结束,而finally后面的return是不会执行的。
注
1、不管有没有出现异常,finally块中代码都会执行;
2、当try和catch中有return时,finally仍然会执行;
3、finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,
而是先把要返回的值保存起来,不管finally中的代码怎么样,返回的值都不会改
变,仍然是之前保存的值),所以函数返回值是在finally执行前确定的;
4、finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。
常见的编译时异常和运行时异常
受检异常(包含编译异常): Exception中除 RuntimeException 及其子类之外的异常都属于受检异常。
非受检异常: 包含运行时异常(RuntimeException 及其子类)和错误(Error)
编译时异常
IOException 输入输出流异常
FileNotFoundException 文件找不到的异常
ClassNotFoundException 类找不到异常
DataFormatException 数据格式化异常
NoSuchFieldException 没有匹配的属性异常
NoSuchMethodException 没有匹配的方法异常
SQLException 数据库操作异常
TimeoutException 执行超时异常
运行时异常
ArrayIndexOutofBoundsException 数组越界异常
ClassCastException 类型转换异常
NullPointerException 空指针异常
IllegalAccessException 非法的参数异常
InputMismatchException 输入不匹配异常
@SneakyThrows 注解
它是 lombok包下的注解,并且继承了 Throwable
使用范围:只能作用在方法和构造函数上
@SneakyThrows 注解的用途得从 java 的异常体系说起。
java中常见的两类异常:
- 普通Exception类,也就是常说的受检异常或 Checked Exception
- RuntimeException类,运行时异常
受检异常会强制要求抛出它的方法声明throws,调用者必须显示的去处理这个异常。设计目的就是为了提醒开发者处理一些场景中必然可能存在的异常情况。
但是,现实中,往往事与愿违。
大部分情况下的异常,都是一路往外抛了事(强制处理有时处理不了,太难了,臣妾做不到)
所以,渐渐的 java程序员处理 Exception 的常见手段就是外面包一层 RuntimeException,接着往上throw。
这种思想尤其在 Spring中到处出现。参见 《Spring in Action》
try {
} catch (Exception e){
throw new RuntimeException(e);
}
Lombok 的 @SneakyThrows就是为了消除这样的模版代码
使用注解后不需要担心 Exception的处理
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();
}
}
真正生成的代码
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.sneakyThrow(t);
中。可能大家都会以为这个方法就是new RuntimeException()之类的。
然而事实并非如此。阅读代码可以看出整个方法其实最核心的逻辑是throw (T)t;
,利用泛型将我们传入的
Throwable强转为RuntimeException。虽然事实上我们不是RuntimeException。但是没关系。因为JVM并不关心这个。泛型最后存储为字节码时并没有泛型的信息。这样写只是为了骗过javac编译器。源码中注释有解释。
public static RuntimeException sneakyThrow(Throwable t) {
if (t == null) throw new NullPointerException("t");
return Lombok.<RuntimeException>sneakyThrow0(t);
}
private static <T extends Throwable> T sneakyThrow0(Throwable t) throws T {
throw (T)t;
}
TODO