Java的异常处理机制可以有效的解决程序中的错误处理问题。
1、简介
传统的结构化程序语言中,处理错误的方法主要为使用判断语句来进行,如C语言程序的典型代码:
#include "stdio.h"
main()
{
int account;
char name[30];
float balance;
FILE *p;
if((p=fopen("data.dat","w"))==NULL)
{
printf("\nFile not opened!");
return;
}
printf("\nPlease input : " ) ;
do
{
printf("\n?");
scanf("%d%s%f",&account,name,&balance);
if(feof(stdin))break;
fprintf(p,"%d%s%.2f\n",account,name,balance);
}
while(1);
fclose(p);
}
可以看出程序的功能性代码和验证性代码混和在一齐,难以理解和阅读,这种不良情况会随着程序规模的变大而加剧。
Java采用了面向对象的错误处理机制,即异常处理,来有效的对此问题加以解决。
先看一个例子:
public class exec
{
public static void main(String args[])
{
String str=javax.swing.JOptionPane.showInputDialog("Please input the size:");
int size=Integer.parseInt(str);
int x[]=new int[size];
System.exit(0);
}
}
象这样的一个简单程序,却需要处理很多可能产生的错误,如输入不是正确的整数值,输入正确但是不满足数组大小为正数的条件,等。
注意:一旦程序发生错误,就会终止正常的运行,显示一个错误输出,其中就含有很多有价值的调试信息,如错误的名称,位置等。
所以,需要加入验证代码。
按照传统的方式可以表达为:
public class exec
{
public static void main(String args[])
{
String str=javax.swing.JOptionPane.showInputDialog("Please input the size:");
//is Integer
char[] sarray =str.toCharArray();
for(int c=0;c<sarray.length;c++)
if(!Character.isDigit(sarray[c]))
{
javax.swing.JOptionPane.showMessageDialog(null,"Not Integer!");
System.exit(0);
}
int size=Integer.parseInt(str);
//is Positive
if(size<=0)
{
javax.swing.JOptionPane.showMessageDialog(null,"Not Positive!");
System.exit(0);
}
int x[]=new int[size];
System.exit(0);
}
}
可以看出这种方式显得相当混乱,而且无法有效解决很多其他可能的错误,如用户不输出任何信息,直接按回车键就会发生新的异常。
使用异常处理机制,可以达到同样的效果,如:
public class exec
{
public static void main(String args[])
{
try
{
String str=javax.swing.JOptionPane.showInputDialog("Please input the size:");
int size=Integer.parseInt(str);
int x[]=new int[size];
}
catch(NumberFormatException e)
{
javax.swing.JOptionPane.showMessageDialog(null,"Not Integer!");
}
catch(NegativeArraySizeException e)
{
javax.swing.JOptionPane.showMessageDialog(null,"Not Positive!");
}
System.exit(0);
}
}
说明:
1)尝试多种错误输入,观察效果和上述程序是否一样。显然,这种写法显得较为简洁
2)防止和处理一个运行时错误,只需要把所要监控的代码放进一个try块就可以了。紧跟着try块的,包括一个说明希望捕获的错误类型的catch子句,如果有多种错误,可以继续添加catch子句。
3)采用了面向对象的编程方法,一旦发生错误,就会由Java虚拟机生成相应异常类的对象,此时就可以被程序中的对应catch子句捕获,从而得以解决。由于采用了异常对象的抛出方式,所以异常对象可以封装相关属性和方法成员来包含处理错误所需要的信息,如:
public class exec
{
public static void main(String args[])
{
try
{
String str=javax.swing.JOptionPane.showInputDialog("Please input the size:");
int size=Integer.parseInt(str);
int x[]=new int[size];
}
catch(NumberFormatException e)
{
javax.swing.JOptionPane.showMessageDialog(null,e.getMessage());
}
catch(NegativeArraySizeException e)
{
javax.swing.JOptionPane.showMessageDialog(null,e.toString());
}
System.exit(0);
}
}
2、catch子句的使用
1)一个catch子句一般只是负责处理一种错误,所以一个try语句后通常会跟有很多catch子句。
2)发生异常时,只有那个异常引用参数类型和异常对象类型一样的catch子句才能得到处理。
3)具有相同异常引用参数类型的catch子句只能写一次。
4)所谓catch子句处理异常,也称之为捕获异常。这种处理并不代表着一定需要书写catch子句中的代码,只要catch子句能够捕获之,就代表错误得到了处理。
5)不同的catch子句之间一般可以不必考虑顺序,除了特殊情况,如捕获Exception的catch子句一定要放在最后。
6)一旦异常对象并某个catch子句处理了,则程序会没有了异常对象,也就是说,该try语句接下来的其他catch子句将统统失效,并且程序仍然正常接着try和catch子句后的语句运行,如:
public class exec
{
public static void main(String args[])
{
try
{
String str=javax.swing.JOptionPane.showInputDialog("Please input the size:");
int size=Integer.parseInt(str);
int x[]=new int[size];
}
catch(NumberFormatException e)
{
javax.swing.JOptionPane.showMessageDialog(null,e.getMessage());
}
catch(NegativeArraySizeException e)
{
javax.swing.JOptionPane.showMessageDialog(null,e.toString());
}
System.out.println("You can see me?");
System.exit(0);
}
}
不论异常是否产生,程序总是输出You can see me?
5)任何程序在进行一些错误验证后,仍然会存在很多未知错误的可能,所以利用所有异常的基类Exception来可以捕获所有的异常,如:
public class exec
{
public static void main(String args[])
{
try
{
String str=javax.swing.JOptionPane.showInputDialog("Please input the size:");
int size=Integer.parseInt(str);
int x[]=new int[size];
}
catch(Exception e)
{
javax.swing.JOptionPane.showMessageDialog(null,e.getMessage());
}
System.exit(0);
}
}
当然这种做法使得程序无法有针对性的处理个别异常对象,所以,更加常见的做法是:
public class exec
{
public static void main(String args[])
{
try
{
String str=javax.swing.JOptionPane.showInputDialog("Please input the size:");
int size=Integer.parseInt(str);
int x[]=new int[size];
}
catch(NumberFormatException e)
{
javax.swing.JOptionPane.showMessageDialog(null,e.getMessage());
}
catch(NegativeArraySizeException e)
{
javax.swing.JOptionPane.showMessageDialog(null,e.toString());
}
catch(Exception e)
{
javax.swing.JOptionPane.showMessageDialog(null,e.getMessage());
}
System.exit(0);
}
}
此程序会在出现NumberFormatException和NegativeArraySizeException异常的情况下单独处理,而其他的任何异常就全交给Exception处理。
注意:此时的次序不能写乱:
public class exec
{
public static void main(String args[])
{
try
{
String str=javax.swing.JOptionPane.showInputDialog("Please input the size:");
int size=Integer.parseInt(str);
int x[]=new int[size];
}
catch(Exception e)
{
javax.swing.JOptionPane.showMessageDialog(null,e.getMessage());
}
catch(NumberFormatException e)
{
javax.swing.JOptionPane.showMessageDialog(null,e.getMessage());
}
catch(NegativeArraySizeException e)
{
javax.swing.JOptionPane.showMessageDialog(null,e.toString());
}
System.exit(0);
}
}
编译错误信息为:
exception java.lang.NumberFormatException has already been caught
exception java.lang.NegativeArraySizeException has already been caught
这说明,由于捕获Exception的catch子句可以捕获所有异常,所以下面的两个异常捕获语句就永远无法正常工作了。
7)常见的异常种类有很多,必要的时候要了解一些常用异常类,如:
public class exec
{
public static void main(String args[])
{
try
{
int a=1/0;
System.out.println("You cann't see it!");
}
catch(ArithmeticException e)
{
System.out.println("Exception:"+e.getMessage());
}
}
}
请问下面的程序在不同的输入情况下会有怎样的运行情况?如输入5、100和0等。
public class exec
{
public static void main(String args[])
{
String str=javax.swing.JOptionPane.showInputDialog("Please input the size:");
int num=Integer.parseInt(str);
int[] array =new int[10];
try
{
array[num]=100;
num=num/num;
System.out.println("You cann't see it?");
}
catch(ArithmeticException e)
{
javax.swing.JOptionPane.showMessageDialog(null,"Divided by Zero");
}
catch(ArrayIndexOutOfBoundsException f)
{
javax.swing.JOptionPane.showMessageDialog(null,"Out Of Array's Bounds");
}
System.out.println("The End!");
}
}
3、finally子句
在程序中,如果会发生不可预料的异常的话,就会导致程序非正常终止,finally子句可以用于表达一定要执行的语句,通常为运行收尾时的必要结束代码,如:
public class exec
{
public static void main(String args[])
{
try
{
String str=javax.swing.JOptionPane.showInputDialog("Please input the size:");
int size=Integer.parseInt(str);
int x[]=new int[size];
}
catch(NegativeArraySizeException e)
{
javax.swing.JOptionPane.showMessageDialog(null,e.toString());
}
finally
{
System.out.println("End!");
}
System.exit(0);
}
}
该程序在如下几种情况下,都会打印End!信息,并且正常结束:
1)输入正常,如5
2)输入非法,但是被捕获,如-2
3)输入非法,同时也没有被捕获,如abcd
注意:此句只能位于异常捕获语句块的最后一个。
4、throw语句
使用该语句可以显式抛出异常对象,如:
public class exec
{
public static void main(String args[])
{
try
{
throw new ArithmeticException("e1");
}
catch( ArithmeticException e)
{
System.out.println("Zero");
}
System.out.println("End!");
}
}
输出为:
Zero
End!
显然,效果和真正发生异常是一样的。
那么为什么要使用throw语句呢?主要的原因在于它可以起到一种通知的作用,在程序执行当中,通过判断条件满足来引发异常的产生,会使得当前程序象对待真正的异常一样,必须立刻对此作出反映。它广泛的应用在程序和对象间的消息通信机制当中。
但是,直接使用这些系统本来就具有特定含义的异常类来作为程序自己的消息通信载体显得不是很方便,所以,合理的做法是建立自定义异常类,可以使得程序更加易于理解,如:
public class HasABreak extends Exception
{
public HasABreak(String s)
{
super(s);
}
}
应用程序为:
public class exec
{
public static void main(String args[])
{
try
{
throw new HasABreak("12:00");
}
catch(HasABreak e)
{
System.out.println(e.getMessage());
}
System.out.println("End!");
}
}
输出为:
12:00
End!
throw语句在嵌套try语句中的使用会使得问题有时变得很复杂,请问这个程序的输出是什么?
public class exec
{
public static void main(String args[])
{
try
{
try
{
throw new ArithmeticException("e1");
}
catch(ArithmeticException e)
{
System.out.println("Exception1:"+e);
throw e;
}
}
catch(ArithmeticException f)
{
System.out.println("Exception2:"+f);
}
System.out.println("End!");
}
}
输出为:
Exception1:java.lang.ArithmeticException: e1
Exception2:java.lang.ArithmeticException: e1
End!
5、throws子句
有些类在使用中可能会产生很多异常,在Java中,一个方法可抛出的异常被当作其公有接口的一部分,方法的使用者需要知道方法可能抛出的异常,以便能为处理这些异常作好准备,此时不能省略这种声明,否则通过不了编译。
throws语句就用于声明程序中可能出现的异常,如:
public class exec
{
public static void main(String args[])throws java.io.IOException
{
int i=System.in.read();
System.out.println(i);
}
}
[此贴子已经被作者于2010-12-12 07:43:18编辑过]