什么是异常
异常本质上是程序上的错误,这个错误包括程序逻辑错误和系统错误。错误在程序中又有运行时异常和编译时异常。
编译异常在编译期间出错有编译器帮助错,然而运行期间的错误编译器则鞭长莫及了,并且运行期间的错误往往是难以预料的,但是如果不处理这些异常则会直接导致程序崩溃。因此在运行期间出现错误应该如何来补救昵?Java提供了异常机制来处理这些错误。
异常分类
在Java中的异常被当做对象来处理,根类为java.lang.Throwable
类,在Java中定义了很多异常类(如OutOfMemoryError
、NullPointerException
、IndexOutOfBoundsException
等),这些异常类分为两大类:Error
和Exception
。
Error
Error是无法处理的异常,比如OutOfMemoryError
,一般发生这种异常,JVM会自动终止程序,因此编写程序时不需要关心这类异常。
Exception
Exception,是经常见到的一些异常情况,比如NullPointerException
,这些异常是可以处理的。
Exception类的异常包括checked exception
和unchecked exception
(unchecked exception
也称运行时异常RuntimeException
,当然这里的运行时异常并不是前面所说的运行期间的异常,只是Java中用运行时异常这个术语来表示,Exception类的异常都是在运行期间发生的)。
unchecked exception
(非检查异常),也称运行时异常(RuntimeException),比如常见的NullPointerException
、IndexOutOfBoundsException
。对于运行时异常,java编译器不要求必须进行异常捕获处理或者抛出声明,由程序员自行决定。checked exception
(检查异常),也称非运行时异常(运行时异常以外的异常就是非运行时异常),java编译器强制程序员必须进行捕获处理,比如常见的IOExeption
和SQLException
。对于非运行时异常如果不进行捕获或者抛出声明处理,编译都不会通过。
在Java中,所有异常类的父类是Throwable
类,Error
类是error
类型异常的父类,Exception
类是exception
类型异常的父类,RuntimeException
类是所有运行时异常的父类,RuntimeException
以外的并且继承Exception
的类是非运行时异常。
典型的
RuntimeException
包括NullPointerException
、IndexOutOfBoundsException
、IllegalArgumentException
等。典型的非
RuntimeException
包括IOException
、SQLException
等。
Java中如何处理异常
在Java中如果需要处理异常,必须先对异常进行捕获,然后再对异常情况进行处理。
如何对可能发生异常的代码进行异常捕获和处理呢?使用try
和catch
关键字即可。
捕获异常
1 | try { |
在try中发生的异常,将交由catch进行处理。
抛出异常
1 | public class Main { |
在
createFile()
中并没有对异常进行处理,而是用throws
关键字声明抛出异常,即告知这个方法的调用者此方法可能会抛出IOException
。那么在main
方法中调用createFile
方法的时候,采用try...catch
块进行了异常捕获处理。
throw关键字手动来抛出异常
1 | public class Main { |
然后在catch块中进行捕获。
理解try,catch,finally,throws,throw五个关键字
try,catch,finally
try关键字用来包围可能会出现异常的逻辑代码,它单独无法使用,必须配合catch或者finally使用。Java编译器允许的组合使用形式只有以下三种形式:
try...catch...
;
try....finally......
;
try....catch...finally...
当然catch块可以有多个,注意try块只能有一个,finally块是可选的(但是最多只能有一个finally块)。
三个块执行的顺序为try—>catch—>finally
。
当然如果没有发生异常,则catch块不会执行。但是finally块无论在什么情况下都是会执行的(这点要非常注意,因此部分情况下,都会将释放资源的操作放在finally块中进行)。
在有多个catch块的时候,是按照catch块的先后顺序进行匹配的,一旦异常类型被一个catch块匹配,则不会与后面的catch块进行匹配。
1 | public String openFile() { |
这里finally中的返回值回吧catch里面的返回值给覆盖,也会把try中的return覆盖掉。从调试中可以看出来,try中就算有return,也会执行finally中。
总结:
throws和thow关键字
throws出现在方法的声明中,表示该方法可能会抛出的异常,然后交给上层调用它的方法程序处理,允许throws后面跟着多个异常类型;
throw一般会用于程序出现某种逻辑时程序员主动抛出某种特定类型的异常。throw只会出现在方法体中,当方法在执行过程中遇到异常情况时,将异常信息封装为异常对象,然后throw出去。throw关键字的一个非常重要的作用就是
异常类型的转换
。
throws表示出现异常的一种可能性,并不一定会发生这些异常;throw则是抛出了异常,执行throw则一定抛出了某种异常对象。两者都是消极处理异常的方式(这里的消极并不是说这种方式不好),只是抛出或者可能抛出异常,但是不会由方法去处理异常,真正的处理异常由此方法的上层调用处理。
异常处理建议
Throwable类中的常用方法
catch关键字后面括号中的Exception类型的参数e。Exception就是try代码块传递给catch代码块的变量类型,e就是变量名。catch代码块中语句”e.getMessage();”用于输出错误性质。通常异常处理常用3个函数来获取异常的有关信息:
getCause():返回抛出异常的原因。如果 cause 不存在或未知,则返回 null。
getMeage():返回异常的消息信息。
printStackTrace():对象的堆栈跟踪输出至错误输出流,作为字段 System.err 的值。
有时为了简单会忽略掉catch语句后的代码,这样try-catch语句就成了一种摆设,一旦程序在运行过程中出现了异常,就会忽略处理异常,而错误发生的原因很难查找。
Java常见异常
runtimeException子类
java.lang.ArrayIndexOutOfBoundsException
数组索引越界异常。当对数组的索引值为负数或大于等于数组大小时抛出。java.lang.ArithmeticException
算术条件异常。譬如:整数除零等。java.lang.NullPointerException
空指针异常。当应用试图在要求使用对象的地方使用了null时,抛出该异常。譬如:调用null对象的实例方法、访问null对象的属性、计算null对象的长度、使用throw语句抛出null等等java.lang.ClassNotFoundException
找不到类异常。当应用试图根据字符串形式的类名构造类,而在遍历CLASSPAH之后找不到对应名称的class文件时,抛出该异常。java.lang.NegativeArraySizeException
数组长度为负异常
java.lang.ArrayStoreException
数组中包含不兼容的值抛出的异常
java.lang.SecurityException
安全性异常
java.lang.IllegalArgumentException
非法参数异常
IOException
IOException
:操作输入流和输出流时可能出现的异常。
EOFException
:文件已结束异常
FileNotFoundException
:文件未找到异常
其他异常
ClassCastException
:类型转换异常类
ArrayStoreException
:数组中包含不兼容的值抛出的异常
SQLException
:操作数据库异常类
NoSuchFieldException
:字段未找到异常
NoSuchMethodException
:方法未找到抛出的异常
NumberFormatException
:字符串转换为数字抛出的异常
StringIndexOutOfBoundsException
:字符串索引超出范围抛出的异常
IllegalAccessException
:不允许访问某类异常
InstantiationException
:当应用程序试图使用Class类中的newInstance()方法创建一个类的实例,而指定的类对象无法被实例化时,抛出该异常
自定义异常
使用Java内置的异常类可以描述在编程时出现的大部分异常情况。除此之外,用户还可以自定义异常。用户自定义异常类,只需继承Exception类即可。
在程序中使用自定义异常类,大体可分为以下几个步骤。
(1)创建自定义异常类。
(2)在方法中通过throw关键字抛出异常对象。
(3)如果在当前抛出异常的方法中处理异常,可以使用try-catch语句捕获并处理;否则在方法的声明处通过throws关键字指明要抛出给方法调用者的异常,继续进行下一步操作。
(4)在出现异常方法的调用者中捕获并处理异常。