异常的作用
异常的引入提高了程序的健壮性.当程序运行出现意外情形时,系统会自动生成一个Exception对象来通知程序,从而提高容错性.先来看异常的使用方式和作用.
public class MainTest {
public static void main(String[] args) {
int a = 10;
int b = 0;
//这里除数是0,会产生异常,因为我们没有处理,会导致JVM崩掉
int c = a / b;
System.out.println(c + "");
}
}
运行会发现JVM崩掉
Exception in thread "main" java.lang.ArithmeticException: / by zero
at com.company.eric.Exception.MainTest.main(MainTest.java:11)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Process finished with exit code 1
使用异常处理
public class MainTest {
public static void main(String[] args) {
try {
int a = 10;
int b = 0;
//这里除数是0,会产生异常,因为我们没有处理,会导致JVM崩掉
int c = a / b;
System.out.println(c + "");
}catch (ArithmeticException e){
System.out.println("出现了算数错误");
e.printStackTrace();
}
}
}
JVM正常退出,从Process finished with exit code 0可以看出
出现了算数错误
java.lang.ArithmeticException: / by zero
at com.company.eric.Exception.MainTest.main(MainTest.java:13)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Process finished with exit code 0
异常的引入可以让程序即使出现了错误,也可以运行,不至于让JVM崩掉.程序中出现的有些小错误是不影响程序的整体运行的,我们可以对异常进行捕获和处理,不让程序崩掉.
Java异常体系结构
- Error 是程序无法处理的错误,比如OutOfMemoryError、ThreadDeath等.这些异常发生时,Java虚拟机(JVM)一般会选择线程终止.
- Exception 又分为非运行时异常(Checked exception)和运行时异常(Runtime exception)
- Checked exception 必须要对其进行处理,否则无法通过编译。处理方式可以用try catch捕获或将其继续抛出
- Runtime exception 可以对其进行处理,也可以不处理。
异常处理的一般结构
1.捕获异常
try
{
// 可能发生异常的代码
// 如果发生了异常,那么异常之后的代码都不会被执行
}
catch (Exception e)
{
// 异常处理代码
}
finally
{
// 不管有没有发生异常,finally语句块都会被执行
}
- try语句块,表示要尝试运行代码,try语句块中代码受异常监控,其中代码发生异常时,会抛出异常对象。
- catch语句块会捕获try代码块中发生的异常并在其代码块中做异常处理,catch语句带一个Throwable类型的参数
- 表示可捕获异常类型。当try中出现异常时,catch会捕获到发生的异常,并和自己的异常类型匹配,若匹配,则执行catch块中代码,并将catch块参数指向所抛的异常对象。catch语句可以有多个,用来匹配多个中的一个异常,一旦匹配上后,就不再尝试匹配别的catch块了。通过异常对象可以获取异常发生时完整的JVM堆栈信息,以及异常信息和异常发生的原因等。
- finally语句块是紧跟catch语句后的语句块,这个语句块总是会在方法返回前执行, 而不管是否try语句块是否发生异常。并且这个语句块总是在方法返回前执行。这是一个必定执行的语句块,除非JVM退出.
try、catch、finally三个语句块应注意的问题
- try、catch、finally三个语句块均不能单独使用,三者可以组成try…catch…finally、try…catch、try…finally三种结构,catch语句可以有一个或多个,finally语句最多一个.
- try、catch、finally三个代码块中变量的作用域为代码块内部,分别独立而不能相互访问。如果要在三个块中都可以访问,则需要将变量定义到这些块的外面。
- 多个catch块时候,只会匹配其中一个异常类并执行catch块代码,而不会再执行别的catch块,并且匹配catch语句的顺序是由上到下。
捕获Exception后可以调用的常用方法
- getCause():返回抛出异常的原因。如果 cause 不存在或未知,则返回 null.
- getMessage():返回异常的消息信息.
- printStackTrace():对象的堆栈跟踪输出至错误输出流,作为字段 System.err 的值。
2.继续抛出
public class MainTest {
public static void main(String[] args) throws FileNotFoundException {
BufferedReader br = new BufferedReader(
new InputStreamReader(
new FileInputStream("test.txt")));
}
}
- throws关键字用于方法体外部的方法声明部分,用来声明方法可能会抛出某些异常.
- throw关键字是用于方法体内部,用来抛出一个Throwable类型的异常.
自己在方法中用throw抛出异常,用throws来表明该方法可能抛出的异常
public void demo() throws Exception {
throw new Exception("测试throw抛出异常");
}
异常的流程:
异常的处理流程还是符合我们现实的生活的;当分配到一件任务时,先看你自己能不能处理,如果能处理的话就处理掉,不能则将任务交给你的上级,你的上级也按照这个判断方式处理;若一直得不到处理,最终交给了公司领导,领导也处理不了,公司关门,游戏结束,……..
自定义异常
尽管Java中有一些常见的异常,但是这些可能不满足我们的需求,我们需要定制自己的异常类
自定义的异常(这里使用的Checked Exception,所以必须对这些异常进行处理,否则不能通过编译)
public class MyException extends Exception{
public MyException(){
super();
}
public MyException(String message){
super(message);
}
}
编写程序时使用该异常,遇到错误手动抛出异常
public class RepeatMachine {
public static void repeatMessage(String message) throws MyException {
if (message == null) {
throw new MyException("输入对象不能为Null");
}
System.out.println(message);
}
}
使用携带抛出异常的类时要对异常进行处理
public class MainTest {
public static void main(String[] args) {
try {
RepeatMachine.repeatMessage(null);
} catch (MyException e) {
System.out.println(e.getMessage());
}
}
}
输出结果
输入对象不能为Null
Process finished with exit code 0
这里演示使用的Runtime exception(即使不对异常进行处理,也可通过编译)
public class MyException extends RuntimeException{
public MyException(){
super();
}
public MyException(String message){
super(message);
}
}
public class RepeatMachine {
public static void repeatMessage(String message){
if (message == null) {
throw new MyException("输入对象不能为Null");
}
System.out.println(message);
}
}
public class MainTest {
public static void main(String[] args) {
try {
RepeatMachine.repeatMessage(null);
} catch (MyException e) {
System.out.println(e.getMessage());
}
RepeatMachine.repeatMessage("My name is Eric");
}
}
输出结果
输入对象不能为Null
My name is Eric
Process finished with exit code 0