一、 引入:
不应该出现了一个不算致命的问题就导致整个系统崩溃,所以java设计者提供了一个异常处理机制来解决问题
快速入门:
- package exception_;
-
- public class Exception01 {
- public static void main(String[] args) {
- int num1=10;
- int num2=0;
- //异常处理流程:把该代码块——》选中——》快捷键:ctrl+alt+t——》选择try-catch
- //如果进行异常处理,那么即使出现了异常,程序可以继续执行
- try {
- int res=num1/num2;
- } catch (Exception e) {
- throw new RuntimeException("出现异常的原因:"+e.getMessage());//e.getMessage()输出异常信息
- }
- System.out.println("程序继续运行……");
- }
- }
- //输出:
- // Exception in thread "main" java.lang.RuntimeException: 出现异常的原因:/ by zero
- // at exception_.Exception01.main(Exception01.java:12)
二、基本介绍:
1、基本概念:java语言中,将程序执行中发生的不正常情况称为“异常”(开发过程中的语法错误和逻辑错误不是异常)
2、执行过程中所发生的异常事件可分为两类:
(1)Error(错误):java虚拟机无法解决的严重问题
如:JVM系统内部错误、资源耗尽等严重情况,比如:StackOverflowError[栈溢出]和OOM(out of memory),Error是严重错误,程序会崩溃
(2)Exception:其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理
例如空指针访问,试图读取不存在的文件,网络连接中断等等
Exception分为两大类:运行时异常[ 程序运行时发生的异常 ]和编译时异常[ 编程时编译器检查出的异常 ]
1)运行时异常:编译器检查不出来,编译器不要求强制处置的异常,一般是编程时的逻辑错误,是程序员应该避免其出现的异常,java.lang.RuntimeException类及它的子类都是运行时异常
对于运行时异常,可以不做处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响
2)编译时异常:编译器要求必须处置的异常(任务不合理,就不干活了)
进入到Throwable的源码后,把光标放在 Throwable上,右击,选择……
即可得到……,可以在上面画思维导图(嘿嘿)
右击,选择“显示实现”

即可开始添加


三、异常体系图:
(虚线是实现,实线是继承)


三、详细介绍:
1、常见的运行时异常:
(1)NullPointerException空指针异常
当应用程序试图在需要对象的地方使用null时,抛出该异常
- package exception_;
-
- public class NullPointerException_ {
- public static void main(String[] args) {
- String name=null;
- System.out.println(name.length());
- }
- }
- //输出:
- // Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "name" is null
- // at exception_.NullPointerException_.main(NullPointerException_.java:6)
(2)ArithmeticException数学运算异常
当出现异常的运算条件时,抛出此异常

- package exception_;
- public class Exception01 {
- public static void main(String[] args) {
- int num1=10;
- int num2=0;
- int res=num1/num2;
- System.out.println(res);
- }
- }
- //输出:
- // Exception in thread "main" java.lang.ArithmeticException: / by zero
- // at exception_.Exception01.main(Exception01.java:7)
(3)ArrayIndexOutOfBoundsException数组下标越界异常
用非法索引访问数组时抛出的异常,如果索引为负或大于等于数组大小,则该索引为非法索引

- package exception_;
-
- public class ArrayIndexOutOfBoundsException_ {
- public static void main(String[] args) {
- int[] arr={1,2,4};
- for(int i=0;i<=arr.length;i++){
- System.out.println(arr[i]);
- }
- }
- }
- //输出:
- //1
- //2
- //4
- //Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
- // at exception_.ArrayIndexOutOfBoundsException_.main(ArrayIndexOutOfBoundsException_.java:7)
(4)ClassCastException类型转换异常
当试图将对象强制转换为不是实例的子类时,抛出该异常

- package exception_;
-
- public class ClassCastException_ {
- public static void main(String[] args) {
- A b1=new B();//向上转型,b1指向A对象
- B b2=(B)b1;//向下转型,b1指向B对象
- C c2=(C)b1;//b1不能指向C对象,因为B和C没有关系
- }
- }
- class A{}
- class B extends A{};
- class C extends A{};
- //输出:
- // Exception in thread "main" java.lang.ClassCastException: class exception_.B cannot be cast to class exception_.C (exception_.B and exception_.C are in unnamed module of loader 'app')
- // at exception_.ClassCastException_.main(ClassCastException_.java:7)
-
(5)NumberFormatException数字格式不正确异常
当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常——》使用异常我们可以确保输入的是满足条件的数字

- package exception_;
-
- public class NumberFormatException_ {
- public static void main(String[] args) {
- String name="韩顺平";//应该输入数字
- int num=Integer.parseInt(name);
- System.out.println(num);
- }
- }
- //输出:
- // Exception in thread "main" java.lang.NumberFormatException: For input string: "韩顺平"
- // at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
- // at java.base/java.lang.Integer.parseInt(Integer.java:665)
- // at java.base/java.lang.Integer.parseInt(Integer.java:781)
- // at exception_.NumberFormatException_.main(NumberFormatException_.java:6)
2、常见的编译异常:
(1)SQLException,操作数据时,查询表可能发生异常
(2)IOException,操作文件时,异常
(3)FileNotFoundException,当操作一个不存在的文件时,异常
(4)ClassNotFoundException,加载类,而该类不存在时,异常
(5)EOFException,操作文件,到文件末尾,异常
(6) IllegalArgumentException,参数异常
四、异常处理:
1、异常处理方式:
(1)try-catch-finally(可以没有finally)
1)程序员在代码中捕获发生的异常,自行处理(try用于包含可能出错的代码,catch用于处理try块中发生的异常)

2)
·如果异常发生了,则异常后面的代码不会执行,直接进入到catch块
·如果异常没有发生,则顺序执行try的代码块,不会进入到catch
·如果希望不管是否发生异常,都执行某段代码(比如关闭连接,释放资源等),则使用finally
·可以有多个catch语句,捕获不同的异常(进行不同的业务处理),要求父类异常在后,子灰异常在前(因为如果父类在前,就可以囊括后面子类的异常处理,那后面子类异常处理的存在也就没有意义了),如果发生异常,只会匹配一个catch
- package exception_;
-
- import project20221109.Person;
-
- public class TryCatchDetail02 {
- public static void main(String[] args) {
- try {
- Person_ person=new Person_();
- System.out.println(person.getName());//NullPointerException
- int num1=10;
- int num2=0;
- int res=num1/num2;//ArithmeticException
- } catch (NullPointerException e) {
- System.out.println("空指针异常="+e.getMessage());
- }catch (ArithmeticException e){
- System.out.println("算术异常="+e.getMessage());
- }catch (Exception e){
- System.out.println(e.getMessage());
- }finally {
-
- }
- }
- }
- class Person_{
- private String name;
-
- public String getName() {
- return name;
- }
- }
- //输出:
- //null
- //算术异常=/ by zero
·可以进行try-finally配合使用,这种用法相当于没有捕获异常,因此程序会直接崩掉 /退出
(应用场景:执行一段代码,不管是否发生异常,都必须执行某个业务逻辑)
- package exception_;
-
- public class TryCatchDetail03 {
- public static void main(String[] args) {
- try {
- int n1 = 10;
- int n2 = 0;
- System.out.println(n1 / n2);
- } finally {
- System.out.println("执行了finally...");
- }
- System.out.println("程序继续执行...");
- }
- }
- //输出:
- // 执行了finally...
- //Exception in thread "main" java.lang.ArithmeticException: / by zero
- // at exception_.TryCatchDetail03.main(TryCatchDetail03.java:8)
- //练习题
- class ExceptionExe01{
- public static int method(){
- int i=1;
- try {
- i++;
- String[] name=new String[3];
- if(name[1].equals("tom")){
- System.out.println(name[1]);
- }else{
- name[3]="hspedu";
- }
- return 1;
- } catch (ArrayIndexOutOfBoundsException e) {
- return 2;
- }catch (NullPointerException e){
- return ++i;
- //程序执行到这里时i=3,但不会马上返回,因为还有finally没有执行,
- //所以用了一个临时变量temp来保存3
- } finally{
- ++i;
- System.out.println("i="+i);
- //输出i=4后,因为没有return语句,无法退出程序,又返回上面去返回3
- }
- }public static void main(String[] args) {
- System.out.println(method());
- }
- }
- //输出
- //i=4
- //3
- //题目:如果用户输入的不是一个整数,就提示他反复输入,直到输入一个整数为止
- //思路:
- //1、创建Scanner对象
- //2、使用无限循环,去接收一个输入
- //3、然后将该输入的值,转成一个int
- //4、如果在转换时,抛出异常,说明输入的内容不是一个可以转成int的内容
- //5、如果没有抛出异常,则break该循环
- package exception_;
- import java.util.Scanner;
- public class TryCatchDetail04 {
- public static void main(String[] args) {
- Scanner scanner=new Scanner(System.in);
- int num=0;
- String inputStr="";
- while(true){
- System.out.println("请输入一个整数:");
- inputStr=scanner.next();
- try {
- num=Integer.parseInt(inputStr);//这里可能抛出异常k
- break;
- } catch (NumberFormatException e) {
- System.out.println("你输入的不是一个整数:");
- }
- }
- System.out.println("你输入的值是="+num);
- }
- }
- //输出:
- //请输入一个整数:
- //tom
- //你输入的不是一个整数:
- //请输入一个整数:
- //1
- //你输入的值是=1
(2)throws
1)将发生的异常抛出,交给调用者(方法)来处理,最顶级的处理者就是JVM

如果程序员没有显示是处理异常,则默认是throws
2)在方法声明中用throws语句可以声明抛出异常的列表,throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类
- public void f2() throws FileNotFoundException,NullPointerException,ArithmeticException{}
- //也可以写成
- public void f2() throws Exception{}
3)子类重写父类的方法时,对抛出异常的规定:
子类重写的方法,所抛出的异常类型要么和父类抛出的异常一致,要么为父类抛出的异常的类型的子类型(如果子类抛出的异常比父类大,那子类抛完到父类抛出异常时就没有必要抛了)
- class Father{
- public void method() throws RuntimeException{}
- }
- class Son extends Father{
- public void method() throws ArithmeticException{}
- }
4)在throws过程中,如果有方法try-catch,就相当于处理异常,就可以不必throws
5)细节:
- public static void f1(){
- f3();
- //报错原因:因为f3()方法抛出的是一个编译异常,即这时f1()必须处理这个编译异常
- //方法一:public static void f1() throws FileNotFoundException{}
- //方法二:
- // try {
- // f3();
- // } catch (Exception e) {
- // throw new RuntimeException(e);
- // }
- }
- public static void f3() throws FileNotFoundException{
- FileInputStream fis=new FileInputStream("d://aa.txt");
- }
- public static void f1(){
- f3();//因为f3()抛出的是运行异常,不要求程序员显示处理,因为有默认处理机制
- }
- public static void f3() throws ArithmeticException{
- }
五、自定义异常
1、概念:当程序中出现了某些“错误”,但该错误信息并没有在Throwable子类中描述处理,这时可以自己设计异常类,用于描述该错误信息
2、步骤:
(1)定义类:自己写类名,继承Exception或RuntimeException
(2)如果继承Exception,属于编译异常
(3)如果继承RuntimeException,属于运行异常(一般是继承RuntimeException),好处在于可以使用默认的处理机制
六、throw 和 throws的区别:

七、练习题

- package exception_;
- import java.util.Scanner;
- public class Homework01 {
- public static void main(String[] args) {
- try {
- if(args.length!=2){
- throw new ArrayIndexOutOfBoundsException("参数个数不对");
- }
- int n1=Integer.parseInt(args[0]);
- int n2=Integer.parseInt(args[1]);
- double res=cal(n1,n2);
- System.out.println("计算结果是:"+res);
- } catch (ArrayIndexOutOfBoundsException e) {
- System.out.println(e.getMessage());
- } catch (NumberFormatException e) {
- System.out.println("参数格式不正确,需要输出整数");;
- }catch (ArithmeticException e){
- System.out.println("出现了除0的异常");
- }
- }
- public static double cal(int n1,int n2){
- return n1/n2;
- }
- }
- //在编辑配置处输入