前言
本篇文章笔者准备重点介绍异常的产生原理,异常处理的基本格式,throw和throws关键字的作用,自定义异常,以及Exception与RuntimeException的区别,断言的作用等等
异常的基本概念
异常是导致程序中断运行的一种指令流,如果不对异常进行正确的处理,则可能导致程序的中断执行,造成不必要的损失,所以在程序的设计中必须要考虑各种异常的发生,并正确做好相应的处理,这样才能保证程序的正常运行。在Java中一切异常都秉着面向对象的设计思想,所有的异常都以类和对象的形式存在,除了Java中已经提供的各种异常类外,用户也可以根据需要定义自己的异常类。
为什么需要异常处理
在没有异常处理的语言中如果要回避异常,就必须使用大量的判断语句,配合所想到的错误状况来捕捉程序中所有可能发生的错误。但为了捕捉这些错误,编写出来的程序代码经常有大量的判断语句,又是这样也未必能捕捉到所有的错误,而且这样做势必导致程序的运行效率的降低。
Java的异常处理机制恰好改进这一点。它具有易于使用,可自行定义异常类,处理抛出的异常同时又不会降低程序运行的速度等优点。因在Java程序设计时,应充分利用Java的异常处理机制,以增进程序的稳定性及效率。
认识异常
public class ExceptionDemo01{
public static void main(String[] args){
System.out.println(******计算开始*******);
int i=10;
int j=0;
int temp=i/j;
System.out.print("两个数字相除结果:" +temp);
System.out.print(******计算结果*******);
}
}
程序运行结果:
计算开始
Exception in thread”main”java.lang.ArithmeticException:/by zero at ExceptionDemo01.main(ExceptionDemo01.java:6 )
在以上程序中,因为被除数为0,所以程序中出现异常,从运行结果可以发现,如果不对异常进行处理,则一旦出现异常后,程序立刻退出,所以后面的两条语句并没有打印输出。此程序的执行流程如图所示
解决方案
在程序中进行异常处理
范例
public class ExceptionDemo02{
public static void main(String[] args){
System.out.println("*****计算开始*****");
int i=10;
int j=0;
try{
int temp=i/j;
System.out.println("两个数字相除的结果:"+temp);
System.out.println("------------");
}catch(ArithmeticException e ){
System.out.println("出现异常了" +e);
}
System.out.println("*******计算结束*******");
}
}
程序运行结果:
计算开始
出现异常了:java.lang.ArithmeticException:/by zero
计算结束
从图中可以清楚的看到,所有异常都在catch中处理了,catch处理完毕之后,程序正常结束。实际上在异常处理的最后有一个finally关键字,可以使用它作为异常的统一接口。
验证finally关键字
public class ExceptionDemo03{
public static void main(String[] args){
System.out.print("******计算开始******");
int i=10;
int j=0;
try{
int temp=i/j;
System.out.println("两个数字相除结果:"+temp);
System.out.println("---------");
}catch(ArithmeticException e){
System.out.println("出现异常了:" +e);
}finally{
System.out.println("不管是否出现异常,都执行代码");
}
System.out.println(******计算结束*****);
程序运行结果:
计算开始
出现异常了:java.lang.ArithmeticException:/byzero
不管是否出现异常,都执行此代码
计算结束
通常程序开发中不会只有一个异常,肯定同时存在多个异常,此时就需要了解异常类的继承结构
- Exception:一般表示的是程序中出现的问题,可以直接使用try….catch处理。
- Error:一般指的是JVM错误,程序中无法处理。
- 一般情况下,开发者习惯于将Exception和Error统称为异常,而算术异常,数字格式异常等都属于Exception的子类。
Java异常信息的输出方式
- System.out.println(异常对象)
- e.printStackTrace()
Java的异常处理机制
在整个Java的异常处理中,实际上也是按照面向对象的方式进行处理,处理的步骤如下:
(1) 一旦产生异常,则首先会产生一个异常类的实例化对象。
(2)在try语句中对此异常类进行捕捉
(3)产生的异常对象与catch语句的各个异常类型进行匹配,如果匹配成功,则执行catch语句中的代码。
从之前学习过的对象多态性可以清楚的知道,所有的子类实例可以全部使用父类类型接收,那么就可以利用向上转型的概念,让所有的异常对象都使用Exception接收。
范例
public class ExceptionDemo{
public static void main(String[] args){
System.out.println(********计算开始*******);
int i=0;
int j=0;
try{
String str1=args[0];
String str2=arg[1];
i=Integer.parseInt(str1);
j=Integer.parseInt(str2);
int temp=i/j;
System.out.println("两个数字相除的结果:"+temp);
System.out.println("--------------");
}catch(Exception e){
System.out.println("其它异常:" +e);
}
System.out.println(*******计算结束*******);
}
}
以上代码直接使用Exception进行异常处理,所以任何的异常都可以非常方便地进行处理。
throws与throw关键字
throws关键字
在定义一个方法时可以使用throws关键字声明,使用throws声明的方法表示此方法不处理异常,而交给方法的调用处进行处理。
范例:处理异常
class Math{
public int div(int i,int j)throws Exception{ //本方法不处理异常
int temp=i/j;
return temp;
}
}
public class ThrowsDemo01{
public static void main(String[] args){
Math m=new Math();
try{ //因为有throws,不管是否有异常,都必须处理
System.out.println("除法操作:"+m.div(10,2));
}catch(Exception e){
e.printStackTrace();
}
}
}
程序运行结果:
除法操作:5
以上代码中,不管是否有问题,都要使用try…catch块进行异常的捕获与处理。既然throws是在方法处定义的,那么在主方法中也可以使用throws关键字,但是主方法为程序的起点,所以此时主方法再向上抛异常,则只能将异常抛给JVM进行处理。这就好比一个公司,部门事情处理不了,要上报给经理,经理再解决不了要上报给董事长,到董事长了,也就到头了,那么Java的头就是JVM。
范例:主方法处使用throws关键字
class Math{
public int div(int i, int j)throws Exception{
int temp=i/j;
return temp;
}
}
public class ThrowsDemo{
//本方法中所有的异常都可以不使用try....catch处理的
public static void main(String[] args){
Math m=new Math();
System.out.println("除法操作:"+m.div(10,2));
}
}
以上代码在主方法处使用了throws关键字,所以在程序主方法中就可以不再使用try…catch语句进行异常的捕获及处理。
提醒
主方法为一切的起点,一切的操作也都是由主方法开始的。所以如果在主方法中使用throws,则程序出现问题后肯定交由JVM进行处理,将导致程序中断。
throw关键字
与throws关键字不同的是,可以直接使用throw关键字人为地抛出一个异常,抛出时直接抛出异常类的实例化对象即可。
范例:抛出异常
public class ThrowDemo01{
public static void main(String[] args){
try{
throw new Exception("自己抛出的异常!");//抛出异常的实例化对象
}catch(Exception e){
System.out.println(e);
}
}
}
程序运行结果:
java.lang.Exception:自己抛出的异常!
throw与throws的综合运用
class Math{
public int div(int i, int j)throws Exception{ //方法不可以处理异常
System.out.println("******计算开始*******");
int temp=0;
try{
temp=i/j;
}cath(Exception e){
throw e //把异常交给被调用处
}finally{
System.out.println("******计算结束*****");
}
return temp;
}
}
public class ThrowDemo{
public static void main(String[] args){
Math m = new Math();
try{
System.out.println("除法操作:"+m.div(10,0));
}catch(Exception e){
System.out.println("异常产生:"+e);
}
}
}
程序运行结果:
计算开始
计算结束
异常产生:java.lang.ArithmeticException:/by zero
Exception类与RuntimeException类的区别
自定义异常类
在Java中已经提供了大量的异常类,但是这些异常类有时也很难满足开发者的需要,所以用户可以根据自己的需要来定义自己的异常类。定义自己的异常类只需要继承Exception类即可
范例:
class MyException extends Exception{ //自定义异常类,继承Exception类
public MyException(String msg){
super(msg);
}
}
public class DefaultException{
public static void main(String[] args){
try{
throw new MyException("自定义异常。");
}catch(Exception e){
System.out.println(e);
}
}
}
程序运行结果:
MyException:自定义异常。
断言
在JDK1.4之后,Java中增加了断言的功能。断言就是肯定某一结果的返回值是正确的,如果最终此结果的返回值是错误的,则通过断言检查肯定会提示错误信息。
范例:
public class Test{
public static void main(String[] args){
int x[]={1,2,3}
assert x.length==0;
}
}
以上程序中,数组x的长度是不可能为0的,所以,此处的断言结果是错误的,但此时运行程序并不会得到任何的结果,因为Java在设计assert关键字时考虑到系统的应用。
如果要想让断言起作用,可以使用一下参数运行参数
编译程序: javacTest.java
验证程序:java -ea Test
程序运行结果:
Exception in thread “main”java.lang.AssertionError at Test.main(Test.java:4)
以上出现的是断言错误,因为数组x的长度不可能是0,所以验证结果就出现了问题。
总结
以上就是笔者对异常的一点理解,有什么不足,请多多指教!