Java异常处理概述:
我们先看一下如下的例子:
import java.util.Scanner;
publicclass Quotient {
publicstaticvoid main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Enter to integer:");
int number1 = input.nextInt();
int number2 = input.nextInt();
System.out.println(number1 + "/" + number2 + "=" + (number1 / number2));
}
}
这时如果对于第二个数我们输入的是0则会产运行时异常。
注意:对于浮点数来说的话如果除数是0的话是不会出现异常的
这个时候我们可以有一个处理办法就是对于第二个输入的数字进行判断使它不能输入0
import java.util.Scanner;
publicclass QuotientWithIf {
publicstaticvoid main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("输入两个整数:");
int number1 = input.nextInt();
int number2 = input.nextInt();
if (number2 != 0) {
System.out.println(number1 + "/" + number2 + "="
+ (number1 / number2));
} else {
System.out.println("除数不能为0!");
}
}
}
还有一种处理办法是更为通用的就是使用异常来进行捕获可能会产生的异常:
import java.util.Scanner;
publicclass QutientWithException {
publicstaticvoid main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("输入两个整数:");
int number1 = input.nextInt();
int number2 = input.nextInt();
try {
if (number2 == 0)
thrownew Exception("除数不能为0!");
System.out.println(number1 + "/" + number2 + "="
+ (number1 / number2));
} catch (Exception e) {
System.out.println(e.getMessage());
}
System.out.println("程序继续执行!");
}
}
上面的程序当中有一个try块和一个catch块,try块中是程序的执行代码,catch块是捕获到相应异常时要执行的一个代码块
thrownew Exception("除数不能为0!");这个表示抛出一个异常,这里的异常就是一异常类创建的对象。
当抛出一个异常的时候正常流程会被中断,这个时候异常会从正常流程这个地方传到catch块执行catch块中的内容,当catch块中的内容执行完后会执行catch块后的语句
throw就像是一个方法的调用它调用的是catch块,catch块可以看作是一个带参数的方法定义,这些参数匹配抛出值的类型,但是有一点要注意的就是在catch块执行完后并不会返回而是执行它后面的内容
有一个方法它可能会出现异常但是它自己不能决定产生异常后如何处理只有调用它的方法知道在出现异常时进行什么处理,这个时候使用try{}catch{},就好像你到饭店去吃饭点了个菜没有了这个时候对于点菜来是一个try中的内容catch中是需要处的的内容没有这个菜了是点菜的那个人去决定怎么处理的而不是被点菜的饭店处理的。
Java中很多的库方法都可能抛出异常
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.util.Scanner;
publicclass FileNotFoundException {
publicstaticvoid main(String[] args) throws UnsupportedEncodingException {
Scanner inputFromConsole = new Scanner(System.in);
System.out.print("输入一个文件名:");
String filename = inputFromConsole.nextLine();
try {
// 这里读取文件的时候按utf-8的格进行行读取
Scanner inputFromFile = new Scanner(new File(filename), "utf-8");
System.out.println("输入的文件存在!");
//读取文件的内容
while (inputFromFile.hasNext()) {
System.out.println(inputFromFile.nextLine());
}
} catch (java.io.FileNotFoundException e) {
System.out.println("输入的文件不存在!");
}
}
}
下面的程序使用do…while来读一个整数,如果读到的是一个整数则结束如果不是则进行相应的提示并继续读
import java.util.InputMismatchException;
import java.util.Scanner;
publicclass DoWileInputInt {
publicstaticvoid main(String[] args) {
Scanner input = new Scanner(System.in);
// 定义一个标记
boolean continueInput = true;
do {
try {
System.out.println("输入一个整数:");
int number = input.nextInt();
System.out.println("输入的整数是:" + number);
continueInput = false;
} catch (InputMismatchException e) {
System.out.println("输入的不是一个整数,请继续!");
// 抛弃当前的输入行,如果没有下面的一句的话在产生异常的时候会一直提示输入错误
input.nextLine();
}
} while (continueInput);
}
}
异常类型:
Throwable:所有异常的根类,所有Java异常类都直接或是间接的继承自这个类
异常类分为三种主要的类型:
Error类:这个是JVM抛出的异常,它是一种内部系统错误。这种错误出现后没有办法处理的
Exception类:这种类型的异常是由程序或是外部环境引起的错误这些错误是可以在程序中进行捕获并处理的
RuntimeException类:表示的是程序设计上的错误,这些异常也是由JVM抛出的
注意:RuntimeException类和Error类及它们的子类都是可不检测异常,而Exception类则是必须检查的异常要在程序中进行检查并给出处理办法
Java异常处理模型:
声明一个异常、抛出一个异常、捕获一个异常
声明异常在方法应后面加上throws 异常类名
public void myMethod() throws Exception1,Exception2,…ExceptionN{方法体}
抛出异常:在程序代码中throw new 异常名
IllegalArgumentException ex = new IllegalArgumentException(“抛出异常”);
throw ex;
或是throw new IllegalArgumentException(“抛出异常”);
这里构造的时候传入了一个参数,这个参数是用来描述异常的,可以通过方法getMessage()获得这个相应的描述
捕获异常:try{…}catch(声明一个异常对象){对异常处理}
从一个通用的异常父类可以派生出多种异常类,如果一个catch可以捕获一个父类的异常对象,那么它就可以捕获那个父类的所有子类的异常对象
在catch块中指定捕获异常的顺序是有讲究的,在catch一个异常类之前不能有catch它父类的异常,因为从常量上来看父类可捕获到了还要子类的catch就没有意义了
从异常中获得信息:
Throwable类中有如下方法:
printStackTrace();这个会打印输出栈跟踪信息
getMessage()返回一个String类型的字符串,它表示对象的消息
getStackTrace()这个方法返回一个数组这个数组的元素是栈跟踪元素
publicclass TestException {
publicstaticvoid main(String[] args) {
try {
System.out.println(sum(newint[] { 1, 2, 3, 4 }));
} catch (Exception e) {
// 打印栈跟踪信息
e.printStackTrace();
// 打印异常信息
System.out.println("\n" + e.getMessage());
// 调用异常对象的toString方法来得到相关信息
System.out.println("\n" + e.toString());
// 得到异常可以跟踪的所有信息
StackTraceElement[] traceElements = e.getStackTrace();
// 使用增强的for循环来进行打印各元素
for (StackTraceElement stace : traceElements) {
System.out.print("方法:" + stace.getMethodName());
System.out.print(";类名:" + stace.getClassName());
System.out.println(";位于" + stace.getLineNumber() + "行");
}
}
}
privatestaticint sum(int[] list) {
int result = 0;
// 下面的求和过程会返产生一个异常
for (int i = 0; i <= list.length; i++) {
result += list[i];
}
return result;
}
}
下面的例子说明异常的三个步:声明、抛出、捕获异常
publicclass CircleException {
privatedoubleradius;
privatestaticintnumberOfObject = 0;
// 构造方法
public CircleException() {
this(1.0);
}
public CircleException(double newRadius) {
//调用set方法来设置半径
setRadius(newRadius);
numberOfObject++;
}
// 相应的get,set方法
publicdouble getRadius() {
returnradius;
}
// 设置半径的时候可能出现异常这里我们要对异常进行声明、抛出
publicvoid setRadius(double radius) throws IllegalArgumentException {
if (radius >= 0)
this.radius = radius;
else
// 抛出一个异常并给定相关的信息
thrownew IllegalArgumentException("要设置的半径不能小于0!");
}
publicstaticint getNumberOfObject() {
returnnumberOfObject;
}
}
publicclass TestCircleException {
publicstaticvoid main(String[] args) {
try {
CircleException c1 = new CircleException();
CircleException c2 = new CircleException(2.0);
CircleException c3 = new CircleException(-6);
} catch (IllegalArgumentException e) {
System.out.println(e);
}
System.out.println("总共有Circle对象:"+CircleException.getNumberOfObject());
}
}
在异常处理中还有一个非常有用的子句就是finally子句
这个子句的意思就是不管是否出现异常或是是否捕获异常这个子句中的代码是都会执行到的
一个相对完整的异常处理结构为:
try{…}catch(异常对象){…}finally{…}
在任何情况下finally块都是会执行到的
如果是没有出现异常则流程是执行try中的语句后会执行finally中的语句再接着执行后面的语句
如果try中有一条语句产生异常被catch到了这时会跳过try中的其它语句而执行catch中的语句,再执行finally中的语句
如果try中有一条语句产生了异常但是没有catch到这时,会跳过try块中的其它语句并执行finally子句并且会把这个异常传给这个方法的调用者
finally在这里是最终都会执行的因而在finally中经常会用来释放资源这样就不怕某些资源在try中使用后没有得到释放掉
首先定义一个自己的异常类:
publicclass MyException extends Exception{
public MyException() {
super();
// TODO Auto-generated constructor stub
}
public MyException(String message, Throwable cause) {
super(message, cause);
// TODO Auto-generated constructor stub
}
public MyException(String message) {
super(message);
// TODO Auto-generated constructor stub
}
public MyException(Throwable cause) {
super(cause);
// TODO Auto-generated constructor stub
}
public String toString(){
return"产生自己的异常";
}
}
测试自己的异常并且使用相对来说完整的一个try…catch…finally结构并且注意这个结果是可以嵌套的!!
publicclass TestFinally {
publicstaticinty = 3;
publicstaticintr = 0;
publicstaticvoid main(String[] args){
try {
mc(1,1);
System.out.println("第一次买好菜了!");
} catch (MyException e) {
System.out.println(e);
System.out.println(e.getMessage());
}finally{
System.out.println("今天一定要吃饭!");
r++;
try {
mc(1,1);
System.out.println("第二次买好菜了!");
} catch (MyException e) {
e.printStackTrace();
}finally{
System.out.println("可以做饭吃了~~");
}
}
}
publicstaticvoid mc(int i,int j) throws MyException{
if(i>y || j>r){
thrownew MyException("产生异常了!!");
}
}
}
何时会使用异常:
try块是正常情况下执行的代码,catch是异常情况下执行的代码。异常处理把错误处理代码从正常的程序设计任务中分离出来,这样使得程序更加易读。
异常处理是要初始化新的异常对象的,需要从调用栈返回,而且还要从异常处理链上找到相应的异常处理器,因而它是会需要占用一些资源的
异常出现在方法中如果想让这个方法的调用者去处理异常应该创建异常并把这抛出,如果可以在发生异常的方法中直接处理异常则不需把这个异常抛出,所以为了性能的考虑如果是简单的异常最好在局部处理掉而不要抛出。
try{
}catch(…){
}
这个不是用来处理简单的可预料的情况的只有对于不可预料的情况才会去处理它