概念
异常是指程序在运行过程中出现的各种不正常的事情,称之为异常。
异常分类
1、Throwable
Throwable是所有异常的父类,它共有两个子类Error和Exception
2、Error(错误)
错误是指程序在运行过程中出现的硬件、jvm错误,比如内存溢出,栈溢出等等,此类错误无法在程序中处理。
常见的Error
StackOverflowError 栈溢出
OutOfMemoryError 内存溢出
2、Exception(异常)
异常是指程序在运行过程中,因为代码编写出现了问题导致的程序异常,此类异常是可以通过修改代码解决的。
此类异常又分为两种,受检异常和非受检异常,除RunTimeException和Error之外的其他异常都为受检异常。
1)、受检异常
在程序编写过程中就要处理的异常,比如FileNotFoundException找不到文件异常,
2)、非受检异常
在程序编写过程中不强制处理的异常。比如ArrayIndexOutOfBoundsException数组越界异常
异常的处理
异常处理的五个关键字
try :将有可能会出现异常的代码放到try代码块中。
catch :捕获异常的处理,在此代码块中捕获可能会出现的异常。
finally : 此代码块中编写出现异常后需要执行的代码,一般用于资源的释放。
throw : 此关键字用在方法体内,用于在程序中主动抛出异常,一般用于抛出参数传递错误,比如当用户输入的年龄或日期超出规定范围的时候可以抛出对应的异常或自定义异常。
throws : 此关键字用与定义方法的时候,将方法体内的异常向外抛出。
语法规则
FileInputStream fis = null;
try{
int i = 10/0;
fis = new FileInputStream("d:\\不存在.txt");
}catch (ArithmeticException e) {
e.printStackTrace();
}catch (FileNotFoundException e) {
e.printStackTrace();
//e.printStackTrace() 在实际生产中不要用,因为它除了不断的刷控制台,并没用什么用,而且会导致日志系统无法采集到异常错误的具体信息比如日期,时间,等级等等
} finally {
if(fis != null) {
try {
fis.close(); //防止多线程场景下会出错
} catch (IOException e) {
e.printStackTrace();
}
}
注意
- 一个try可以匹配多个catch语句
- catch代码块中的代码只有捕获到异常时才会执行
- 多个catch语句从上到下捕获的异常应该是由小到大。
- finally中的代码一定会执行。
- 当try中出现了异常,程序不会执行后面的代码,直接到响应的catch中进行异常的捕获。
- 对于throws来讲,子类只能抛出比父类更小或相同的异常。
try-with-resources
try-with-resources是jdk1.7引入的语法糖
它的出现优化了在finally中关闭各种资源的操作。需要注意的是并非所有的类都能用try-with-resources处理,要使用try-with-resource的资源,必须先实现AutoCloseable接口,其中包含了单个返回void的close方法,Java类库与第三方类库中的许多类和接口,现在都实现或扩展了AutoCloseable接口,因此我们现在不必实现了。
通过try-finally处理
public class Demo {
public static void main(String[] args) {
BufferedInputStream bin = null;
BufferedOutputStream bout = null;
try {
bin = new BufferedInputStream(new FileInputStream(new File("test.txt")));
bout = new BufferedOutputStream(new FileOutputStream(new File("out.txt")));
int b;
while ((b = bin.read()) != -1) {
bout.write(b);
}
}
catch (IOException e) {
e.printStackTrace();
}
finally {
if (bin != null) {
try {
bin.close();
}
catch (IOException e) {
throw e;
}
finally {
if (bout != null) {
try {
bout.close();
}
catch (IOException e) {
throw e;
}
}
}
}
}
}
}
通过try-with-resources处理异常
public class TryWithResource {
public static void main(String[] args) {
try (BufferedInputStream bin = new BufferedInputStream(new FileInputStream(new File("test.txt")));
BufferedOutputStream bout = new BufferedOutputStream(new FileOutputStream(new File("out.txt")))) {
int b;
while ((b = bin.read()) != -1) {
bout.write(b);
}
}
catch (IOException e) {
e.printStackTrace();
}
}
}
自定义异常
public class AgeException extends Exception {
public AgeException() {
}
public AgeException(String message) {
super(message);
}
}
常见面试题
Error 和 Exception 区别是什么?
Error是错误,是jvm或硬件出现了问题。此类异常无法通过代码处理,一般在程序中也不会对Error进行处理。
Exception是异常,可以通过代码处理,Exception又分为两种,受检异常(必须在代码编写过程中处理),非首检异常(可处理可不处理)。
throw 和 throws 的区别是什么?
throw使用在方法体内,用于主动抛出一个异常,常用于处理错误参数等。
throws定义在方法的声明上,用于将异常向上抛出,谁调用谁处理。
NoClassDefFoundError 和ClassNotFoundException区别?
NoClassDefFoundError是错误,编译时有此类,运行时在内存中找不到此类,
ClassNotFoundException是受检异常,在使用Class.getForName、Classloader.loadClass时需要处理此异常。
通过传入的类路径参数没有找到该类,就会抛出该异常;另一种抛出该异常的可能原因是某个类已经由一个类加载器加载至内存中,另一个加载器又尝试去加载它。
try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?
常见的 RuntimeException 有哪些?
ClassCastException(类转换异常)
IndexOutOfBoundsException(数组越界)
NullPointerException(空指针)
ArrayStoreException(数据存储异常,操作数组时类型不一致)
Java常见异常有哪些
java.lang.OutOfMemoryError:内存不足错误。当可用内存不足以让Java虚拟机分配给一个对象时抛出该错误。
java.lang.StackOverflowError:堆栈溢出错误。当一个应用递归调用的层次太深而导致堆栈溢出或者陷入死循环时抛出该错误。
java.lang.ClassCastException:类造型异常。假设有类A和B(A不是B的父类或子类),O是A的实例,那么当强制将O构造为类B的实例时抛出该异常。该异常经常被称为强制类型转换异常。
java.lang.ClassNotFoundException:找不到类异常。当应用试图根据字符串形式的类名构造类,而在遍历CLASSPAH之后找不到对应名称的class文件时,抛出该异常。
java.lang.ArithmeticException:算术条件异常。譬如:整数除零等。
java.lang.ArrayIndexOutOfBoundsException:数组索引越界异常。当对数组的索引值为负数或大于等于数组大小时抛出。
java.lang.IndexOutOfBoundsException:索引越界异常。当访问某个序列的索引值小于0或大于等于序列大小时,抛出该异常。
java.lang.NoSuchFieldException:属性不存在异常。当访问某个类的不存在的属性时抛出该异常。
java.lang.NoSuchMethodException:方法不存在异常。当访问某个类的不存在的方法时抛出该异常。
java.lang.NullPointerException:空指针异常。当应用试图在要求使用对象的地方使用了null时,抛出该异常。譬如:调用null对象的实例方法、访问null对象的属性、计算null对象的长度、使用throw语句抛出null等等。
java.lang.NumberFormatException:数字格式异常。当试图将一个String转换为指定的数字类型,而该字符串确不满足数字类型要求的格式时,抛出该异常。
异常处理-阿里巴巴Java开发手册
- 【强制】Java 类库中定义的可以通过预检查方式规避的RuntimeException异常不应该通过catch 的方式来处理,比如:NullPointerException,IndexOutOfBoundsException等等。 说明:无法通过预检查的异常除外,比如,在解析字符串形式的数字时,可能存在数字格式错误,不得不通过catch NumberFormatException来实现。 正例:if (obj != null) {…} 反例:try { obj.method(); } catch (NullPointerException e) {…}
- 【强制】catch时请分清稳定代码和非稳定代码,稳定代码指的是无论如何不会出错的代码。对于非稳定代码的catch尽可能进行区分异常类型,再做对应的异常处理。 说明:对大段代码进行try-catch,使程序无法根据不同的异常做出正确的应激反应,也不利于定位问题,这是一种不负责任的表现。
正例:用户注册的场景中,如果用户输入非法字符,或用户名称已存在,或用户输入密码过于简单,在程序上作出分门别类的判断,并提示给用户。 - 【强制】捕获异常是为了处理它,不要捕获了却什么都不处理而抛弃之,如果不想处理它,请将该异常抛给它的调用者。最外层的业务使用者,必须处理异常,将其转化为用户可以理解的内容。
- 【强制】finally块必须对资源对象、流对象进行关闭,有异常也要做try-catch。 说明:如果JDK7及以上,可以使用try-with-resources方式。
- 【强制】不要在finally块中使用return。 说明:try块中的return语句执行成功后,并不马上返回,而是继续执行finally块中的语句,如果此处存在return语句,则在此直接返回,无情丢弃掉try块中的返回点。 反例:
private int x = 0;
public int checkReturn() {
try {
// x等于1,此处不返回
return ++x;
} finally {
// 返回的结果是2
return ++x;
}
}
参考文章: