异常处理

java的异常体系

Java 异常处理、初始化块、final关键字_java
Error、Exception的区别:Error是程序本身无法处理的错误,Excepttion是程序本身可以处理的异常,捕获处理后系统可能会恢复。

CheckedException是编译时异常,RuntimeException是运行时异常。

可以extends Exception自定义异常种类。

 

执行顺序

try{
    int i = 1 / 0;
}catch (Exception e){
    System.out.println("catch...");
}finally {
    System.out.println("finally...");
}
System.out.println("other...");

try中没有发生异常:try -> finally -> finally之后的代码

try中发生了异常:

  • 不再执行try中后续的代码,转到执行catch
  • 如果catch中直接处理完了异常,则执行finally -> finally之后的代码;如果catch中throw往外抛了异常,则不再执行catch中后续的代码,直接执行finally,执行finally后不会再执行finally块之后的代码,而是跳到外层的catch中捕获处理异常(如果有外层的异常处理)。
     

在方法体中没有捕获处理异常,会跳出该方法的栈帧,导致方法体中后续代码都不会执行。

在循环体中,慎用throw直接抛出异常,如果循环体中的异常直接抛到了循环体外,会导致循环终止,后续批次都不会执行。

比如使用循环批量推送短信,某次循环时发生异常,没有在循环内处理异常,让异常抛到了循环外,则循环会被终止,循环中后续批次的消息都不会发送。

循环这种批量操作的场景,往往要尽量避免循环被异常终止,保证循环的继续执行,在循环体中可能发生异常的地方使用try…catch捕获处理掉异常。

 

异常块的优化

try…catch块对性能的影响主要体现在2方面

  • 会影响指令重排序
  • 发生异常时会生成Exception对象,需要保存栈快照等信息,开销大
     

优化点

  • 不要大量使用try-catch
  • 减少try中的代码量,能放到try外面就尽量放到外面

 

初始化块

初始化块和成员变量、成员函数一个级别,一般用于初始化。

class Xxx {
    // 普通初始化块
    {

    }


    // 静态初始化块
    static {

    }


    // ......

}

一个类中可以有多个初始化块,如果都是static初始化块或者普通初始化块,越靠前的越先执行。

static初始化快只能访问类的静态成员,只在JVM加载类的class对象时执行1次,常用于初始化类的静态成员、公共资源。

编译时,会把普通初始化块中的代码放到构造函数函数体内的最前面。每次创建对象时,在执行构造函数之前,都会先执行普通初始化快。普通初始化快常用与初始化对象。

 

final关键字

final可修饰类、变量(包括成员变量、局部变量)、方法

  • 被final修饰的类不能被继承
  • 被final修饰的变量,声明时就必须赋值,后续不能修改其值,即只读。基本类型、String类型不能改变值,引用类型不能修改引用(内存地址),但可以修改引用指向的对象本身。
  • 被final修饰的方法不能被重写

 

运算符优先级

运算符 结合性
[ ] . ( ) 访问数据元素、调用成员、小括号 从左向右
! ~ ++ – + - 单目运算符 从右向左
* / % 乘除取模 从左向右
+ - 加减 从左向右
<< >> >>> 位运算 从左向右
< <= > >= instanceof 比较判断 从左向右
== != 等价判断 从左向右
& 从左向右
^ 从左向右
| 从左向右
&& 从左向右
|| 从左向右
? : 三目运算符 从右向左
= += -= *= /= %= &= |= ^= <<= >>= >>= 赋值 从右向左
, 从左到右

 

常见运算符的优先级

单目 > 算术运算 > 位运算 > 条件判断 > 逻辑运算 > 三目 > 赋值

 

>>>是无符号右移,和>>右移一样,只是不考虑最高位的正负,不管最高位原来是0还是1,都直接取0。