Java异常
什么是异常
程序运行过程中发生了不正常的情况,这种不正常的情况叫做:异常。
异常在Java中以类和对象形式存在。(面向对象)
异常的作用
异常处理机制的作用就是增强程序的健壮性。
异常发生了也不影响程序的执行。
异常的继承结构图
Throwable是Java 语言中所有错误或异常的超类,在 Java 中只有 Throwable 类型的实例才可以被抛出(throw)或者捕获(catch),它是异常处理机制的基本组成类型。 实例分为 Error 和 Exception 两种。
Error 类是指 java 运行时系统的内部错误和资源耗尽错误。应用程序不会抛出该类对象。
如果出现了这样的错误,除了告知用户,剩下的就是尽力使程序安全的终止。
Exception 又有两个分支 :
一个是运行时异常 RuntimeException ,一 个是编译时异常 CheckedException。
什么是编译时异常和运行时异常
编译时异常(受检异常,受控异常)和运行时异常(未受检异常,未受控异常),两者都发生在运行期间,
只不过编译时异常在编译期间必须处理,否则编译器会报错(throws/try catch),
而运行时异常,在编译期间可以不处理,编译器不报错。
编译时异常和运行时异常的区别
编译时异常一般发生的概率比较高。
例如:
你看到了外面正在写着倾盆大雨,你出门之前会预料到:如果不打伞,可能会生病(生病是一种异常),而且这个异常发生的概率非常高,所以我们出门前要拿一把伞。
“ 拿一把伞”就是对“生病异常”发生之前的一种处理方式。
对于一些发生概率较高的异常,需要在运行之前对其进行预处理。
运行时异常一般发生的概率比较低。
举个例子:
小明走在大街上,可能被鸟屎砸到,被鸟屎砸到也算是一种异常。
但是这种异常发生的概率比较低,在出门之前你没必要提前对这种发生概率较低的异常进行预处理。
如果你预处理这种异常,你将活得很累。
假设Java中没有对异常进行划分,没有分为:编译时异常,运行时异常,所有的异常都需要在编写 程序阶段进行预处理,会怎么样
首先,程序肯定是绝对的安全。
但是,程序员编写程序太累了,代码到处都是处理异常的代码。
就好比,一个人出门带着各种东西,大包小包的,人会非常累。
Java中对异常的两种处理方式
处理方式
第一种方式:在方法的声名的位置上,使用throws关键字,抛给上一级。
谁调用我,我就抛给谁。抛给调用者。
第二种方式:使用try catch语句进行异常的捕捉。
这个异常发生了,谁也不知道,因为我给抓住了。
举个例子:
我是公司的小职员,因为我的失误,导致公司损失了1000元(异常),
我有两种处理方式:
第一种方式:我把这件事告诉了我的领导(调用者)。【异常上抛】
第二种 方式:我自己掏腰包把这个钱给补上。【异常的捕捉】
思考:异常发生之后,我选择了上抛,抛给了我的调用者,调用者需要对这个异常进行处理,那么调用者同样又两个处理方式。
第一种方式:继续上抛
第二种方式:自己捕捉
注意:
Java中异常发生之后,如果一直上抛,最终抛给了main方法,main方法继续上抛,抛给了调用者JVM,JVM知道了这个异常的发生,只有一个结果:终止Java程序的执行。
但是不建议在main方法上使用throws。
异常处理机制的作用就是增强程序的健壮性。
即异常发生了也不影响程序的执行。
所以,一般main方法中的异常建议使用try catch进行捕捉,
main方法就不要继续上抛了。
哪里的代码执行,哪里的代码不执行?
只要异常没有捕捉,采用上报的方式,此方式的后续代码不会执行。一个方法体当中的代码出现异常之后,如果上报的话,此方法结束。
try语句块中的某一行出现异常,该行后面的代码不会执行。
try…catch捕捉异常之后,后续的代码可以执行。
深入try…catch
- catch后面小括号中的类型可以是具体的异常类型,也可以是该异常类型的父类型(多态)
- catch可以写多个。建议catch的时候,精确的一个一个处理,这样有利于程序的调试。
- catch写多个的时候,从上到下,必须遵守从小到大。
Java8新特性
catch写多个的时候,Java8中可以用 |
catch(FileNotFoundException | ArithmeticException | ... e)
上报和捕捉怎么选择
如果希望调用者来处理,选择throws上报。
其余情况使用try…catch捕捉的方式。
异常对象常用的方法
- getMessage(): 获取异常的简单描述信息。
- printStackTrace():打印异常追踪的堆栈信息。Java后台打印异常堆栈信息的时候,采用了异步线程的方式。
怎么看异常的追踪信息,可以快速的调试程序呢?
异常追踪信息,从上往下一行一行的看。
但是值得注意的是:SUN公司写的代码就不用看了。
主要问题一定是出现在了自己编写的代码上。
finally子句
在finally子句中的代码是最后执行的,并且是一定执行的,即使try语句块中的代码出现了异常。
finally子句必须和try一起出现,不能单独编写。没有catch语句也可以。
但是有一个特例:退出JVM之后,finally语句中的代码就不执行了。
try {
System.out.println("try.....");
System.exit(0);
} finally {
System.out.println("finally....");
}
throw与throws
throws
- 声明位置:方法名之后。
- 作用:通知调用者该方法在运行时,==【有可能】==抛出的异常。
- 携带数据:throws后面携带==【异常类型】==,一个throws后面可以携带多个异常类型。
- 调用:当一个方法被throws修饰时,调用方法时必须考虑异常捕捉的问题。
throw
- 声名位置:方法的执行体中。
- 作用:抛出一个指定的异常对象。
- 携带数据:throw后面携带==【异常对象】==,一个throw一次只能携带一个异常对象。
- 调用:当一个方法内部存在throw命令时,如果抛出的异常对象是编译时异常, 则需要在方法申明时加上该异常的抛出 ,即需要加上throws语句 ,或者在方法体内try catch捕捉处理该异常,否则编译报错 。执行到 throw 语句则后面的语句块不再执行。
Java中怎么自定义异常
第一步:编写一个类继承Exception或者RuntimeException
第二步:提供两个构造方法,一个无参的,一个带有String参数的。
|