浅谈Java中的异常种类

前言

一般来讲,关于报错信息主要分为两大类,即Exception(异常)Error(错误),有时候我们用“异常”来统称这两种情况,在本文中,将会就这两种情况做进一步的讲解

同时,在这里我先声明,本文将不含Java对异常的处理方式、各个异常的详细讲解以及编译后代码中异常处理的讲解,而仅仅是针对Java中各种异常大类做一个粗略的讨论

概念

我们一般将宏观概念的异常分为以下两类,它们都属于Java中Throwable的子类:

  • Error
  • Exception

而Exception又可以进一步划分为以下这些种类:

  • 受检异常/编译期异常
  • 非受检异常/运行时异常

关于这些概念都是什么意思,接下来就会马上来进行进一步的讲解

Error

Error一般是程序中较严重的出错,是虚拟机层面的异常,一旦发生将会导致系统崩溃,无法由程序自身处理,通常有以下两种情况:

  • OutOfMemoryError:又称OOM,表示内存溢出错误,通常发生在内存泄露或内存不足的情况
  • StackOverflowError:表示栈溢出错误,通常发生在递归过深的情况

这两种异常一个通常发生在Java堆上,一个通常发生在虚拟机栈上,看到共同点了吗?没错,就是Error通常和JVM的内存区域脱不开关系,一旦程序报了Error,那我们一般都会去查看heap dump文件、修改JVM参数等一系列底层措施,而且一旦发生了Error,程序是会直接崩溃的,不能采取任何Java代码层面的措施来弥补

Exception

Exception相比于Error就不那么严重,但是发生的次数却相当频繁,不过Java为我们提供了try-catch系列语法来捕获这些异常。既然是捕获,那相比于Error发生只能眼睁睁看着系统崩溃,Exception我们可以进行手动的捕获操作,当异常发生时,进行一些处理操作,来尽可能减少其危害

Exception相比于Error来讲,种类极为繁多,所以我们将Exception按照特性,分为受检异常非受检异常,接下来我们就会针对这两种情况再单独讨论

受检异常/编译期异常

受检异常,也叫编译期异常,一般我们指需要在代码中显式处理的异常,如今的编译器会强制提示你进行try-catch的捕获,同时Java也强制约束你进行捕获操作,否则就会在编译阶段报错,这也是编译期异常名字的由来

这类异常也可以再进一步划分,这里参考阿里公司出版的《码出高效:Java开发手册》,将受检异常进一步划分为以下两类:

  • 不可处理异常:程序无法自行处理的异常,进行任何试图解决异常的行为都是于事无补的,最常见的处理方式是完整保存现场状态,供之后分析解决
  • 可处理异常:程序可以进行一些设置好的操作来尽最大程度降低异常的影响,这些异常中很大一部分是我们预计会发生的,属于程序执行流的一环

不可处理异常中,常见的有SQLException、ClassNotFoundException等,这些异常发生时,无论怎么重试,怎么处理都是于事无补的,只能回头检查程序

这类错误一般都是代码编写错误或者配置文件配置项错误,Java程序是不可能帮你手动更改的,但是由于这种异常发生后会导致一系列连锁反应,所以Java语言会强制你捕获这类异常,这类异常的捕获并不是为了进行处理,而是为了让程序提前终止,来让你尽早排查错误

可处理异常中,最常见的就是各种安全框架中的未认证异常和登陆失败异常,这类异常通常属于我们规划好的执行流图中的一环,我们也早就准备好了发生异常时的处理措施,比如进行页面跳转之类

这类错误一般是由于一些外部因素,且这些外部因素发生概率非常高,所以Java语言强制需要你进行捕获,这类异常的捕获通常是为了让程序能够继续执行,或者安全正常的结束

非受检异常/运行时异常

非受检异常,一般是由于运行时的各种意外情况导致程序运行异常,所以很多人习惯称之为运行时异常,这类异常均继承自RuntimeException。Java语言不强制对这类异常进行捕获,但是仍可以进行手动捕获,来避免可能发生的意外

同样地,我们仍可以对这一类异常做进一步的划分:

  • 可预测异常(Predicted Exception):可以预测到会发生的异常,一般是由于代码错误或外部因素导致
  • 警告级异常(Caution Exception):需要进行显式的捕获处理的异常,否则就会导致程序不可用
  • 可忽略异常(Ignored Exception):程序或框架会自行处理的异常,程序员可以忽略

可预测异常,最常见的就是NullPointerException(空指针异常)和IndexOutOfBoundsException(数据越界异常),这类异常我们完全可以通过提前检查来进行避免

Java不要求我们强制捕获这类异常,一个原因是这类异常在任何需要传入对象参数的函数中都要进行捕获,如果强制捕获会导致代码过长,另一个原因是这类异常的捕获完全可以通过参数检验来代替,使用性能低下的try-catch反而是一种不良的编码习惯

警告级异常,也有地方叫做需捕捉异常,一般是由一些框架的基础方法抛出,因为这类异常如果发生会导致整个服务不可用,所以需要进行捕获处理,比如超时异常之类

可忽略异常,这类异常通常我们见不到,因为基本都由底层框架来进行处理,我们只需要知道这类异常不由程序员进行捕获处理就可以了

总结

整个Java的异常分类就是这样了,我在下面总结了一幅图,来作为整篇文章的收尾:
总结

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章