Java学习历程十一《工具类之异常和异常处理》

文章目录

    • Java 中的常用工具类之异常处理
      • 异常
      • 处理
        • try-catch-finally
        • throws 和 throw
        • 自定义异常
      • 异常链

Java 中的常用工具类之异常处理

异常

什么是异常?

程序中出现的错误,意外,背离程序设计的结果

  • 编译时异常
  • 运行时异常

异常类:

  • Throwable 根类
    • Error 子类[严重错误,无法处理]
      • 虚拟机错误
      • 内存溢出
      • 线程死锁
    • Exception 子类[程序可处理的异常]
      • Unchecked Exception[非检查异常,编译器不强制处理]
        • RuntimeException
          • 空指针
          • 数组越界
          • 算数计算异常
          • 类型转换错误
      • checked Exception[检查异常,编译器要求代码中处理异常]
        • IO异常
        • SQL数据操作异常

处理

机制:

  1. 先抛出异常:发现异常,产生异常对象,抛出异常
    • 异常对象包括
      • 异常类型
      • 异常出现时候程序的状态
      • 异常信息…
  2. 捕获异常对象:匹配可以处理异常的处理器来处理异常,匹配不到的结果是系统终止
    • 检查型异常 必须捕获处理
    • 非检查异常 允许不处理
  • try[可能产生异常的代码]-catch[捕获异常]-finally[无论如何都要执行的逻辑]
  • throw[手动抛出异常]
  • throws[声明可能要抛出的异常]
  • 自定义异常
  • 异常链

try-catch-finally

try 可以 接多个catch ,如果不接catch,必须有finally

package com.test;

import java.util.Scanner;

public class TryDemo1 {
    public static void main(String[] args) {
        // 定义两个整数,输出商
        Scanner sc = new Scanner(System.in);
        System.out.println("~~~~~程序开始~~~~~");
        try {
            System.out.print("输入整数x:");
            int x = sc.nextInt();
            System.out.print("输入整数y:");
            int y = sc.nextInt();
            System.out.println("x➗y的结果为:" + x / y);
        } catch (Exception e) {
            System.out.println("程序出错了~~~~exception");
            e.printStackTrace(); // 输出错误的堆栈信息
        } finally{
            System.out.println("~~~~~程序结束~~~~~");
        }
    }
}

当输入y为0或者输入的数据无法转换成Int,就会捕获异常,然后执行catch的代码块

多重catch

package com.test;

import java.util.InputMismatchException;
import java.util.Scanner;

public class TryDemo1 {
    public static void main(String[] args) {
        // 定义两个整数,输出商
        Scanner sc = new Scanner(System.in);
        System.out.println("~~~~~程序开始~~~~~");
        try {
            System.out.print("输入整数x:");
            int x = sc.nextInt();
            System.out.print("输入整数y:");
            int y = sc.nextInt();
            System.out.println("x➗y的结果为:" + x / y);
        } catch (ArithmeticException e) {
            // ArithmeticException 捕获算术异常
            System.out.println("程序出错了~~~~算术异常");
            e.printStackTrace(); // 输出错误的堆栈信息
        } catch (InputMismatchException e) {
            // InputMismatchException 捕获输入数据的格式异常
            System.out.println("程序出错了~~~~输入格式异常");
            e.printStackTrace(); // 输出错误的堆栈信息
        } catch (Exception e) {
            // 不能保证上面两个异常可以被明确捕获,那么最后需要用一个父类来捕获漏网之鱼
            System.out.println("Exception 异常");
        } finally {
            System.out.println("~~~~~程序结束~~~~~");
        }
    }
}

finally 块 无论是否出错都会执行相应的代码,能够阻断finally块的方法有

  • System.exit(1) 强制退出

当try catch finally 块中都存在return 语句的时候,无论是否发生异常,都将return finally块中的结果

throws 和 throw

  • throws 声明抛出异常的类型
  • throw 手动抛出异常

throws:

结构:

public void method() throws Exception1,Exception2,... {
    // 可能产生异常的代码
}

这种处理异常的方式不是 method()方法内部来实现对异常的捕获和处理的,上述的格式的意思是,调用这个方法可能会出现某些异常,
需要调用者对可能出现的异常进行捕获或者处理

// 使用 throws
package com.test;

import java.util.InputMismatchException;
import java.util.Scanner;

public class tryDemo2 {
    public static void main(String[] args) {
        try {
            int res = test();
            System.out.println("x/y=" + res);
        } catch (ArithmeticException e) {
            System.out.println("除数不能为0");
            e.printStackTrace();
        } catch (InputMismatchException e) {
            System.out.println("输入数据必须为数字");
            e.printStackTrace();
        }

    }

    public static int test() throws ArithmeticException, InputMismatchException {
        Scanner sc = new Scanner(System.in);
        System.out.println("=====程序开始=====");
        System.out.print("输入整数x:");
        int x = sc.nextInt();
        System.out.print("输入整数y:");
        int y = sc.nextInt();
        System.out.println("=====程序结束=====");
        return x / y;
    }
}

可以直接throws父类异常,根据多态的方式去处理各个异常,但是需要明确的有处理父类异常的catch

package com.test;

import java.util.InputMismatchException;
import java.util.Scanner;

public class tryDemo2 {
    public static void main(String[] args) {
        try {
            int res = test();
            System.out.println("x/y=" + res);
        } catch (ArithmeticException e) {
            System.out.println("除数不能为0");
            e.printStackTrace();
        } catch (InputMismatchException e) {
            System.out.println("输入数据必须为数字");
            e.printStackTrace();
        } catch (Exception e){
            // 显式的catch Exception 处理 否则会报错
            e.printStackTrace();
        }

    }
    /**
    *  这是一个测试两个数据做除法结果的方法
    * @return 数的商
    * @throws Exception
    */
    public static int test() throws Exception {
        Scanner sc = new Scanner(System.in);
        System.out.println("=====程序开始=====");
        System.out.print("输入整数x:");
        int x = sc.nextInt();
        System.out.print("输入整数y:");
        int y = sc.nextInt();
        System.out.println("=====程序结束=====");
        return x / y;
    }
}

为什么使用Exception会强制处理异常?

因为Exception中包括checkException,检查异常是必须去处理的

注意: 当子类重写父类带有抛出异常的方法的时候,子类方法的throws必须声明的异常是父类throws声明异常的同类或者子类

throw 抛出异常对象

throw new IOException();

注意: 只能抛出 可抛出类Throwable或者其子类的实例对象.

格式1:

public void method(){
    try{
        // code 1
        throw new ExceptionType();
    } catch(ExceptionType e){
        // code 2
    } finally{
        // code 3
    }

}

格式2:

public void method() throws ExceptionType{
    // code 1
    throw new ExceptionType();
}

通过手动抛出异常,捕获异常的方式,来实现某些业务需求.

自定义异常

定义一个异常类,继承于 Throwable 或者 他的子类

public class MyException extends Exception {
    public MyException() {
        super("这个异常是自定义异常"); // 异常信息 对应e.getMessage()
    }
} 

异常链

一层一层的抛出的异常链条

  • 在捕获一个异常A之后,抛出另外一个异常B
  1. testOne() 触发 one
  2. testTwo() 处理 异常one 抛出异常 two
  3. testThree() 处理异常two …
package com.test;

public class TryDemo3 {
    public static void main(String[] args) {
        try {
            testThree();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public static void testOne() throws MyException {
        throw new MyException();
    }

    public static void testTwo() throws Exception {
        try {
            testOne();
        } catch (MyException e) {
            throw new Exception("我是异常two");
        }
    }

    public static void testThree() throws Exception {
        try {
            testTwo();
        } catch (Exception e) {
            throw new Exception("我是异常three");
        }
    }
}

执行的结果是

java.lang.Exception: 我是异常three
	at com.test.TryDemo3.testThree(TryDemo3.java:29)
	at com.test.TryDemo3.main(TryDemo3.java:6)

发现只是有最后一个异常的message,前面异常信息都丢失了,想要连带的保留异常信息的方式有.

在形成新异常对象的时候将旧的异常作为参数传入 throw new Exception("new exception",e)

上述的代码中将e作为参数传入的结果是:

java.lang.Exception: 我是异常three
	at com.test.TryDemo3.testThree(TryDemo3.java:29)
	at com.test.TryDemo3.main(TryDemo3.java:6)
Caused by: java.lang.Exception: 我是异常two
	at com.test.TryDemo3.testTwo(TryDemo3.java:21)
	at com.test.TryDemo3.testThree(TryDemo3.java:27)
	... 1 more
Caused by: com.test.MyException: 这个异常是自定义异常
	at com.test.TryDemo3.testOne(TryDemo3.java:14)
	at com.test.TryDemo3.testTwo(TryDemo3.java:19)
	... 2 more

或者通过详细的方式去new 新的异常

catch (MyException e){
    Exception newE = new Exception("new exception");
    newE.initCause(e);
    throw newE;
}

你可能感兴趣的:(Java)