JavaEE - 异常

一、异常

异常是程序在运行期发生的不正常的事件,它会打断指令的正常执行流程。

设计良好的程序应该在异常发生时提供处理这些不正常事件的方法,使程序不会因为异常的发生而阻断或产生不可预见的结果。

1. 异常分类

异常分类

  1. 所有的异常类都是Throwable的子孙类
  2. 错误 - Error:错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。
  3. 异常 - Exception:其它因编程错误或偶然的外在因素导致的一般性问题。这类异常得到恰当的处理时,程序有机会恢复至正常运行状况。
    • 一般性异常 - CheckedException:受检性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
    • 运行时异常 - RuntimeException:非受检性异常是可以被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。

1. Error

JVM系统内部错误或资源耗尽等严重情况,属于JVM需要负担的责任,这一类异常事件无法恢复或不可能捕获,将导致应用程序中断。

2. Exception

一般分为Checked异常和Runtime异常,所有RuntimeException类及其子类的实例被称为Runtime异常,不属于该范畴的异常则被称为CheckedException

2.1 Checked异常

受检性异常 ,编译器要求必须处置的异常。指的是程序在运行时由于外界因素造成的一般性异常。如:类未找到异常、IO异常、文件未找到异常、数据库异常 等

受检性异常描述
ClassNotFoundException应用程序试图加载类时,找不到相应的类,抛出该异常。
CloneNotSupportedException当调用 Object 类中的 clone 方法克隆对象,但该对象的类无法实现 Cloneable 接口时,抛出该异常。
IllegalAccessException拒绝访问一个类的时候,抛出该异常。
InstantiationException当试图使用 Class 类中的 newInstance 方法创建一个类的实例,而指定的类对象因为是一个接口或是一个抽象类而无法实例化时,抛出该异常。
InterruptedException一个线程被另一个线程中断,抛出该异常。
NoSuchFieldException请求的变量不存在
NoSuchMethodException请求的方法不存在
2.2 Runtime异常

非受检性异常 ,程序员在编写程序的时应该避免的异常(逻辑异常)如:数组下标越界异常、空指针异常、计算类异常、类型转换异常 等

非受检性异常描述
ArithmeticException当出现异常的运算条件时,抛出此异常。例如,一个整数"除以零"时,抛出此类的一个实例。
ArrayIndexOutOfBoundsException用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引。
ArrayStoreException试图将错误类型的对象存储到一个对象数组时抛出的异常。
ClassCastException当试图将对象强制转换为不是实例的子类时,抛出该异常。
IllegalArgumentException抛出的异常表明向方法传递了一个不合法或不正确的参数。
IllegalMonitorStateException抛出的异常表明某一线程已经试图等待对象的监视器,或者试图通知其他正在等待对象的监视器而本身没有指定监视器的线程。
IllegalStateException在非法或不适当的时间调用方法时产生的信号。换句话说,即 Java 环境或 Java 应用程序没有处于请求操作所要求的适当状态下。
IllegalThreadStateException线程没有处于请求操作所要求的适当状态时抛出的异常。
IndexOutOfBoundsException指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。
NegativeArraySizeException如果应用程序试图创建大小为负的数组,则抛出该异常。
NullPointerException当应用程序试图在需要对象的地方使用 null 时,抛出该异常
NumberFormatException当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。
SecurityException由安全管理器抛出的异常,指示存在安全侵犯。
StringIndexOutOfBoundsException此异常由 String 方法抛出,指示索引或者为负,或者超出字符串的大小。
UnsupportedOperationException当不支持请求的操作时,抛出该异常。

2. 捕获异常

使用 try 和 catch 关键字可以捕获异常。try/catch 代码块放在异常可能发生的地方。try/catch代码块中的代码称为保护代码。

  • try/catch不能相互独立存在。

语法结构:

try{
	...可能发生异常的代码...
}catch(异常类型 e){
	...处理异常的代码...
}finally{
	...不管是否发生异常,都会执行...
}
注意:finally代码块根据需求可写可不写

Catch 语句包含要捕获异常类型的声明。当保护代码块中发生一个异常时,try 后面的 catch 块就会被检查。如果发生的异常包含在 catch 块中,异常会被传递到该 catch 块,这和传递一个参数到方法是一样。

注意: 异常处理时,唯一可以不执行finally代码块是的System.exit(1)

system.exit(int status)

  1. 正常退出

    status为0时为正常退出程序,也就是结束当前正在运行中的java虚拟机。

  2. 非正常退出

status为非0的其他整数(包括负数,一般是1或者-1),表示非正常退出当前程序。

在一个try-catch[-finally]语句体中,如果程序是按照预期的执行,到最后如果需要停止程序。那么就可以使用System.exit(0);表示正常退出! 而System.exit(1);一般都是放在catch语句中,当程序发生了错误,需要停止程序,表示这个程序非正常退出!

public static void main(String[] args) {
    //下面的例子中声明只有两个元素的一个数组,当代码试图访问数组的第三个元素的时候就会抛出一个异常。
    try {
        int a[] = new int[2];
        //用非法索引访问数组时
        System.out.println("访问第三个元素:" + a[3]);
    } catch (ArrayIndexOutOfBoundsException e) {
        System.out.println("抛出异常:" + e);
    }
}

多重捕获块

一个 try 代码块后面跟随多个 catch 代码块的情况就叫多重捕获

try{
   // 程序代码
}catch(异常类型1 异常的变量名1){
  // 程序代码
}catch(异常类型2 异常的变量名2){
  // 程序代码
}catch(异常类型3 异常的变量名3){
  // 程序代码
}

可以在 try 语句后面添加任意数量的 catch 块。如果保护代码中发生异常,异常被抛给第一个 catch 块。如果抛出异常的数据类型与异常类型1匹配,它在这里就会被捕获。如果不匹配,它会被传递给第二个 catch 块。直到异常被捕获或者通过所有的 catch 块。

  • 所以写catch代码时,先捕获的异常的范围要小于后捕获的异常的范围。范围大的异常要写在后面
Scanner scan = new Scanner(System.in);
int a = scan.nextInt();
int b = scan.nextInt();
try {
    System.out.println(a/b);//b为0会抛异常
    System.out.println("上面抛出异常后这句就不会被打印");
    
    String next = scan.next();
    //将字符串转换为int
    int parseInt = Integer.parseInt(next);//输入非数字字符串会抛异常
    System.out.println(parseInt);
    System.out.println("上面抛出异常后这句就不会被打印");
} catch (ArithmeticException e) {
    System.out.println("处理数学计算类异常");
} catch (NumberFormatException e) {
    System.out.println("处理数字格式化异常");
} finally {
    scan.close();
}

//处理多个异常还可以这样写
try {
	...
} catch (ArithmeticException | NumberFormatException e) {
	System.out.println("处理异常");
}

3. throws/throw 关键字

3.1 throws

修饰方法,让调用该方法的地方去处理方法抛出的异常

public static void main(String[] args) {
        try {
            method();
        } catch (ClassNotFoundException e) {
            System.out.println(e);//java.lang.ClassNotFoundException: xxx
        }
    }
	//让调用该方法的地方去处理方法抛出的异常
    public static void method() throws ClassNotFoundException {
        Class<?> forName = Class.forName("xxx");
    }

一个方法可以声明抛出多个异常,多个异常之间用逗号隔开。

public void method() throws RemoteException, InsufficientFundsException {
      ...
   }
3.2 throw

手动抛出异常,配合着自定义异常一起使用

MyException.java

//自定义异常类
public class MyException extends Exception{
   @Override
   public String toString() {
      return "除数不能为0的异常";
   }
}

Test.java

public class Test {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int a = scan.nextInt();
        int b = scan.nextInt();
        try {
            if (b == 0) {
                //手动抛出异常
                throw new MyException();
            }
        } catch (MyException e) {
            //处理异常
            b = 1;
        }
        System.out.println(a / b);
        scan.close();
    }
}

自定义异常类时需要记住下面几点

  • 所有异常都必须是 Throwable 的子类。
  • 如果希望写一个受检性异常类,则需要继承 Exception 类
  • 如果你想写一个非受检性异常类,那么需要继承 RuntimeException 类
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值