1 什么是异常?
俗话说的好,金无足赤,人无完人。再完美的程序也有着难以避免的错误。我记得曾听一位巨佬说过,程序员其实本质上就是”面向bug编程”。(你在改bug的样子真的很靓仔..)说回正题,在Java的世界中也有着自己的一套方案,便于程序员时刻”救火”,检测程序中的一些漏洞,然后将系统一点一点变得稳定。

2 异常的分类
在Java这门语言中,将异常主要分为了两类,一类是指Exception和Exception的子类实例组成,称为异常;一类是指Error和Error的子类实例组成,称为错误,它们均都继承自Throwable类,下面来详细康康它们的区别:
-
错误是指在正常情况下不太可能出现的情况,如果出现了Error,在大多数情况下会使得程序崩溃(处于不可恢复状态),一般来说Error类对象由JAVA虚拟机生成并且抛出,常见的包括OutOfMemoryError,StackOverFlowError等…
-
异常又分为可检查(checked)异常和不可检查(unchecked)异常,可检查异常在代码中需要被显示捕获(一般来说IDE会显式提醒),像是IOException,SQLException,或者用户自定义异常等,这些异常时必须处理的,如果不处理程序就不能编译通过;而不可检查的异常就是运行时异常(RuntimeException),像是让大家头皮发麻的NullPointerException 空指针异常,ArithmeticException 算数运算异常 /zero,这类异常一般都是程序员在编码时出现疏忽,出现了逻辑上的错误。
看完了区别之后,咱们来一张异常概括性的”全家福”,看一看它们的整体脉络,方便下一步的梳理。

3 异常的处理机制
JAVA主要提供了两种机制进行处理异常代码
-
1、捕获异常 -
2、抛出异常
3.1 捕获异常
1. 关键语法 try catch finally
try{
//part1. do something
}catch(异常的类型 异常变量名){
//part2. do something
}finally{
//part3. do something
}
2. 详细分析
我将上面的代码主要分为3个区域,编号为1,2,3。下面分别介绍一下每块区域分别做什么事儿。
part1处于try块中,是自己写的目标代码
part2处于catch块中,是需要捕获的异常信息,当try块中的代码发生异常的时候,try后面的catch块就会响应,若发生的异常刚好包含在catch块中的话,异常就会自动被传到catch块中,然后在catch块中可以进行处理(比如说打印出异常的堆栈信息 => 可以打印到控制台上,或者写入文件,或者可以接入阿里的钉钉报警实时提醒报错信息等等)
part3处于finally块中,一般用来进行一些流的关闭,比如说对文件io流的关闭,或者数据库连接流的关闭等等,目的是为了节约资源,同时finally中的代码无论异常有没有发生,一定会执行
3. 代码实例
package com.liz;
/**
* Description: 异常处理 tip
* date: 2020/11/26 19:07
*
* @author 1z
*/
public class Demo {
public static void main(String[] args) {
try{
//part1 目标代码
int num = 1 / 0;
}catch (Exception e){
//part2 需要捕获的异常信息,在这里采用打印堆栈信息的方法处理异常
e.printStackTrace();
}
//finally {
//由于这里没有需要操作的文件流等,所以finally可以不需要
//}
}
}

4. 多重捕获情境
存在一个try语句后面跟着多个catch代码块,这种情况称为多重捕获
try{
//part1. do something
}catch(异常的类型1 异常变量名1){
//part2. do something
}catch(异常的类型2 异常变量名2){
//part3 do something
}catch(异常的类型3 异常变量名3){
//
}
finally{
//part3. do something
}
5. 关于try catch的一些小tip
-
try catch finally代码块均都不能独立存在
-
在try catch中可以不用加入finally(视需求而定 请参考上述finally的用法)
-
在try语句后面可以添加任意多的catch,但是catch的异常类型级别是从低到高,从子类到父类。(由于catch的逻辑从上到下,如果上面的异常已经捕获就不会走下面的代码,为了让代码更加健壮,因此catch内部设置异常的类型应该是从低级到高级,从子类到父类)
-
try语句是可以嵌套的,可以在try中嵌套另外一个try语句,但是由于堆栈的弹入弹出问题,一般这种方式不常用,因为难以阅读和梳理
-
无论有没有异常,finally中的代码都会执行,除特定需求外一定不要在finally中书写return语句,否则会导致程序的提前退出
3.2 抛出异常
-
关键语法 throw throws
throw 的作用是用来抛出明确的异常信息,一般用于方法中
public static void main(String[] args) {
//构建一个空指针异常吧!!
throw new RuntimeException("create a nullptr error");
}

package com.xq;
/**
* Description: 异常处理 tip
* date: 2020/11/26 19:07
*
* @author 1z
*/
public class Demo {
public static void main(String[] args) {
//构建一个空指针异常吧
try {
throw new RuntimeException("create a nullptr error");
} catch (Exception e) {
e.printStackTrace();
}
}
}

Tip1: throw后面new的实例一定是Throwable 或者 是Throwable的子类类型的对象
Tip2: 程序在执行throw语句后立刻停止执行后续的语句,然后将这个throw的结果转交给最邻近的try catch块进行处理,如果没有并没有try catch块处理,默认会中断程序的运行,然后打印程序堆栈
throws的作用是显示的抛出一个异常,代表着方法可能抛出的异常声明,提出声明是为了让其他方法知晓当前方法所有的异常,加以处理
/**
* Description: 异常处理 tip
* date: 2020/11/26 19:07
*
* @author 1z
*/
public class Demo {
public static void main(String[] args) {
//如果main方法调用func方法,根据throws提供的信息可以进行一系列处理并捕获
try {
func();
}catch (ArithmeticException e){
e.printStackTrace();
}
}
//throws 显示声明了当前func方法会报出ArithmeticException
public static void func() throws ArithmeticException{
int i = 1 / 0;
}
}
一点点小总结
这次的内容主要从JAVA的异常出发,整理总结了关于异常的处理方式,包括Exception,Error的区别,try-catch-finally和throw,throws的一些使用的技巧。如果上述文章出现了什么问题,请大家及时反馈,我会及时进行更正和修改。
最后的最后,留个小彩蛋吧!!
本文在处理异常信息的时候使用的是直接打印堆栈的方式,但是并不适用于以后的项目开发中,那么如何做到进一步利用异常信息,达到在文件中以日志形式展现甚至可以接入钉钉线上报警异常信息呢?
我是1z,咱们下期再聊吧。
原文始发于微信公众号(FingerDance):JAVA异常那些事儿
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/26816.html