Java异常
在Java中,我们会经常遇到“异常”这种现象,那么什么是异常呢?
异常其实就是程序上的错误,在我们编写程序的过程中经常会产生发生错误,包括编译期间的错误和运行期间的错误。是在Java开发过程中面对到的各种状况,大家可以理解她为一种事件。当发生在程序的运行期间会干扰各种流程。
在Java中是通过Throwable以及与他相关的各种子类进行描述的。
Throwable是根类,它有两个子类分别是:Exception,Error。
Error: 是程序无法解决的错误,表示运行应用程序中出现的较为严重的问题。
常见的错误有
- 虚拟机错误(VirtualMachineError)
- 内存溢出(OutOfMemoryError)
- 线程死锁(ThreadDeath)
Exception:是程序本身可以处理的异常,异常处理通常指针对这种类型异常的处理。
常包括
- 检查异常(CheckException):编译器要求必须在代码阶段就处理这些异常
- IO异常(IOException)
- SQL异常(SQLException)
- 非检查异常(UnCheckException):是指编译器非强制要求处理的异常,包括RuntimeException以及它的子类包括
- 空指针异常(NullPointerException)
- 数组下标越界异常(ArryIndexOutOfBoundsException)
- 算数异常(ArithmeticException)
- 类型转换异常(ClassCastException)
在Java应用程序中,异常处理机制一般分为:抛出异常&捕获异常
他的整体流程大概是:
1.程序首先要抛出异常之后才才可以捕获异常,而抛出异常通常是当一个方法中出现错误引发异常时,方法会创建异常对象并且交付给运行系统进行处理
异常对象(Exception Object)通常包括
- 异常类型
- 异常出现时的程序状态
2.而当运行时系统捕获到该异常时,就会进入到捕获异常环节,该阶段,系统会自动逐步去寻找适合的处理器,如果找到与抛出异常匹配的处理器,就会还行相关的处理逻辑,如果没有找到,系统就会终止,此时Java程序就会停止运行。
实现阶段
异常处理通常通过以下五个阶段实现的
try, catch, finally, throw, throws
常见的结构为:
public void method(){
try{
//代码段1
//产生异常的代码段2
}
catch(异常类型ex){
//对异常进行处理的代码段3
}
finally{
//代码段4
}
}
- try:用于捕获异常
- catch:用于针对try块捕获到的异常
- finally:无论是否发生异常代码块在此语句下的代码块都可以执行
语法要求:try块后可以链接零个或者多个catch块,如果没有catch块,则必须跟一个finally块,必须组合适应,不可以单独使用。
场景:
场景1
首先在我们的eclipse中创建包,新建com.kilig.Test工程,然后新建TryDemoOne的测试包:
要求:定义两个整数,输出两个数的商。
目前来看是没有爆发任何错误的,那是由于目前我们的结果是被定义死的,不会出错,但是一旦整个程序中有用户加入,那么就会爆发很多错误。
场景2
现在需求改为,要求可以接受用户键盘的输入,针对用户的输入信息,产生新的效果。
现在来看,也是没有报错的,但是如果用户输入的数据发生问题怎么半?比方说用户输入的新数据除数是0,会发生什么呢?
我们可以看到,程序报错了,是main方法执行过程中,算数产生异常。可以看到,程序已经无法正常运行结果
如果用户输入的是一个字母呢?
可以看到这是一个格式错误的异常
可以看到,在如此简单的程序运行过程中,我们都会会面临到各种个样的异常,我们无法控制或者限制人为去改变这些异常,那么我们只能通过控制程序,智能化的改变这些异常,接下来让我们给程序加一套装备!
使用try-catch结构处理异常:
分析:在研究代码中,我们发现,在人为输入的过程中,就会发生有可能引起异常的原因了,所以我们需要未雨绸缪,将灭霸扼死在摇篮中!
测试:
我们可以看到,当在容易发生大代码块用Try包裹起来后,如果发生异常,会进入到Catch块中,执行异常对象,不会爆发红色的报错信息。如果没有异常,会跳过Catch块,正常运行,说明理论上这是行得通!(就像我们在逛淘宝时,突然屏幕产生了一个位置的错误,但是程序不会终止,而是提交到后台去运行解决,而不影响我们接着逛)
那么怎样才能让我们知道程序哪一个部位出错,而且程序继续执行,得出正确结果呢?让我们继续往下做。
1.在捕获的catch参数中,e对象有一个方法,printStackTrace() 它能精准的打印出错误的堆栈信息,描述,错误的位置
此外,为了以防万一,我们可以给语句加上finally块,保证必须执行的要求。
此外,try后面可以跟多个catch块,那么就意味着我们可以将不同类型的错误信息,数出来,让我们可以更加明显的看到不同类型的错误。然后通常在最后需要添加一个Exception的最后一道关防来防护代码块,目的就是捕获漏网之鱼,更加全面的保证程序的正常运行
一般情况下,都是按照try-catch-finally去执行的。但是,在特殊情况下,也是可以强制要求finally强制执行的。
在上面的程序我们继续加入这样的一段代码,我们可以看到,当输入字母或者正常输入时,程序都和上面输出的结果是一样的,但是当我们输入数字0时,就发生了下面这样的现象。为什么呢?
那是因为,System.exit(); 是程序终止的功能。
现在让我们结合Java API 来认识一下这个方法:https://docs.oracle.com/javase/8/docs/api/
首先System类是在java.lang中,然后在下面找到System类,可以看到介绍,System包含常见的文件和方法,而且它是不可以被实例化操作
然后找到exit方法:
描述终止的状态,一般情况下,数字非0,则表示异常终止状态。
Return的使用
我们知道,return关键字用来完成方法返回值的带回。那么在这怎么使用它呢? 我们在测试类中创建一个简单的程序。实现return功能,可以看到,return终止了程序的运行,载满情况后,立马终止。那么,当return语句放在try-catch中,也可以实现同样的终止功能么?
Test:
package com.kilig.test;
import java.util.InputMismatchException;
import java.util.Scanner;
public class TryDemoTwo {
public static void main(String[] args) {
// TODO Auto-generated method stub
int result = test();
System.out.println("The Quotient of two numbers is : "+result);
}
private static int test() {
// TODO Auto-generated method stub
Scanner input =new Scanner(System.in);
System.out.println("======BEGAIN======");
try {
System.out.print("Please input first number: ");
int one = input.nextInt();
System.out.print("Please input secound number: ");
int two = input.nextInt();
return one/two;
}catch(ArithmeticException e) {
System.out.println("Divider cannot be zero");
return 0;
}finally {
System.out.println("======OVER======");
return -1000000;
}
}
}
运行结果看一下:
可以看到finally被无视运行了,这是为什么呢?
可以看到,在finally中加入return后,前面所有return逻辑就不回去执行,直接强制执行finally语句,所以这也就是为什么,在try-catch-finally都加入return后,我们的finally代码块变为黄色,提示不可以这样写的原因了。