十三、Java异常处理机制详解

简介: 异常机制是指程序在执行过程中发生了不正常的情况。

前言


异常层次结构图:


1.png



一、概述


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


代码演示:


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

运行结果:

2.png



没有正确输出,抛出了被 0 除异常

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


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

3.例如常见的:ArrayIndexOutOfBoundsException异常、ClassCastException异常、NullPointerException异常

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

5.Throwable下有两个分支:Error(不可处理,直接退出JVM)和Exception(可处理的)

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

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

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


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

举个例子:

你看到外面下雨了,倾盆大雨的。

你出门之前会预料到:如果不打伞,我可能会生病(生病是一种异常)。

而且这个异常发生的概率很高,所以我们出门之前要拿一把伞。

“拿一把伞”就是对“生病异常”发生之前的一种处理方式。

对于一些发生概率较高的异常,需要在运行之前对其进行预处理。

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

举个例子:

小明走在大街上,可能会被天上的飞机轮子砸到。

被飞机轮子砸到也算一种异常。

但是这种异常发生概率较低。

在出门之前你没必要提前对这种发生概率较低的异常进行预处理。

如果你预处理这种异常,你将活的很累。


二、异常处理


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区别详述。


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

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

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

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


1.png



取得异常的堆栈信息(比较适合于程序调试阶段):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();
        }
    }
}

运行结果:

1.png


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



四、手动抛异常


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


示例代码(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抛出异常的形式来编写代码,代码会变得更加美观,更加高大上,更加无懈可击,换句话说,代码不会太Low!!!(小编建议大家以后可以多多使用)


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
恭喜你注册成功!!


相关文章
|
13天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
43 2
|
17天前
|
Java 编译器
探索Java中的异常处理机制
【10月更文挑战第35天】在Java的世界中,异常是程序运行过程中不可避免的一部分。本文将通过通俗易懂的语言和生动的比喻,带你了解Java中的异常处理机制,包括异常的类型、如何捕获和处理异常,以及如何在代码中有效地利用异常处理来提升程序的健壮性。让我们一起走进Java的异常世界,学习如何优雅地面对和解决问题吧!
|
6天前
|
安全 Java 程序员
Java中的异常处理:从新手到专家
在Java编程的世界里,异常处理是每个开发者必须面对的挑战。本文将带你从基础的异常概念出发,逐步深入到高级处理技巧,让你在遇到代码中的“意外”时,能够从容应对,甚至化险为夷。
|
11天前
|
Java 数据库连接 开发者
Java中的异常处理:从基础到高级
【10月更文挑战第42天】在Java的世界中,异常处理是维护程序稳定性和健壮性的关键。本文将带你深入了解Java的异常处理机制,从基本的try-catch语句出发,逐步探索更复杂的异常处理策略。我们将通过实际代码示例来演示如何捕获和处理异常,以及如何自定义异常类型来满足特定需求。无论你是Java新手还是有经验的开发者,这篇文章都将帮助你更好地理解和应用Java的异常处理。
|
17天前
|
Java 开发者
Java中的异常处理:从基础到高级
【10月更文挑战第35天】在Java的世界里,异常处理是维护程序健壮性的关键。本文将深入浅出地探讨Java的异常处理机制,从基本的try-catch语句到自定义异常类的实现,带领读者理解并掌握如何在Java中优雅地处理错误和异常。我们将通过实际代码示例,展示如何捕获、处理以及预防潜在的运行时错误,确保程序即使在面临意外情况时也能保持稳定运行。
33 7
|
17天前
|
Java 编译器 数据库连接
Java中的异常处理机制深度解析####
本文深入探讨了Java编程语言中异常处理机制的核心原理、类型及其最佳实践,旨在帮助开发者更好地理解和应用这一关键特性。通过实例分析,揭示了try-catch-finally结构的重要性,以及如何利用自定义异常提升代码的健壮性和可读性。文章还讨论了异常处理在大型项目中的最佳实践,为提高软件质量提供指导。 ####
|
17天前
|
Java 数据库连接 开发者
Java中的异常处理机制及其最佳实践####
在本文中,我们将探讨Java编程语言中的异常处理机制。通过深入分析try-catch语句、throws关键字以及自定义异常的创建与使用,我们旨在揭示如何有效地管理和响应程序运行中的错误和异常情况。此外,本文还将讨论一些最佳实践,以帮助开发者编写更加健壮和易于维护的代码。 ####
|
20天前
|
Java
Java 异常处理下篇:11 个异常处理最佳实践
本文深入探讨了 Java 异常处理的最佳实践,包括早抛出晚捕获、只捕获可处理的异常、不要忽略捕获的异常、抛出具体检查性异常、正确包装自定义异常、记录或抛出异常但不同时执行、避免在 `finally` 块中抛出异常、避免使用异常进行流程控制、使用模板方法处理重复的 `try-catch`、尽量只抛出与方法相关的异常以及异常处理后清理资源。通过遵循这些实践,可以提高代码的健壮性和可维护性。
|
21天前
|
Java 编译器 开发者
Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面
本文探讨了Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面,帮助开发者提高代码质量和程序的健壮性。
41 2
|
23天前
|
Java 程序员 数据库连接
深入浅出Java异常处理
【10月更文挑战第30天】在Java的世界里,异常处理就像是生活中的急救箱,遇到意外时能及时救治。本文不仅教你如何使用try-catch语句包扎“伤口”,还会深入讲解如何通过自定义异常来应对那些常见的“头疼脑热”。准备好,我们将一起探索Java异常处理的奥秘,让你的程序更加健壮。