Java笔记 —— 异常(实例详解)

在这里插入图片描述
Java中的异常Throwable分为三种情况

  1. Error:严重的错误,是我们无法处理的问题,比如OOM,内存溢出问题
  2. 运行时异常RuntimeException:编译器不会检查的异常,可以处理也可以不处理。但这个异常我们通常不处理,因为运行时异常一般都是我们写的程序代码出了问题。与其抛出解决异常,不如直接把代码修改正确就行。比如数组下标越界,访问null指针,类型转换错误等。
  3. 编译时异常: 除了RuntimeException运行时异常以外的异常都是编译时异常。这种异常必须要处理,如果不处理程序就无法通过编译。比如File对象中有不存在的路径文件。
    在这里插入图片描述

如果程序出现了问题,我们没有做任何处理,JVM会给出一个默认的处理结果。把异常的名称,相关的原因,以及出现问题的相关信息,包括位置输出在控制台
同时程序结束,后面的代码不会运行

那么为什么会有异常的抛出与处理机制呢?

因为在程序运行的过程中,可能会出现意想不到的情况,比如读取文件时发现文件不存在,这个就是异常。异常不一定会发生,但是如果发生了,程序要能够抛出异常,避免因为一个异常,而导致整个程序的崩溃,这个后果可能会非常严重。

抛出和处理异常后,try-catch-finally语句块之后的程序代码依旧可以正常的运行,而如果不做异常处理,之后的程序代码就不会运行了。

异常举例

运行时异常举例
package review.ExceptionDemo;

public class demo4 {
    public static void main(String[] args) {
        //运行时异常举例
        System.out.println("befor异常之前");
        int r1 = div(2,0);
        System.out.println(r1);
        System.out.println("after异常之后");
    }
    public static int div(int a,int b){
        return a/b;
    }
}

在这里插入图片描述
除数不能为0,发生异常,程序直接停止,不会继续向下运行

package review.ExceptionDemo;

public class demo4 {
    public static void main(String[] args) {
        //运行时异常举例
        int[] arr = {1,2,3,4,5};
        int r2 = array(arr);
        System.out.println(r2);
    }
    public static int array(int[] arr){
        return arr[arr.length];
    }
}

在这里插入图片描述
数组下标越界异常

编译时异常举例

在这里插入图片描述
在编译的时候就会出现错误信息提示,说明这里可能会出现异常,但是程序中又没有对这个异常进行处理,所以不能编译

package review.ExceptionDemo;

import java.text.SimpleDateFormat;
import java.util.Date;

public class demo5 {
    public static void main(String[] args) {
        //编译时异常举例
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        String s ="2021-10-18";
        try {
            Date date = sdf.parse(s); 
            System.out.println(date);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

在这里插入图片描述
修改后可以正常的编译程序,并且捕获异常

处理异常

try-catch-finally

那么现在的问题是,我们知道这里可能会出现异常,为了避免程序的崩溃,所以我们需要对这个异常进行抛出并且处理

异常的处理格式:
1、try…catch…finally
2、throws

    try...catch...finally的处理格式:
            try{
                可能会出现问题的代码;
            }catch(异常的类名 变量名){
                针对问题的一些处理;
                没有发生此catch对应的异常,此catch中的语句不会执行
            }finally{
                释放资源的代码
                不管是否发生异常,都会执行finally中的语句
            }
package review.ExceptionDemo;

public class demo6 {
    public static void main(String[] args) {
        System.out.println("before");
        int a = 5;
        int b = 0;

        //try...catch处理一些可能会出现问题的代码
        try {
            System.out.println(a/b);
        }catch (ArithmeticException a1){
            System.out.println("除数不能为0");
        }
        System.out.println("after");

    }
}

在这里插入图片描述
当然,一段代码中也可能有多个异常,有几个异常就需要写几个catch语句

package review.ExceptionDemo;

public class demo6 {
    public static void main(String[] args) {
        System.out.println("before");
        int a = 5;
        int b = 0;

        try{
            System.out.println(a / b);
            int[] arr = {1, 2, 3, 4, 5};
            System.out.println(arr[5]);
        }catch (ArithmeticException a1){
            System.out.println("除数不能为0 ");
        }catch (ArrayIndexOutOfBoundsException a2){
            System.out.println("数组下标越界");
        }

    }
}

注意:

  1. 异常的类型尽可能的准确,如果能明确异常的种类时,就不要用该异常的父类
    比如IOException可以处理的异常,不要用Exception来概括
  2. 当多个异常之间是平级的关系时,多个catch语句没有前后顺序关系,谁在前谁在后都行。但是一旦出现了父类继承的关系,父类异常必须在后。
  3. 一旦try里面的代码出现了问题,就会去匹配catch里面的异常,继续执行catch中的语句。try里面的代码就停在了出现问题的那一步。但是try-catch语句后面的代码可以正常执行。
package review.ExceptionDemo;

public class demo6 {
    public static void main(String[] args) {
        try{
            System.out.println("before");
            int[] arr = {1, 2, 3, 4, 5};
            System.out.println(arr[5]);
            System.out.println("after");
        } catch (ArrayIndexOutOfBoundsException a2){
            System.out.println("数组下标越界");
            System.out.println("继续执行");
        }finally{
            System.out.println("不管是否发生异常,都会执行");
        }
        
        System.out.println("之后的程序代码正常执行");
    }
}


在这里插入图片描述

package review.ExceptionDemo;

public class demo6 {
    public static void main(String[] args) {
        try{
            System.out.println("before");
            int[] arr = {1, 2, 3, 4, 5};
            System.out.println(arr[3]);
            System.out.println("after");
        } catch (ArrayIndexOutOfBoundsException a2){
            System.out.println("数组下标越界");
            System.out.println("继续执行");
        }finally{
            System.out.println("不管是否发生异常,都会执行");
        }
    }
}

在这里插入图片描述
JDK7的新特性,可以一次性处理多个异常

try{
	可能会出现问题的代码
 }catch(异常类名1|异常类名2|... 变量名){
	处理异常的语句
 }
public class demo7 {
    public static void main(String[] args) {
        int a = 3;
        int b = 0;
        try{
            System.out.println(a / b);
            int[] arr = {1, 2, 3, 4, 5};
            System.out.println(arr[5]);
        }catch (ArithmeticException|ArrayIndexOutOfBoundsException a1){
            System.out.println("发生异常");
        }
    }
}

注意:

  1. 不同的异常处理的方式是一样的,虽然简洁但是不能针对性的进行处理
  2. 多个异常的类型之间必须是平级的关系
catch语句块中的方法
package review.ExceptionDemo;

public class demo8 {
    public static void main(String[] args) {
        int a = 10;
        int b = 0;

        try {
            System.out.println(a/b);
        }catch (ArithmeticException a1){
            //方法一
            String message = a1.getMessage();
            //打印出现问题的原因
            System.out.println(message);

            //方法二
            String s = a1.toString();
            System.out.println(s);

            //方法三
            a1.printStackTrace();
        }

        System.out.println("之后程序的代码正常执行");
    }
}

在这里插入图片描述
这里打印的异常信息,与没有做异常处理时,JVM自动在控制台给出的异常信息类似。但是做了异常处理后,可以让程序后面的代码正常的执行,不会因为这个异常而导致整个程序的终止。

printStackTrace()

这个方法是从java.lang.Throwable类继承过来的,会将具体的错误发生的栈轨迹信息打印在控制台上

package test.ExceptionDemo;

public class ExceptionDemo3 {
    public static void test1() throws Exception{
        throw new Exception("Exception");
    }
    public static void test2() throws Exception{
        test1();
    }

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

在这里插入图片描述

在方法test1()中抛出异常,方法test2()中调用方法test1(),在main方法中捕获异常,并且打印栈轨迹信息。因此,输出依次展示了test1() —> test2() —> main的过程。

throws

有时候我们可以针对一些异常进行处理,但是也有的时候,我们无法处理这个异常
对于这种情况,为了保证程序的正常执行,可以使用try-catch-finally之外的第二个处理方法

throws抛出异常,用在方法的声明上,表明当前方法不处理异常,等实际调用的时候,由该方法的调用者来处理异常

格式:
throws 异常类名
修饰符 返回值类型 方法名(参数) throws 异常类名1,异常类名2 … { }

注意:

  1. 抛出编译时异常,抛出异常的方法内可以不做处理,但是调用该方法的时候必须做处理,否则编译时就会报错
  2. 抛出运行时异常,调用时可以不做任何处理。编译时不会报错,但是程序遇到错误会终止
  3. 最好抛出详细的异常类型,也可以抛出更大的异常类型,但是处理的时候要对应上。比如throws Exception,则catch语句中是 Exception e
  4. 尽量不要在main方法上抛出,如果在main方法上抛出,就会交给JVM处理,遇到异常时程序会直接停止
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class demo9 {
    public static void main(String[] args) {
        System.out.println("程序开始");

        try {
            fun1();
        }catch (Exception pe){
            pe.printStackTrace();
        }

        try {
            fun2();
        }catch (ArithmeticException ae){
            ae.printStackTrace();
        }

        System.out.println("程序结束");
    }

    public static void fun2() throws ArithmeticException{
        int a = 10;
        int b =0;
        System.out.println(a/b);
    }

    public static void fun1() throws ParseException {
        String s = "2021-10-18";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = sdf.parse(s);
        System.out.println(date);
    }
}

在这里插入图片描述
发生异常之外的代码都正常的执行了

throw

throws和throw的区别:

  1. throws用来声明一个方法可能产生的所有异常,throw用来抛出一个具体的异常类型。
  2. throw语句用在方法体内,表示抛出异常,由方法体内的语句处理。
    throws语句用在方法声明后面,表示抛出异常,由该方法的调用者来处理
  3. throws只是表明一种可能性,不一定会抛出异常
    throw则是一定会抛出一个具体的异常
throw举例
package review.ExceptionDemo;

public class demo10 {
    public static void main(String[] args) {
        fun();
    }
    public static void fun(){
        int a = 10;
        int b = 0;

        if(b == 0){
            System.out.println("报错,除数不能为0");
            throw new ArithmeticException();
        }else {
            System.out.println(a/b);
        }

    }
}

在这里插入图片描述

throws举例
package review.ExceptionDemo;

public class demo10 {
    public static void main(String[] args) {
        try{
            fun();
        }catch(ArithmeticException ar){
            ar.printStackTrace();
        }
        System.out.println("程序结束");
    }
    public static void fun() throws ArithmeticException{
        int a = 10;
        int b = 0;
        System.out.println(a/b);
    }
}

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一纸春秋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值