(九)Java关于异常处理(Error和Exception)详解

Java的异常处理是构建鲁棒软件的关键,包括异常的分类(如Error和Exception,以及checked和unchecked异常)、处理语法(try-catch-finally结构)和自定义异常。异常处理允许程序员控制和管理程序运行时可能出现的问题,提高软件的稳定性和健壮性。
摘要由CSDN通过智能技术生成

Java 的异常处理

前言

​ 有实际意义的软件本身是复杂的,软件运行的坏境也是复杂的,加之软件使用者在操作时的不确定性和不可控性,使得程序在执行过程中出现不正常,甚至导致程序运行崩溃的情况在所难免。而程序员需要尽可能控制这些”异常“情况,使软件“鲁棒”。
​ 鲁棒性是软件质量的一个非常重要的衡量标准,也是软件工程的一个专业术语。

鲁棒是 Robust的音译,也就是健壮和强壮的意思。它是在异常和危险情况下系统生存的关键。比如说,计算机软件在输入错误、磁盘故障、网络过教或有意攻击情况下,能否不死机、不崩溃,就是该软件的鲁棒性。

——来源于百度百科

​ C语言系统对于“异常”,基本没有提供系统级别的处理手段,全部要靠程序员编码进行判断和处理。C++、Java这样的后起之秀提供了系统级别的异常处理手段,大大简化了对异常的处理。
​ 对 Java 异常处理的学习和掌握,是编写出鲁棒性高的实用软件的基本功,这里必须强调:这里所说的异常,不是语法错误!凡是能在编译过程中发现的错误,都不在异常处理范围之列。

异常

什么是异常?

异常本质上是程序的错误。

​ 在程序开发中,异常指不期而至的各种状况。它是一个事件,当发生在程序运行期间时,会干扰正常的指令流程。

异常的分类

在Java中,通过 Throwable 及其子类描述各种不同的异常类型。

Throwable有两个重要的子类:Exception 和 Error

Error

​ Error是程序无法处理的错误,表示运行应用程序 中较严重问题。

​ 大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java虚拟机)出现的问题。

​ 例如: Java虚拟机运行错误(Virtual MachineError),当 JVM 不再有继续执行操作所需的内存资源时,将出现 OutOfMemoryError。

​ 这些错误是不可查的,因为它们在应用程序的 控制和处理能力之外,而且绝大多数是程序运行 时不允许出现的状况。对于设计合理的应用程序来说,即使确实发生了错误,本质上也不应该试图去处理它所引起的异常状况。因此我们编写程序时不需要关心这类异常。

Exception

​ Exception 是程序本身可以处理的异常。异常处理通常只针对这种类型异常的处理。

​ Exception 又分为 unchecked exception(非检查异常) 和 checked exception (检查异常)。

unchecked exception(非检查异常)

​ unchecked exception:编译器不要求强制处置的异常。 Java编译器不会检查这些异常,在程序中可以选择捕获处理,也可以不处理,照样正常编译通过。

checked exception (检查异常,又称非运行时异常)

checked exception:编译器要求必须处置的异常,除了 RuntimeException 及其子类以外,其他都属于 Exception 类的子类。如 IOException、SQLException 等 ,Java编译器会检查这些异常,当程序中可能出现这类异常时,要求必须进行异常处理,否则编译 不会通过。

异常处理语法及过程

异常处理代码介绍

先看下面两行代码:

public class SimpleExceptionDemo {
    public static void main(String[] args) {
        System.out.println(12 / 0);
    }
}

这里明知故犯,我们明显能够看到 Java 如何处理”除0错“。

​ 这个程序不能够被正常执行,不过执行的结果是在 console 中出现了红色的异常提示,并清晰地说明是类 SimpleExceptionDemo 的第5行,发生了 ArithmeticException (数学异常),且是:/ by zero!

​ 这说明,”除0错“是被 Java 系统”捕获“,并处理了,其实我们可以在我们的代码中”捕获“并处理这个异常:

package com.hb.about_exception.core;

import java.util.Scanner;

public class SimpleExceptionDemo {
    public static void main(String[] args) {
        int num1;
        int num2;
        int result;

        Scanner in = new Scanner(System.in);
        //从键盘输入两个相除的数
        num1 = in.nextInt();
        num2 = in.nextInt();

        try {
            result = num1 / num2;
            //num2 若为 0 ,则会出现”除 0 错“异常;
            //但 num2 也大概率不为 0 ;
            System.out.println(num1 + "/ " + num2 + "=" + result);
        } catch (ArithmeticException arithmeticException) {
            //catch 意为”捕获“:这里试图捕获除 0 错异常;
            System.out.println("怎么可以除 0 呢?小笨蛋");
        }

        in.close();
    }
}

将上述程序执行两次,第一次 num2 不为 0 ,第二次 num2 为 0;

第一次执行结果如下:

7
7
7 / 7 = 1

第二次执行结果如下:

这个简单的例子至少说明关于Java异常处理的基本原则:

程序一旦发生异常,则,异常点后的语句将停止执行。

​ 如果不存在这种异常的捕获语句,则,以后的所有代码都将停止执行,程序“崩溃”,由 JVM 接手处理异常;

​ 如果存在,则,转而执行异常捕获语句块中的代码;并继续执行异常捕获语句块的后续代码,程序不会崩溃!

下图,对比不同情况下的程序流程:

在Java应用程序中,异常处理机制为:抛出异常捕获异常

抛出异常

  • 当一个方法出现错误引发异常时,方法创建异常对象并交付运行时系统。
  • 异常对象中包含了异常类型和异常出现时的程序状态等异常信息。
  • 运行时系统负责寻找处置异常的代码并执行。

捕获异常

  • 在方法抛出异常之后,运行时系统将转为寻找合适的异常处理器。
  • 运行时系统从发生异常的方法开始,依次回查调用栈中的方法,当异常处理器所能处理的异常类型与方法抛出的异常类型相符时,即为合适的异常处理器。
  • 当运行时系统遍历调用栈而未找到合适的异常处理器,则运行时系统终止。同时,意味着Java程序的终止。

对于运行时异常、错误或可查异常,Java技术所 要求的异常处理方式有所不同。简单地说,异常总是先被抛出,后被捕捉的。

总的来说:

​ 异常处理通过5个关键字来实现:try、catch、 finally、throw 、throws;

try — catch — finally

  • try块: 用于捕获异常;

  • catch块: 用于处理try捕获到的异常;

  • finally块: 无论是否发生异常,都要执行的块

try 块后可接零个或者多个 catch 块,如果没有 catch 块,则必须跟一个 finally 块。

多重 catch 块
  • 一旦某个catch捕获到匹配的异常类型,将进入异常处理代码。一经处理结束,就意味着整个 try - catch 语句结束。其他的catch子句不再有匹配和捕获异常类型的机会。

  • 对于有多个catch子句的异常程序而言,应该尽量将捕获底层异常类的 catch 子句放在前面,同时尽量将捕获相对高层的异常类的catch子句放在后面。否则,捕获底层异常类的catch子句将可能会被屏蔽。

  • 引发多种类型的异常

    • 排列 catch 语句的顺序:先子类后父类;
    • 发生异常时按顺序逐个匹配;
    • 只执行第一个与异常类型匹配的 catch 语句;

    常见的异常类型

    异 常 类 型说 明
    Exception异常层次结构的父类
    ArrayIndexOutOfBoundsException数组下标越界
    NullPointerException尝试访问 null 对象成员
    ClassNotFoundException不能加载所需的类
    IllegalArgumentException方法接收到非法参数
    ClassCastException对象强制类型转换出错
    NumberFormatException数字格式转换异常,如把"abc" 转换成数字

抛出异常和捕获异常的选择

​ 对于异常,通常有两种处理手段:抛出和捕获。在前面的示例中,两种处理方法都使用过。上面的代码主要是讲述异常的基本语法和产生过程,对于这两种处理方式的差别并没有说明。

​ 一般来说,如果对于某种异常,如果在本方法中有处理它的安排,那么就捕获,而且,这个异常不再向上一级方法(调用本方法的方法)抛出。这样做相当于自动响应异常,并给出有效处理。
​ 如果本方法没有处理它的安排,那通常分两种情况:
​ 一种情况是,这种异常不影响后续代码的逻辑和执行,那么,就直接捕获且什么都不处理(保证捕获处理块为空)即可;
​ 另一种情况是,这种异常严重影响到后续代码的执行,甚至会影响到调用本方法的上一级方法的正常执行,那么,就把这个异常“抛出”。
​ 还有一种简单的处理异常的原则:能处理则处理,不能处理则抛出。
​ 当然,抛到了主函数main()那里的异常,最好还是处理一下,免得异常发生后,满屏红字。
事实上,关于异常的处理选择,要根据具体应用场景进行灵活选择,没有任何可以“套”的公式。所以,熟练掌握异常的方法只有一个:多编程。

自定义异常

​ 用 Exception 类可以派生出“检查型异常”类;
​ 用 RuntimeException 可以派生出“运行时异常”类。
​ 通常建议定义“检杳型异常”,这样可以强迫程序员对异常进行捕获和处理;如果确实不需要程序员有目的的进行捕获,也可以定义“运行时异常”。
​ 这里利用 Eclipse 帮助我们非常方便、迅速的建立一个异常类:

​ 注意上图中框选和箭头所指处。

​ 选择“Finish”按钮后,会出现异常类代码。这时会发现,除了代码里出现了大量构造方法外,编译器还会出现黄色警告。使用“Ctrl +1”自动修正功能,会出现下图所示的要求生成一个“序列号”的修正方案。(这里涉及到了 Java ”序列化“的问题,此处不作详细赘述)

​ 备注:序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间,序列化是为了解决在对对象流进行读写操作时所引发的问题。

public class CoordinateOutOfRange extends Exception {

	/**
	 * 
	 */
	private static final long serialVersionUID = 95715270923882271L;

	public CoordinateOutOfRange() {
		// TODO Auto-generated constructor stub
	}

	public CoordinateOutOfRange(String message) {
		super(message);
		// TODO Auto-generated constructor stub
	}

	public CoordinateOutOfRange(Throwable cause) {
		super(cause);
		// TODO Auto-generated constructor stub
	}

	public CoordinateOutOfRange(String message, Throwable cause) {
		super(message, cause);
		// TODO Auto-generated constructor stub
	}

	public CoordinateOutOfRange(String message, Throwable cause, boolean enableSuppression,
			boolean writableStackTrace) {
		super(message, cause, enableSuppression, writableStackTrace);
		// TODO Auto-generated constructor stub
	}

}

这样就生成一个我们自己定义的异常类了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

HB0o0

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

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

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

打赏作者

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

抵扣说明:

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

余额充值