您的位置 首页 java

java程序员必备的基础知识_java异常机制(二)

二、异常的继承体系结构

Throwable 类是 Java 语言中所有错误或异常的超类。

  • Throwable类是所有错误和Java中异常的超类。 只有当对象是此类(或其子类之一)的实例时,才能通过 Java 虚拟机或者Java throw 语句抛出。
  • Exception和Error都是继承了Throwable类,它是异常处理机制的基本组成类型。
  • Exception和Error体现了Java平台设计者对不同异常情况的分 类。Exception是程序正常运行中,可以预料的意外情况,可能并且应该被捕获,进行相应处理。
  • Error是指在正常情况下,不大可能出现的情况,绝大部分的Error都会导致程序(比如JVM自身)处于非正常的、不可恢复状态。既然是非正常情况,所以不便于也不需要捕获,常见的比如OutOfMemoryError之类,都是Error的子类。
java程序员必备的基础知识_java异常机制(二)

1、Error

Error 是 Throwable 的子类,用于指示合理的应用程序 不应该试图捕获的严重问题

Java 程序通常不捕获错误。错误一般发生在严重故障时,它们在Java程序处理的范畴之外。

2、 Exception

异常:java语言中,将程序执行中发生的不正常情况称之为异常, 就是程序执行的时候出现了你不想看到的情况。

Exception 异常主要分为两类

  • 一类是 受查异常(检查性异常) ,checkedException。可检查异常在源代码里必须显式地进行捕获处理,这是编译期检查的一部分。Checked Exception的假设是我们捕获了异常,然后恢复程序。但是,其实我们大多数情况下,根本就不可能恢复。这也是为什么有些资料说 Checked Exception 是多余的原因。
  • 一类是 运行时异常(非受查异常),RuntimeException。通常是可以编码避免的逻辑错误,具体根据需要来判断是否需要捕获,并不会在编译期强制要求。

举个例子:你要去机场和你的领导去出差,导致你最后无法坐上飞机的因素有哪些?

1、可以自行解决的:比如没带身份证,比如起床起晚了。 这叫运行时异常,通常自己导致的。你可以提前做好准备。

2、不能自行解决的:比如在你去的路途中地震了,突然下雨飞机 不能起飞了。 这叫错误,通常是上帝导致的。

中途堵车了,你领导没来。 这叫检查行异常,通常是别人导致的, 你必须提前做好措施。

(1) 常见的检查性异常

名字

问题

IOException

IO异常,在对流操作时有可能会出现的异常,学流时用到

SQLException

SQL异常,学数据库时会用到

ClassNotFoundException

找不到某个类时,会抛出该异常, 反射时会用到

InterruptedException

当阻塞方法收到中断请求的时候就会抛出中断异常

ClassNotFoundException

Java支持使用Class.forName方法来动态地加载类,任意一个类的 类名如果被作为参数传递给这个方法都将导致该类被加载到JVM内 存中,如果这个类在类路径中没有被找到,那么此时就会在运行时抛出ClassNotFoundException异常。

 Class.forName("com.ydlclass.Dog");  

InterruptedException

 try {
Thread.sleep(123);
} catch (InterruptedException e) {
e.printStackTrace();
}  

如果我们有一个运行中的软件,例如是杀毒软件正在全盘查杀病 毒,此时我们不想让他杀毒,这时候点击取消,那么就是正在中断一个运行的线程。

其实这段代码的大致意思就是我睡的好好的,有人把我吵醒了。一般是一个程序在睡觉,另一个线程将他打断。

(2) 常见的非检查性异常:

名字

问题

NullPointerException

空指针引用异常,视图调用空对象的方法或者属性时,抛出该异常

ArithmeticException

算术运算异常

ClassCastException

类型转换异常,当试图将对象强制转换为不是实例的子类 时,抛出该异常

IndexOutOfBoundsException

下标越界异常

NumberFormatException

数字格式异常

结局此类异常通常通过简单的逻辑判断就可以,一般不需要捕获处理:

NullPointerException

 String str = null;
byte[] bytes = str.getBytes();
//解决方法:
String str = null; if(Objects.nonNull(str)){
byte[] bytes = str.getBytes();
}  

ArithmeticException

 int i = 0;
int num = 1/i;
//解决方法:
int i = 0; if(i != 0){
int num = 1/i;
}  

ClassCastException

 Animal aniaml = new Dog(); Cat cat = (Cat)animal;
//解决方法:
Animal aniaml = new Dog();
if(animal instanceof Cat){
Cat cat = (Cat)animal;
}  

IndexOutOfBoundsException

 int[] nums = new int[3]; int i = 3;
nums[i] = 4;
//解决方案:
int[] nums = new int[3];
int i = 3;
if(i > -1 && i < nums.length){
nums[i] = 4;
}  

NumberFormatException

 String str = "abc";
Pattern pattern = Pattern.compile("^[-+]? [d]*$");
if(pattern.matcher(str).matches()){
        int num = Integer.parseInt(str);
        System.out.println(num);
}  

(3) 自定义异常类型

Java 的异常机制中所定义的所有异常不可能预见所有可能出现的错误,某些特定的情境下,则需要我们自定义异常类型来向上报告某些错误信息。

在 Java 中你可以自定义异常。编写自己的异常类时需要记住下面的几点。

  • 所有异常都必须是 Throwable 的子类。
  • 如果希望写一个检查性异常类,则需要继承 Exception 类。
  • 如果你想写一个运行时异常类,那么需要继承RuntimeException 类。

一个异常怎么抛出: throw new RuntimeException(“您输入的数字不合法”);

 public class Test1 {
        public static void main(String[] args) {
                while (true){
                fun2();
                }
        }
        public static void fun2(){
        try {
        fun();
                }catch (IndexOutOfBoundsException e){
        
                }
        }
        public static void fun(){
                Scanner scanner = new Scanner(System.in);
                int i = scanner.nextInt();
                if(i > 5){
                System.out.println("我们可以继续玩游戏!");
                } else {
                throw new RuntimeException("我的数组下标越界了!");
                }
        }
}  

工作中我们使用最多的还是自定义运行时异常:

 public class ServiceException extends RuntimeException{
        // 错误码
        private Integer code;
        // 错误信息
        private String message;
        // 空构造
        public ServiceException(){}
        public ServiceException(String message, Integer code){
        this.message = message;
        this.code = code;
        }
        public Integer getCode() {
        return code;
        }
        public void setCode(Integer code) {
        this.code = code;
        }
        @Override
        public String getMessage() {
        return message;
        }
        public void setMessage(String message) {
        this.message = message;
        }
}  

在需要抛出这个异常的地方,我们可以这样:

 throw new ServiceException(102,"业务出问题了");  

3、异常链

一个异常被抛出去后会继续被调用这个方法的方法捕获或抛出,也就是异常会扩散。

我们举一个例子:

你女朋友要找你约会——》半路遇上了债主——》债主打了你一顿——》结果约会迟到了——》你女朋友说你不爱他——》然后分手了

一件很正常的约会,因为出现了债主,导致最后两人分手,虽然这确实不可思议。一个异常的出现可能会导致整个方法调用链的问题。

方法在栈空间被调用,多个方法互相调用形成了调用链条,会生成一个StackTrace,也叫栈轨迹,或堆栈信息,或调用链。JVM抛出 异常时会打印这个堆栈信息,也就是我们经常在idea中看到的红色 的错误的信息。但是事实上,我们在捕获异常后也要主动打印堆栈信息,这样才能争取的找到问题、解决问题。

为了打印这个堆栈信息,Java每实例化一个Exception,都会对当时 的栈进行快照,这是一个相对比较重的操作。如果发生的非常频繁,这个开销可就不能被忽略了。以建议仅捕获有必要的代码段, 尽量不要一个大的try包住整段的代码。

有时我们甚至有这样的需求:捕获一个异常后需要抛出另外一个异常,并且希望把异常原始信息保存下来,这样的多个异常组成的链条被称为【异常链】。

1. 在JDK1.4以前,程序员必须自己编写代码来保存原始异常信息,

2. 现在所有Throwable的子类子构造器中都可以接受一个cause对象作为参数,这个cause就异常原由,代表着原始异常,即使在当前位置创建并抛出行的异常,也可以通过这个cause追踪到异常最初发生的位置。

3. Throwable类及其所有的子类都提供了带cause参数的构造器, 其他的异常类就只有通过initCause()来设置cause了。

文章来源:智云一二三科技

文章标题:java程序员必备的基础知识_java异常机制(二)

文章地址:https://www.zhihuclub.com/183028.shtml

关于作者: 智云科技

热门文章

网站地图