写点什么

Java 基础:异常处理机制

  • 2022 年 6 月 24 日
  • 本文字数:4714 字

    阅读完需:约 15 分钟

前言

异常层次结构图:


一、概述

  1. 异常机制:程序在执行过程中发生了不正常的情况。


代码演示:


public class ExceptionText {    public static void main(String[] args) {        int a=100;        int b=0;        System.out.println(a/b);    }}
复制代码


运行结果:



没有正确输出,抛出了被 0 除异常通过以上示例,我们看到 java 给我们提供了这样一个体系结构,当出现问题的时候,它会告诉我们,并且把错误的详细信息也告诉我们了,这就是异常的体系结构,这样我们的程序更健壮,我们可以把这个信息,再进行处理以下告诉用户。从上面大家还可以看到,java 异常都是类,在异常类中会携带一些信息给我们,我们可以通过这个类把信息取出来


  1. java 提供异常处理机制,将不正常情况输出在控制台,供程序员参考,修改代码,提高代码的健壮性!!!

  2. 例如常见的:ArrayIndexOutOfBoundsException异常 ClassCastException异常NullPointerException异常

  3. 异常在 java 中以类和对象的形式存在每个类可以创建对象。

  4. Throwable 下有两个分支:Error(不可处理,直接退出 JVM)和 Exception(可处理的)Exception 下有两个分支:Exception 的直接子类:编译时异常(要求程序员在编写程序阶段必须预先对这些异常进行处理,如果不处理编译器报错)。RuntimeException:运行时异常。(在编写程序阶段程序员可以预先处理,也可以不处理)

  5. 编译时异常(受控异常)和运行时异常(非受控异常),都是发生在运行阶段。

  6. 编译时异常和运行时异常的区别?


编译时异常一般发生的概率比较高。


举个例子:你看到外面下雨了,倾盆大雨的。你出门之前会预料到:如果不打伞,我可能会生病(生病是一种异常)。而且这个异常发生的概率很高,所以我们出门之前要拿一把伞。“拿一把伞”就是对“生病异常”发生之前的一种处理方式。对于一些发生概率较高的异常,需要在运行之前对其进行预处理。


运行时异常一般发生的概率比较低。


举个例子:小明走在大街上,可能会被天上的飞机轮子砸到。被飞机轮子砸到也算一种异常。但是这种异常发生概率较低。在出门之前你没必要提前对这种发生概率较低的异常进行预处理。如果你预处理这种异常,你将活的很累。

二、异常处理

Java 中异常处理有两种方式:

  • 在方法声明的位置上,使用 throws 关键字,抛给上一级。谁调用我,我就抛给谁。抛给上一级。


public class ExceptionText {    public static void main(String[] args) throws Exception{        int a=100;        int b=0;        divide(a,b);    }
public static void divide(int a, int b) throws Exception{ int c = a / b; System.out.println(c); }}
复制代码


  • 使用 try..catch 语句进行异常的捕捉。


public class ExceptionText {    public static void main(String[] args){        int a=100;        int b=0;        try {            divide(a,b);        } catch (Exception e) {            e.printStackTrace();        }    }    public static void divide(int a, int b) throws Exception{        int c = a / b;        System.out.println(c);    }
复制代码


注意:


1.Java 中异常发生之后如果一直上抛,最终抛给了 main 方法,main 方法继续向上抛,抛给了调用者 JVM,JVM 知道这个异常发生,只有一个结果。终止 java 程序的执行。2.try 语句中某一行出现异常该行后续代码不执行 try...catch 捕获后,后续代码可执行。

try...catch 和 finally 概述

  • 语法格式:


try {
}catch(OneException e) {
}catch(TwoException e) {
}finally { }
复制代码


  • try 中包含了可能产生异常的代码

  • try 后面是 catch,catch 可以有一个或多个,catch 中是需要捕获的异常

  • finally 表示:不管是出现异常,还是没有出现异常,finally 里的代码都执行,finally 和 catch 可以分开使用,但 finally 必须和 try 一块使用


try {
}finally {
}
复制代码


  • catch(异常1 | 异常2 |异常3 |......) jdk8 新特性!!


示例代码(1):


public class ExceptionText {    public static void main(String[] args){        int a=100;        int b=0;        try {            divide(a,b);            //上一行代码有异常,直接进入catch里面!!            System.out.println("我能执行吗?");        } catch (Exception e) {            System.out.println("被0除了!!");        }    }    public static void divide(int a, int b) throws Exception{        int c = a / b;        System.out.println(c);    }}
复制代码


运行结果:


被0除了!!
复制代码


示例代码(2):


public class ExceptionText {    public static void main(String[] args){        int a=100;        int b=0;        try {            divide(a,b);            //上一行代码有异常,直接进入catch里面!!            System.out.println("我能执行吗?");        } catch (Exception e) {            System.out.println("被0除了!!");        }finally {            System.out.println("finally执行了!!");        }    }    public static void divide(int a, int b) throws Exception{        int c = a / b;        System.out.println(c);    }}
复制代码


运行结果:


被0除了!!finally执行了!!
复制代码


throws 与 try...catch 如何选择?


需要上报异常使用 throws,需要捕获异常时使用 try...catch 进行捕获!!

finally 重要面试题:

示例代码(3):


public class FinallyText {    public static void main(String[] args) {        System.out.println(n());    }        public static int n(){        int i=100;        try {            return i;        }finally {            i++;        }    }}
复制代码

运行结果:你们猜猜?有兴趣的铁子评论区讨论讨论一番哦!!!

final、finalize 和 finally 区别详述。

  1. final: 是一个关键字,表示最终的,不变的,可修饰属性、方法等!

  2. finalize: 是 Object 类的一个方法,无需程序员调用,JVM 垃圾回收器 GC 调用。

  3. finally: 与 try 一起使用,异常处理机制中,finally 语句块一定执行!!

三、异常中两个迷人的方法

取得异常描述信息:getMessage()

示例代码(4):


public class ExceptionText01 {    public static void main(String[] args) {        int a=100;        int b=0;        try {            int c=a/b;            System.out.println(c);        }catch (ArithmeticException e){            //e 是一个引用,它指向了堆中的 ArithmeticException            //通过 getMessage 可以得到异常的描述信息            System.out.println(e.getMessage());        }    }}
复制代码


运行结果:


/ by zero
复制代码

找不同:找一找下面的结果和上面的结果有什么不同?

取得异常的堆栈信息(比较适合于程序调试阶段):printStackTrace();

示例代码(5):


public class ExceptionText01 {    public static void main(String[] args) {        int a=100;        int b=0;        try {            int c=a/b;            System.out.println(c);        }catch (ArithmeticException e){            //e 是一个引用,它指向了堆中的 ArithmeticException            //通过 printStackTrace 可以打印栈结构            e.printStackTrace();        }    }}
复制代码


运行结果:


比较比较两个方法在运行结束后,各有什么不同呢!!!

四、手动抛异常

话不多说,直接上代码!!!

示例代码(6):


   public static void main(String[] args) {       int ret = method1(1000, 10);       if (ret == -1) {           System.out.println("除数为 0");       }       if (ret == -2) {           System.out.println("被除数必须为 1~100 之间的数据");       }       if (ret == 1) {           System.out.println("正确");       }   }    private static int method1(int value1, int value2){        if (value2 == 0) {            return -1;        }        if (!(value1 >0 && value1<=100)) {            return -2;        }        int value3 = value1/value2;
System.out.println("value3=" + value3); return 1; }
复制代码


运行结果:


被除数必须为 1~100 之间的数据
复制代码

将以上代码与以下代码作比较,找不同!!

示例代码(7):


    public static void main(String[] args) {        try {            int ret = method1(1000, 10);            System.out.println(ret);        }catch(Exception iae) { //可以采用 Exception 拦截所有的异常            System.out.println(iae.getMessage());        }    }    private static int method1(int value1, int value2){        if (value2 == 0) {            //手动抛出异常            throw new IllegalArgumentException("除数为 0");        }        if (!(value1 >0 && value1<=100)) {            //手动抛出异常            throw new IllegalArgumentException("被除数必须为 1~100 之间的数据");        }        int value3 = value1/value2;        return value3;    }
复制代码


运行结果:


被除数必须为 1~100 之间的数据
复制代码


我们不难看出,使用 throw 抛出异常的形式来编写代码,代码会变得更加美观



throws 和 throw 的区别?thorws 是声明异常,throw 是抛出异常

五、神奇的自定义异常

第一步:编写一个类,继承 Exception 或 RunTimeException.

第二步:提供两个构造方法。

示例代码(8):


public class MyException extends Exception{    public MyException() {
}
public MyException(String s) { super(s); }}
复制代码

小试牛刀:

编写程序模拟用户注册:1、程序开始执行时,提示用户输入“用户名”和“密码”信息。


2、输入信息之后,后台 java 程序模拟用户注册。


3、注册时用户名要求长度在[6-14]之间,小于或者大于都表示异常。


代码演示:用户注册类:


/** *用户登录 * @username 用户名 * @password 密码 * 当用户名为null,用户名要求长度在[6-14]之间,小于或者大于都表示异常。 */
class UserService { public void register(String username, String password) throws MyException { if (null==username || username.length() <= 6 || username.length() >= 14) { throw new MyException("输入有误,请输入6~14之间的用户名"); } System.out.println("恭喜你注册成功!!"); }}
复制代码


自定义异常类:


public class MyException extends Exception{    public MyException() {
}
public MyException(String s) { super(s); }}
复制代码


测试类:


public class ExceptionText {    public static void main(String[] args) {        Scanner input = new Scanner(System.in);        System.out.println("请输入用户名:");        String str = input.nextLine();        System.out.println("请输入密码:");        String passWord = input.next();        UserService userService = new UserService();        try {            userService.register(str, passWord);        } catch (MyException e) {            // e.printStackTrace();            System.out.println(e.getMessage());        }    }}
复制代码


运行结果 1:


请输入用户名:小马请输入密码:123456输入有误,请输入6~14之间的用户名
复制代码


运行结果 2:


请输入用户名:鹅厂小马前来报到请输入密码:123456789恭喜你注册成功!!
复制代码


发布于: 刚刚阅读数: 3
用户头像

该来的总会来,或迟或早。🎈 2022.06.13 加入

有JAVA方面3年学习经验,csdn/51cto等平台优质作者,华为云云享专家、阿里云受邀专家博主,擅长JAVA,大数据等方面的技术等。

评论

发布
暂无评论
Java基础:异常处理机制_异常_百思不得小赵_InfoQ写作社区