Java常见异常及处理⽅式总结
⽬录
⼀、概述
⼆、异常分类
三、声明及抛出
四、捕获异常
五、捕获多个异常
六、⾃定义异常
七、异常堆栈
⼀、概述
异常指不期⽽⾄的各种状况,它在程序运⾏的过程中发⽣。作为开发者,我们都希望⾃⼰写的代码永远
都不会出现 bug,然⽽现实告诉我们并没有这样的情景。如果⽤户在程序的使⽤过程中因为⼀些原因造成他的数据丢失,这个⽤户就可能不会再使⽤该程序了。所以,对于程序的错误以及外部环境能够对⽤户造成的影响,我们应当及时报告并且以适当的⽅式来处理这个错误。
之所以要处理异常,也是为了增强程序的鲁棒性。
异常都是从 Throwable 类派⽣出来的,⽽ Throwable 类是直接从 Object 类继承⽽来。你可以在 Java SE 官⽅ API ⽂档中获取更多关于它们的知识。
⼆、异常分类
异常通常有四类:
Error:系统内部错误,这类错误由系统进⾏处理,程序本⾝⽆需捕获处理。
Exception:可以处理的异常。
RuntimeException:可以捕获,也可以不捕获的异常。
继承 Exception 的其他类:必须捕获,通常在 API ⽂档中会说明这些⽅法抛出哪些异常。
平时主要关注的异常是 Exception 下的异常,⽽ Exception 异常下⼜主要分为两⼤类异常,⼀个是派⽣于 RuntimeExcption 的异常,⼀个是除了 RuntimeExcption 体系之外的其他异常。
RuntimeExcption 异常(运⾏时异常)通常有以下⼏种:
错误的类型转换
数组访问越界
访问null指针
算术异常
⼀般来说,RuntimeException 都是代码逻辑出现问题。
⾮ RuntimeException(受检异常,Checked Exception)⼀般有:
打开⼀个不存在的⽂件
没有到具有指定名称的类
操作⽂件异常
受检异常是编译器要求必须处理的异常,必须使⽤try catch处理,或者使⽤throw抛出,交给上层调⽤者处理。
三、声明及抛出
throw 抛出异常
当程序运⾏时数据出现错误或者我们不希望发⽣的情况出现的话,可以通过抛出异常来处理。
异常抛出语法:
throw new 异常类();
新建 ThrowTest.java:
public class ThrowTest {
public static void main(String[] args) {
Integer a = 1;
Integer b = null;
//当a或者b为null时,抛出异常
if (a == null || b == null) {
throw new NullPointerException();
} else {
System.out.println(a + b);
}
}
}
运⾏:
Exception in thread "main" java.lang.NullPointerException
at ThrowTest.main(ThrowTest.java:8)
throws 声明异常
throws ⽤于声明异常,表⽰该⽅法可能会抛出的异常。如果声明的异常中包括 checked 异常(受检异常),那么调⽤者必须捕获处理该异常或者使⽤ throws 继续向上抛出。throws 位于⽅法体前,多个异常之间使⽤ , 分割。
新建ThrowsTest.java:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class ThrowsTest {
public static void main(String[] args) throws FileNotFoundException {
//由⽅法的调⽤者捕获异常或者继续向上抛出
throwsTest();
}
public static void throwsTest() throws FileNotFoundException {
new FileInputStream("/home/project/shiyanlou.file");
}
}
编译运⾏:
Exception in thread "main" java.io.FileNotFoundException: /home/project/shiyanlou.file (系统不到指定的路径。
)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at java.io.FileInputStream.<init>(FileInputStream.java:93)
at ThrowsTest.throwsTest(ThrowsTest.java:13)
at ThrowsTest.main(ThrowsTest.java:8)
四、捕获异常
通常抛出异常后,还需要将异常捕获。使⽤ try 和 catch 语句块来捕获异常,有时候还会⽤到 finally。
对于上述三个关键词所构成的语句块,try 语句块是必不可少的,catch 和 finally 语句块可以根据情况选择其⼀或者全选。你可以把可能发⽣错误或出现问题的语句放到 try 语句块中,将异常发⽣后要执⾏的语句放到 catch 语句块中,⽽ finally 语句块⾥⾯放置的语句,不管异常是否发⽣,它们都会被执⾏。
你可能想说,那我把所有有关的代码都放到 try 语句块中不就妥当了吗?可是你需要知道,捕获异常对于系统⽽⾔,其开销⾮常⼤,所以应尽量减少该语句块中放置的语句。
新建 CatchException.java:
public class CatchException {
public static void main(String[] args) {
try {
// 下⾯定义了⼀个try语句块
System.out.println("I am try block.");
Class<?> tempClass = Class.forName("");
// 声明⼀个空的Class对象⽤于引发“类未发现异常”
System.out.println("Bye! Try block.");
} catch (ClassNotFoundException e) {
// 下⾯定义了⼀个catch语句块
System.out.println("I am catch block.");
e.printStackTrace();
//printStackTrace()的意义在于在命令⾏打印异常信息在程序中出错的位置及原因
System.out.println("Goodbye! Catch block.");
} finally {
// 下⾯定义了⼀个finally语句块
System.out.println("I am finally block.");
}
}
}
编译运⾏:
I am try block.
I am catch block.
java.lang.ClassNotFoundException:
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Unknown Source)
at CatchException.main(CatchException.java:8)
Goodbye! Catch block.
I am finally block.
五、捕获多个异常
在⼀段代码中,可能会由于各种原因抛出多种不同的异常,⽽对于不同的异常,我们希望⽤不同的⽅式来处理它们,⽽不是笼统的使⽤同⼀个⽅式处理,在这种情况下,可以使⽤异常匹配,当匹配到对应的异常后,后⾯的异常将不再进⾏匹配。
新建源代码⽂件 MultipleCapturesDemo.java:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class MultipleCapturesDemo {
public static void main(String[] args) {
try {
new FileInputStream("");
} catch (FileNotFoundException e) {
System.out.println("IO 异常");
} catch (Exception e) {
System.out.println("发⽣异常");
}
}
}
编译运⾏:
IO 异常
在处理异常时,并不要求抛出的异常同catch所声明的异常完全匹配,⼦类的对象也可以匹配⽗类的处理程序。⽐如异常 A 继承于异常 B,那么在处理多个异常时,⼀定要将异常 A 放在异常 B 之前捕获,如果将异常 B 放在异常 A 之前,那么将永远匹配到异常 B,异常 A 将永远不可能执⾏,并且编译器将会报错。
六、⾃定义异常
尽管 Java SE 的 API 已经为我们提供了数⼗种异常类,然⽽在实际的开发过程中,你仍然可能遇到未知的异常情况。此时,你就需要对异常类进⾏⾃定义。
⾃定义⼀个异常类⾮常简单,只需要让它继承 Exception 或其⼦类就⾏。在⾃定义异常类的时候,建议同时提供⽆参构造⽅法和带字符串参数的构造⽅法,后者可以为你在调试时提供更加详细的信息。
百闻不如⼀见,下⾯我们尝试⾃定义⼀个算术异常类。
创建⼀个 MyAriException 类:
主要的代码如下:
// MyAriException.java
public class MyAriException extends ArithmeticException {
//⾃定义异常类,该类继承⾃ArithmeticException
public MyAriException() {
}
//实现默认的⽆参构造⽅法
public MyAriException(String msg) {
super(msg);
}
//实现可以⾃定义输出信息的构造⽅法,将待输出信息作为参数传⼊即可
}
添加⼀个 ExceptionTest 类作为测试⽤,在该类的 main() ⽅法中,可以尝试使⽤ throw 抛出⾃定义的异常。
代码⽚段如下:
// ExceptionTest.java
import java.util.Arrays;
public class ExceptionTest {
public static void main(String[] args) {
int[] array = new int[5];
//声明⼀个长度为5的数组
Arrays.fill(array, 5);
//将数组中的所有元素赋值为5
for (int i = 4; i > -1; i--) {
//使⽤for循环逆序遍历整个数组,i每次递减
if (i == 0) {
// 如果i除以了0,就使⽤带异常信息的构造⽅法抛出异常
throw new MyAriException("There is an exception occured.");
}
System.out.println("array[" + i + "] / " + i + " = " + array[i] / i);
// 如果i没有除以0,就输出此结果
}
}
}
检查⼀下代码,编译并运⾏,期待中的⾃定义错误信息就展现在控制台中了:
array[4] / 4 = 1
array[3] / 3 = 1
array[2] / 2 = 2
array[1] / 1 = 5
Exception in thread "main" MyAriException: There is an exception occured.try catch的使用方法
at ExceptionTest.main(ExceptionTest.java:17)
七、异常堆栈
当异常抛出后,我们可以通过异常堆栈追踪程序的运⾏轨迹,以便我们更好的 DEBUG。
新建⼀个 ExceptionStackTrace.java:
public class ExceptionStackTrace {
private static void method1() {
method2();
}
private static void method2() {
throw new NullPointerException();
}
public static void main(String[] args) {
try {
method1();
} catch (Exception e) {
//打印堆栈轨迹
e.printStackTrace();
}
}
}
编译运⾏:
java.lang.NullPointerException
hod2(ExceptionStackTrace.java:7)
hod1(ExceptionStackTrace.java:3)
at ExceptionStackTrace.main(ExceptionStackTrace.java:11)
通过上⾯的异常堆栈轨迹,在对⽐我们⽅法的调⽤过程,可以得出异常信息中⾸先打印的是距离抛出异常最近的语句,接着是调⽤该⽅法的⽅法,⼀直到最开始被调⽤的⽅法。从下往上看,就可以得出程序运⾏的轨迹。
到此这篇关于Java常见异常及处理⽅式总结的⽂章就介绍到这了,更多相关Java异常内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论