Java异常处理

1、概述

异常:就是程序出现了不正常的情况

用来封装错误信息的对象

组成结构:类型、提示、行号

2、异常的传承结构

查看API文档可知,Java中所有错误和异常的顶级父类是Throwable类

Throwable类下有两个子类,分别是Error和Exception,两者的区别是:

Error:是指不需要捕获的严重问题,通常是Java程序外的问题,不如说硬件问题或者内存不足导致的问题等。因此Java中出现了Error,我们无须处理

Exception:称之为异常类,他表示的是程序可以处理的问题

Exception下有很多异常子类,其中有一个异常子类是RuntimeException类,这里可以将异常类分为两大类:

① 编译时异常:

其他编译类以及不是RuntimeException子类的异常类都是检查异常(也叫编译时异常)

在编写完程序后,Java编译器会对其进行检查,如果检查出此类异常,就必须要显式处理,否则程序将无法进行编译。

例如:ClassNotFoundException、FileNotFoundException、SQLException等都是编译时异常

② 运行时异常:

RuntimeException以及子类被称为神经检查的异常(也叫作运行异常)

这类异常通常在编写完程序后没有问题,但是运行程序才出现异常,需要我们回来修改代码进行解决的异常,这类异常无须显式处理,当然也可以像编译时异常一样处理

例如:IndexOutOfBoundsException、ArithmeticException、NullPointException、ClassCastException等都是运行时异常。

判断一个异常是不是运行时异常,可以通过检查这个异常类是不是RuntimeException的子类,或者建厂这个异常是否只在程序运行时才会出现。

3虚拟机默认处理方式

如果长须在运行时出现了问题,而我们有没有处理该问题,最终虚拟机会做默认的处理,而这种默认处理的方式为:

① 将异常的名称(类型)、异常的原因以及异常出现的位置等信息输出在了控制台(Console窗口)

② 将程序停止运行(这意味着,出现异常的代码后面代码将不再执行)

异常示例-1

package Part03Exception;

/**
 * 异常实例
 */
public class ExceptionDemo {
    public static void main(String[] args) {
        int i = 1/0;
        System.out.println("执行完毕");
    }
}

运行结果

Exception in thread "main" java.lang.ArithmeticException: / by zero
	at Part03Exception.ExceptionDemo.main(ExceptionDemo.java:8)

异常示例-2

package Part03Exception;

/**
 * 
 * 
 * 异常实例
 */
public class ExceptionDemo2 {
    public static void main(String[] args) {
        //定义一个数组
        int[] arr = { 88, 23, 45 };
        System.out.println(arr[0]);
        System.out.println(arr[3]);
        System.out.println(arr[1]);
        System.out.println(arr[2]);
    }
}

运行结果

88
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
	at Part03Exception.ExceptionDemo2.main(ExceptionDemo2.java:13)

如果程序出现了异常,需要我们自己处理,有两种方案:

① 使用 try  catch  进行处理(捕获异常)

② 使用 throw 进行处理(抛出异常)

4异常处理之try..catch.. 处理

try..catch.. 处理已偿还的格式为:

try{
  可能出现异常的代码;
}catch(异常类型 变量名){
  异常处理代码; 
  //当try中的代码出现了异常并且这个异常能和catch中的异常类型匹配上, 才会执行catch
  //反之, 如果出现的异常和catch中的异常类型不匹配, 就不会执行catch
}

执行流程为

① 程序执行到try{}中的代码时,如果出现的异常没将会自动产生一个异常对象,该异常对象会被提交给Java运行时系统;

② 当Java运行时系统接受到异常队形时,回到catch()中寻找匹配的异常类型,找到后就进出catch{}中进行异常处理;

③ 执行完毕后,程序还可以继续执行try..catch 之后的代码

代码案例-1:

package Part03Exception;

/**
 * JAVA异常处理机制中的try-catch
 * 语法:
 * try{
 *     可能会出现异常的代码片段
 * }catch(XXXException e){
 *     当try中执行的代码片段出现了对应的catch捕获的异常的处理方法
 * }
 * try语句块不能独立存在,后面必须要跟着catch或者finally
 */
public class TryCatchDemo {
    public static void main(String[] args) {
        System.out.println("程序开始了");
        try{//可能会出现异常的代码片段
            String str = null;
            //这里会出现空指针异常,虚拟机会实例化空指针异常的实例,并在这里抛出
            System.out.println(str.length());
        }catch (NullPointerException e){//捕获是否会出现的异常类型
            System.out.println("出现了空指针异常!并在这里得到了解决");
        }
        System.out.println("程序结束了");
    }
}

代码案例-2:

package Part03Exception;

/**
 * JAVA异常处理机制中的try-catch
 * 语法:
 * try{
 *     可能会出现异常的代码片段
 * }catch(XXXException e){
 *     当try中执行的代码片段出现了对应的catch捕获的异常的处理方法
 * }
 * try语句块不能独立存在,后面必须要跟着catch或者finally
 */
public class TryCatchDemo {
    public static void main(String[] args) {
        System.out.println("程序开始了");
        try {//可能会出现异常的代码片段
            //String str = null;
            String str = "";
            //这里会出现空指针异常,虚拟机会实例化空指针异常的实例,并在这里抛出
            System.out.println(str.length());
            System.out.println(str.charAt(0));
            //批量注释: 选中要注释的代码片段,crtl+/
//        }catch (NullPointerException e){//捕获是否会出现的异常类型
//            System.out.println("出现了空指针异常!并在这里得到了解决");
//        }catch (StringIndexOutOfBoundsException e){
//            System.out.println("出现了字符串下标越界异常!并在这里得到了解决");
//        }
            //可以合并捕获异常,当不同异常处理手段相同时,建议使用此种方案
        }catch (NullPointerException|StringIndexOutOfBoundsException e){
            System.out.println("出现了空指针或者下标越界异常的处理");
        }
        System.out.println("程序结束了");
    }
}

代码案例-3:

package Part03Exception;

/**
 * JAVA异常处理机制中的try-catch
 * 语法:
 * try{
 *     可能会出现异常的代码片段
 * }catch(XXXException e){
 *     当try中执行的代码片段出现了对应的catch捕获的异常的处理方法
 * }
 * try语句块不能独立存在,后面必须要跟着catch或者finally
 */
public class TryCatchDemo {
    public static void main(String[] args) {
        System.out.println("程序开始了");
        try {//可能会出现异常的代码片段
            //String str = null;
            //String str = "";
            String str = "a";
            //这里会出现空指针异常,虚拟机会实例化空指针异常的实例,并在这里抛出
            System.out.println(str.length());
            System.out.println(str.charAt(0));
            System.out.println(Integer.parseInt(str));
            //批量注释: 选中要注释的代码片段,crtl+/
//        }catch (NullPointerException e){//捕获是否会出现的异常类型
//            System.out.println("出现了空指针异常!并在这里得到了解决");
//        }catch (StringIndexOutOfBoundsException e){
//            System.out.println("出现了字符串下标越界异常!并在这里得到了解决");
//        }
            //可以合并捕获异常,当不同异常处理手段相同时,建议使用此种方案
//        }catch (NullPointerException|StringIndexOutOfBoundsException e){
//            System.out.println("出现了空指针或者下标越界异常的处理");
            //当异常的种类较多时,或者防止出现自己不知道会发生的异常,可以使用异常的超类,
            //来兜底,一定要先捕获子类异常,然后再捕获超类异常
        }catch (Exception e){
            System.out.println("反正是一个错!");
        }
        System.out.println("程序结束了");
    }
}

5finally块

作用就是确保一定要执行的代码

代码案例-1:

package Part03Exception;
/*
* finally块
 * finally是异常处理机制的最后一块,它可以直接跟在try语句块后面,或者最后一个catch之后
 * finally语句块的特点:
 * 只要程序可以执行到try代码块中,无论是否出现异常,都会执行finally中的代码
 * 因此我们会将资源的释放操作放在finally中确保执行代码
* */
public class FinallyDemo1 {
    public static void main(String[] args) {
        System.out.println("程序开始了");
        //选中可能会出现异常的代码片段,然后按快捷键ctrl+alt+T,选择try
        try{
            String str = "a";
            System.out.println(str.length());
            System.out.println("try中的代码块执行完毕");
            return;//方法实际返回前,也必须要执行完finally
        }catch (Exception e){
            System.out.println("出错了!");
        }finally {
            System.out.println("finally中的代码执行了!");
        }
        System.out.println("程序结束了");
    }
}

代码案例-2:

package Part03Exception;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.FileOutputStream;

/*
*异常处理机制在io操作中的应用
*/
public class FinallyDemo2 {
    public static void main(String[] args) {
        FileOutputStream fos = null;
        try {
        fos = new FileOutputStream("fos.dat");
        fos.write(1);
        } catch (IOException  e) {
            System.out.println("出错了,在这里解决");
        }  finally {
            try {
                if (fos!= null){
                    fos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

}

代码案例-3:

package Part03Exception;
import java.io.FileOutputStream;
import java.io.IOException;
public class AutoCloseableDemo {
    public static void main(String[] args) {
        try (
                /*
                 *只有实现了AutoCloseable接口的类才可以在这里定义并初始化
                 * */
                FileOutputStream fos = new FileOutputStream("fos.dat");
        ) {
            fos.write(1);
        } catch (IOException e) {
            System.out.println("出错了!");
        }
    }
}

6throw 关键字

当程序发生错误而无法处理的时候,会抛出对应的异常对象,除此之外,在某些时刻,您可能想要自行抛出异常,例如:字异常处理结束后,再将异常抛出,让下一层异常出库块来捕捉,若想要自行抛出异常,您可有使用"throw"关键字,并生成执行的异常对象后抛出:

例如: throw new ArithmeticException();

代码案例:

Persion类

package Part03Exception;

/**
 * 使用当前类测试异常的抛出
 */
public class Person {
    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if (age<0||age>100){
            //对外抛出一个运行时期异常,异常信息是年龄不合法
            throw new RuntimeException("年龄不合法");
        }
        this.age = age;
    }
}

ThrowDemo类

package Part03Exception;

/**
 * 异常的抛出
 * throw关键字可以主动对外抛出一个异常
 * 通常下列情况我们会主动抛出异常:
 * 1:当前代码片段出现了异常,但是该异常不应当在当前的代码片段被解决,
 * 可以将其抛出
 * 2:程序可以运行,但是不满足业务要求时,我们也可以对外抛出异常告知
 */
public class ThrowDemo {
    public static void main(String[] args) {
        Person p = new Person();
        try {
            p.setAge(10000);//语法没有错误,但是业务是有错误的
        }catch (RuntimeException e){
            System.out.println("出错了!");
            p.setAge(66);
        }
        System.out.println("此人的年龄:"+p.getAge());
    }
}

7异常处理之throws处理

程序中会声明许多方法,这些方法中肯那个会因某些错误而引发异常,但是不希望直接在这个方法中处理这些异常,而希望调用这个他的方法来统一处理,这时候可以使用throws关键字声明这个方法抛出的异常

throws 处理异常的格式为:

...方法名() throws 异常类名 {
  方法体
}

代码案例:

Person类

package Part03Exception;

/**
 * 使用当前类测试异常的抛出
 */
public class Person {
    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) throws Exception{
        if (age<0||age>100){
            //对外抛出一个运行时期异常,异常信息是年龄不合法
            //throw new RuntimeException("年龄不合法");
            /*
            *java中除了RuntimeException之外,
            * 其他异常throw抛出是编译器要求必须在方法上使用throws关键字声明该异常的抛出
            * */
            throw new Exception("年龄不合法");
        }
        this.age = age;
    }
}

ThrowDemo

package Part03Exception;

/**
 * 使用当前类测试异常的抛出
 */
public class Person {
    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) throws Exception{
        if (age<0||age>100){
            //对外抛出一个运行时期异常,异常信息是年龄不合法
            //throw new RuntimeException("年龄不合法");
            /*
            *java中除了RuntimeException之外,
            * 其他异常throw抛出是编译器要求必须在方法上使用throws关键字声明该异常的抛出
            * */
            throw new Exception("年龄不合法");
        }
        this.age = age;
    }
}

Throws 的重写规则

代码案例

package Part03Exception;

import java.awt.*;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.SQLException;

public class ThrowsDemo {
    public void doSome() throws IOException, AWTException { }
}
class SubClass extends ThrowsDemo{
    //1.父类抛什么异常,子类就抛什么异常
    //public void doSome() throws IOException, AWTException { }
    //2.允许仅抛出部分异常
    //public void doSome() throws IOException { }
    //3.允许不抛出任何异常
    //public void doSome(){ }
    //4.允许抛出超类方法抛出的异常的子类异常类型
    //FileNotFoundException 是 IOException的子类
    //public void doSome() throws FileNotFoundException { }
    //5.不允许排除额外的异常(超类方法没有声明抛出的,或者和超类声明抛出的异常没有继承关系)
    //public void doSome() throws SQLException { }
    //6.不允许抛出超类方法抛出的异常的超类类型
    //public void doSome() throws Exception { }
}

异常常用方法

代码案例

package Part03Exception;

/**
 * 异常常用方法
 */
public class ExceptionApiDemo {
    public static void main(String[] args) {
        try {
            String str = "abc";
            System.out.println(Integer.parseInt(str));
        }catch (Exception e){
            System.out.println("PlanB");
            //该方法用来在控制台输出异常的堆栈信息,便于程序员解决bug
            e.printStackTrace();
            //一般给用户看的
            String message = e.getMessage();
            System.out.println("异常的原因是:"+message);
        }
    }
}

自定义异常

代码案例

package Part03Exception;

/**
 * 自定义异常
 * 通常使用自定义异常来表达业务错误:
 * 自定义异常一般要做到以下几点:
 * 1.类名要见明知义
 * 2.需要继承Exception(直接或者间接继承皆可以)
 * 3.提供超类中所有的构造器
 * Illegal: 非法的
 */
public class IllegalAgeException extends Exception{
    //提供超类中的全部的构造器
    //alt+insert,选择Constructor,按crtl+a全选,回车
    public IllegalAgeException() {
    }
    public IllegalAgeException(String message) {
        super(message);
    }
    public IllegalAgeException(String message, Throwable cause) {
        super(message, cause);
    }
    public IllegalAgeException(Throwable cause) {
        super(cause);
    }
    public IllegalAgeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}

Person

package Part03Exception;

/**
 * 使用当前类测试异常的抛出
 */
public class Person {
    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) throws IllegalAgeException{
        if (age<0||age>100){
            //对外抛出一个运行时期异常,异常信息是年龄不合法
            //throw new RuntimeException("年龄不合法");
            /*
            *java中除了RuntimeException之外,
            * 其他异常throw抛出是编译器要求必须在方法上使用throws关键字声明该异常的抛出
            * */
            throw new IllegalAgeException("年龄超过了范围:"+age);
        }
        this.age = age;
    }
}

ThrowDemo

package Part03Exception;

/**
 * 异常的抛出
 * throw关键字可以主动对外抛出一个异常
 * 通常下列情况我们会主动抛出异常:
 * 1:当前代码片段出现了异常,但是该异常不应当在当前的代码片段被解决,
 * 可以将其抛出
 * 2:程序可以运行,但是不满足业务要求时,我们也可以对外抛出异常告知
 */
public class ThrowDemo {
    public static void main(String[] args) {
        Person p = new Person();
        try {
            p.setAge(10000);//语法没有错误,但是业务是有错误的
        } catch (IllegalAgeException e) {
            e.printStackTrace();
        }
        System.out.println("此人的年龄:" + p.getAge());
    }
}

8、总结

什么时候需要try..catch..异常,什么时候需要throws异常

① 如果这个宜昌市方法内部的代码造成的异常,而不是因为调用者的传参导致的异常(也就是说这个异常和调用者没有关系),通常需要我们用try  catch异常

② 如果这个异常是调用者的传参导致的异常,则将异常throws抛出(也就是将异常抛给调用者)

③ 不要在main方法上throws抛出异常,因为这样会将异常抛给虚拟机,而虚拟机不会帮我们处理异常的(虚拟机会按默认的方式处理:输出异常信息以及终止程序执行)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值