Java笔记整理 —— 异常

       如果没有使用异常处理机制,当抛出异常后,程序就退出了,下面的代码就不再执行。这样就导致一个不算致命的问题就会引起整个系统的崩溃,这使得程序的健壮性很差。因此,Java的设计者提供了一个 异常处理机制 来解决这个问题。

        如果程序员认为一段代码可能出现异常/问题,可以使用 try-catch 异常处理机制来解决,将该代码块选中 -> 快捷键 ctrl + alt + t -> 选中 try-catch。这样即使出现异常,程序也会继续执行。

异常

基本概念

    Java语言中,将程序执行中发生的不正常情况称为“异常”。(开发过程中的语法错误和逻辑错误不是异常

Error(错误)

    Java虚拟机无法解决的严重问题,如:JVM系统内部错误、资源耗尽(StackOverflowError栈溢出,out of memory内存溢出),Error是严重错误,程序会崩溃。

Exception(异常)

     其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如空指针访问,试图读取不存在的文件,网络连接中断等等。Exception分为两大类:运行时异常(程序运行时发生的异常)和编译时异常(编程时,编译器检查出的异常)。

异常体系图

1. 异常分为两大类,运行时异常和编译时异常。

2. 运行时异常,编译器检查不出来。一般是指编程时的逻辑错误,是程序员应该避免其出现的异常。java.lang.RuntimeException类及它的子类都是运行时异常。

3. 对于运行时异常,可以不做处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响。

4. 编译时异常,是编译器要求 必须处置的异常。

 ​​​​​ 

常见的运行时异常 

1. NullPointerException 空指针异常

  当应用程序试图在需要对象的地方使用 null 时,抛出该异常。

    public static void main(String[] args) {
        String a = null;
        System.out.println(a.length());  //抛出异常
    }

2. ArithmeticException 数学运算异常

  当出现异常的运算条件时,抛出此异常,比如一个整数除以零。

    public static void main(String[] args) {
        int a = 10;
        int b = 0;
        System.out.println(a/b);
    }

3. ArrayIndexOutOfBoundsException 数组下标越界异常

  用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引。

    public static void main(String[] args) {
        int[] a = {1,2,3,4};
        System.out.println(a[4]); //越界
    }

4. ClassCastException 类型转换异常

  试图将对象强制转换为不是实例的子类时,抛出该异常。

public class Test {
    public static void main(String[] args) {
        A a = new B();
        B b = (B)a; // 向下转型,没问题
        C c = (C)a; // a实际上是一个B类,而B类和C类没有关系
    } 
}

class A{}
class B extends A{}
class C extends A{}

5. NumberFormatException 数字格式不正确异常

   当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常—— 使用该异常可以确保输入的是满足条件的数字。

    public static void main(String[] args) {
        String name = "青眼白龙";
        System.out.println(Integer.parseInt(name));
    }

常见的编译时异常

异常处理 

     异常处理就是当异常发生时,对异常的处理方式。有两种:1. try-catch-finally,程序员在代码中捕获发生的异常,自行处理。  2. throws,将发生的异常抛出,交给调用者来处理,最顶级的处理者就是JVM。

      对于编译异常,程序中必须处理,比如 try-catch 或者 throws。对于运行异常,程序中如果没有处理,默认就是throws的方式处理

1. try-catch-finally

注意事项:

1. 如果异常发生了,则异常发生后面的try代码块不会执行,直接进入到 catch 块。

    public static void main(String[] args) {
        try{
            String a = "青眼白龙";
            int b = Integer.parseInt(a);   
            System.out.println("异常后面的代码");   //这行直接不执行了
        }catch(Exception e){
            System.out.println("出现异常");   // 输出  出现异常
        }
    }

2. 如果异常没有发生,则顺序执行try的代码块,不会进入到catch。

3. 如果希望不管是否发生异常,都执行某段代码(比如关闭连接,释放资源等),则使用finally 语句(finally 可以省略)。

4. 可以有多个 catch 语句,捕获不同的异常(进行不同的业务处理),要求父类异常在后,子类异常在前。如果发生异常,只会匹配一个catch。

public static void main(String[] args) {
        try {
            Person person = new Person();
            person = null;
            System.out.println(person.getClass()); // NullPointerException
            int n1 = 10;
            int n2 = 0;
            int res = n1 / n2; // ArithmeticException
        } catch (NullPointerException e) {   // 单独指定的异常,在前
            System.out.println("空指针异常");
        }catch (ArithmeticException e){    // 单独指定的异常
            System.out.println("算术异常"); 
        }catch (Exception e){           // 父类异常
            System.out.println("其他异常");   
        }
    }

5.  可以进行 try - finally 配合使用,这种用法相当于没有捕获异常,因此程序会直接崩掉。应用场景就是执行一段代码,不管是否发生异常,都必须执行某个业务逻辑。

6. 如果 catch 里有 return 语句,执行到 return 时不会立刻执行,而是先去执行finally(因为执行完return程序就结束了,而finally必须执行),如果finally没有return 语句,最后执行catch的return,如果有则执行finally的return,然后程序结束(不执行catch的return),throw语句也是同理。

catch{
    ...
    return ++i; // 这里会用一个temp临时存储i的值,不管finally怎么修改i,最终还是返回temp
}

参考P451

2. throws

1. 如果一个方法可能产生某种异常,但是并不能确定如何处理这种异常,则此方法应显示地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的的调用者负责处理。

2. throws语句可以抛出多个异常,可以是方法中产生的异常类型,也可以是它的父类。

class A{
    public void f1() throws FileNotFoundException,Exception,ArithmeticException{}
}

3. 子类重写父类的方法时,所抛出的异常类型要么与父类一致,要么是父类抛出的异常类型的子类型。

class A{
    public void f1() throws FileNotFoundException{}
}
class B extends A{
    @Override
    public void f1() throws FileNotFoundException {   //相同或者为子类型
        super.f1();
    }
}

4. 在throws过程中,如果有方法 try-catch,就相当于处理异常,可以不必throws

    public void f1() {
        f2();  //报错
    }

    public void f2() throws FileNotFoundException{}  //抛出一个编译异常

  f2抛出了一个编译异常,这是必须处理的,由于调用者是f1,因此f1需要throws这个异常或者使用 try-catch 语句处理。

    public void f1() {   // 第一种方法
        try {
            f2();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }  
    
    public void f1() throws FileNotFoundException{  // 第二种方法
        f2();
    }
    public void f1() {
        f2();   //正确
    } 

    public void f2() throws NullPointerException{}

  这次f2抛出了一个运行异常,而运行异常并不要求程序员显示处理,因为有默认处理机制,因此不会报错。

自定义异常

       当程序中出现了某些“错误”,但该错误信息并没有在Throwable子类中描述处理,这个时候可以自己设计异常类,用于描述该错误信息。

步骤

1. 定义类:自定义异常类名,继承Exception或RuntimeException

2. 如果继承Exception,属于编译异常。

3. 如果继承RuntimeException,属于运行异常(一般来说,继承RuntimeException,好处是可以使用默认处理机制,要不然还得在调用方法里加throws)

class AgeException extends RuntimeException{
    public AgeException(String message) {  //构造器
        super(message);
    }
}
public class Test {
    public static void main(String[] args) {
        Scanner a = new Scanner(System.in);
        int b = a.nextInt();
        if(b<18){
            throw new AgeException("未成年");  //抛出异常
        }
    }
}


// throw new ArrayIndexOutOfBoundsException("数组过大") 
// 也可以在已有的类型中写参数表示异常信息

throw和throws

接下来分析一段代码:

public static void main(String[] args) {
        try {
            throw new AgeException("未成年");
        } catch(Exception e){
            System.out.println("catch方法");
            throw new AgeException("未成年");
        } finally{
            System.out.println("finally方法");
    //        return;
        }
    }

    try里throw的异常被catch接收(因此不会输出异常),然后输出"catch方法",紧接着catch方法又throw了一个异常,但是因为如果执行throw的话,程序就终止了,而finally必须执行,因此先不执行throw方法,执行finally,输出"finally方法",然后回到throw方法,输出异常。

public static void main(String[] args) {
        try {
            throw new AgeException("未成年");
        } catch(Exception e){
            System.out.println("catch方法");
            throw new AgeException("未成年");
        } finally{
            System.out.println("finally方法");
            return;  // 加上了return
        }
    }

    执行到catch里的throw时,调用finally方法,然后由于finally里有return语句,因此程序结束,直接不输出异常了。 (如果catch里没有return和throw,那么按顺序执行)P458 示例

   综合练习 P495 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值