异常

顶级类Throwable

  • 错误 Error

  • 异常 Exception
    Throwable的方法:
    String toString()返回异常信息的简短描述
    String getMessage()返回异常信息的详细描述
    void printStackRrace()将异常信息追踪到标准的错误流

    异常的处理方式

  • try…catch的异常处理
    try 尝试,检测 catch 捕获异常

    1
    2
    3
    4
    5
    6
    try{
    //被检测的代码
    //可能发生异常的代码
    }catch(异常类的类名 变量名){
    //异常处理程序
    }
  • 异常的处理程序:只要写了捕获,异常就被处理了。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public static void main(String[] args) {
    int []arr={1,2,3};
    try{
    System.out.println(arr[5]);
    }catch (Exception e){//利用多态性 异常类很多,直接写父类Exception就行
    //处理异常代码
    System.out.println("异常被处理了");
    }
    }
  • 异常对象,抛出到了main方法,main方法接收了异常对象
    try:检测到有异常对象的存在,try继续将异常对象抛出
    try:异常对象抛给catch语句
    catch:捕获到异常对象 会有多态性

  • 归纳*:try检测到异常发生,异常对象抛给catch,捕获该异常,异常对象就会被处理掉,程序继续执行

  • 异常对象,调用父类Throwable类的方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     public static void main(String[] args) {   
    int []arr={1,2,3};
    try{
    System.out.println(arr[5]);
    }catch (Exception e){//利用多态性 异常类很多,直接写父类Exception就行
    // Exception e=new ArrayIndexOutOfBoundsException();
    //处理异常代码
    String message = e.getMessage();
    String s = e.toString();
    System.out.println("message="+message);
    System.out.println("s="+s);
    System.out.println("异常被处理了");
    e.printStackTrace();
    }
    }
  • 多catch并行处理
    一个try后面可以跟随多个catch

    1
    2
    3
    4
    try{
    }catch(异常类 变量){
    }catch(异常类 变量){
    }
  • try跟随多个catch

    多个catch之间存在顺序问题,顺序错误,编译失败

    catch中的异常类之间没有继承关系:没有顺序

    如果catch中的异常类之间存在继承关系:父类写下面,越是父类越往下写。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class Test03 {
public static void main(String[] args) {
try{
createException(0);
}
//捕获空指针异常
catch (NullPointerException e){
//处理空指针异常
System.out.println("处理空指针异常");

}
//捕获越界异常
catch (ArrayIndexOutOfBoundsException e){
//处理越界异常
System.out.println("处理越界异常");
}
}
public static void createException(int i){
if (i==0){
String str=null;
System.out.println(str.length());
}else {
int[]arr=new int[1];
System.out.println(arr[2]);
}
}
}
  • 多个catch合并(不常用)
1
2
3
4
5
try{
createException(0);
}catch (NullPointerException|ArrayIndexOutOfBoundsException|ClassCastException e){
//无论什么异常,处理方式只能这个地方写代码,灵活性不够
}
  • try catch finally

    finally代码块,跟随异常处理出现,自己不能淡出使用

    finally代码块的写法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    try{

    }catch(异常类名 变量名){

    }finally{

    }
    //以下的定义方式不常见
    try{

    }finally{

    }

    无论程序中是否有异常,finally代码块里面的程序一定执行。作用是释放资源

1
2
3
4
5
6
7
8
9
10
11
12
13
public static void main(String[] args) {
try{
getSum();
}catch (ArrayIndexOutOfBoundsException e){
System.out.println("处理越界异常");
}finally {
System.out.println("这里的代码必须执行");
}
}
public static int getSum(){
int []arr={1,2};
return arr[2]+1;
}
  • finally代码运行细节问题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static void main(String[] args) {
int number = getNumber();
System.out.println(number);
}
//finally代码块必须执行,return结束方法
public static int getNumber(){
try {
return 1;
}catch (Exception e){
return 2;
}finally {
return 3;
}
}
//执行结果为3 先走try 再走finally
1
2
3
4
5
6
7
8
9
10
public static int getNumber2(){
int a=1;
try{
return a;//返回1
}catch (Exception e){
return a;//不走
}finally {
++a;//a自增,但是a=1时已经返回
}
}
1
2
3
4
5
6
7
8
9
10
11
public static int getNumber3(){
int a=1;
try{
return a;//返回1
}catch (Exception e){
return a;
}finally {
++a;//自增
System.exit(0);//虚拟接结束运行,不会执行后面的代码了。也不会输出
}
}

throw throws关键字

  • throw方法内部的问题

    throw new 异常, 方法中遇到了throw下面就不再执行了。

  • throws 将方法内部的问题暴露出去

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public static void main(String[] args) {
int sum = 0;
try {
sum = getSum(100, 100);
System.out.println(sum);
} catch (Exception e) {
e.printStackTrace();
}

}
/**
* 定义方法,小学考试
* 计算总成绩 语文+数学
* 成绩在0-100之间
*/
//throws写在方法的定义上,throws后面写异常的类名
private static int getSum(int math,int chinese)throws Exception{
if (math<0||math>100||chinese<0||chinese>100){
//方法内部产生问题,抛出异常
throw new Exception();
}
System.out.println("后面的语句执行");
return math+chinese;
}

编译异常和运行异常

  • 非RuntimeException类和子类,都是编译时期的异常

    如果调用的方法抛出编译异常,必须处理否则不能运行

    可以使用try catch或者在方法的定义上throws继续抛出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static void main(String[] args) throws ParseException {
System.out.println( getDateTimeString());
System.out.println(getDateTime().toString());
}
public static String getDateTimeString(){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String format = sdf.format(new Date());
// System.out.println(format);
return format;
}
public static Date getDateTime() throws ParseException {
String s="2020-02-02";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date parse = sdf.parse(s);
return parse;
}
  • RuntimeException

    方法内部throw new运行时期的异常,方法的定义上不需要throws来对外暴露异常。

    调用者不知道方法会出现异常,因此调用者也不需要去处理。

    运行异常的最大特点就是不让处理。运行异常一旦发生,处理根本就没有意义。只能修改源代码。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    /*
    * 当以方法计算圆形面积
    * */
    public static void main(String[] args) {
    getArea(-9);
    }
    public static double getArea(double r){
    if (r<0){
    throw new RuntimeException();
    }
    return r*r*Math.PI;

    }

常见的运行异常

ClassCastException类型转换异常,NullPointerException空指针异常,

IndexOutOfBoundsException越界异常,IllegalArgumentException非法参数异常

自定义异常

1
2
3
4
5
6
//自定义异常类
public class RadiusException extends RuntimeException{
public RadiusException(String str){
super(str);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* 继承RuntimeException还是Exception
* 看的是异常发生以后是不是必须修改代码
* */
public static void main(String[] args) {
System.out.println(getArea(-8));
}
public static double getArea(double r){
if (r<=0){
//抛出自定义异常类
throw new RadiusException(r+"半径不能小于等于0");
}
return Math.pow(r,2)*Math.PI;
}

字类父类异常处理

  • 父类方法抛出异常

    子类和父类一样,父类抛出异常,子类重写也抛出异常。

    子类也可以不抛出异常,如果子类要抛出异常,那么抛出的异常不能大于父类。

  • 父类方法不抛出异常

    子类重写方法后绝对不能throws。只能捕获处理、try catch