首页 > 代码库 > JAVA异常处理机制
JAVA异常处理机制
JAVA的异常机制主要依赖于try、catch、finally、throw和throws五个keyword,当中trykeyword后紧跟一个花括号括起来的代码块(花括号)不可省略,简称try块。它里面放置可能引发异常的代码。
catch后相应异常类型和一个代码块。用于表明该catch块用于处理这样的类型的代码块。多个catch块后还能够跟一个finally块,finally块用于回收在try块里打开的物理资源,异常机制会保证finally块总被运行。throwskeyword主要在方法签名中使用,抛出一个详细的异常对象;而throw用于抛出一个实际的异常,throw能够单独作为语句使用,抛出一个详细的异常对象。
我们希望全部的错误都能够在编译阶段被发现,就是在试图执行程序之前排除全部错误,但这是不现实的,余下的问题必须在执行期间得到解决。
JAVA将异常分为两种。Checked异常和Runtime异常,JAVA觉得Checked异常都是能够在编译阶段被处理的异常。所以他强制程序处理全部多的Checked异常。而Runtime异常则无需处理。
JAVA的异常处理机制能够让程序具有极好的容错性,让程序更加健壮。
当程序执行出现意外情形时。系统会自己主动生成一个Exception对象来通知程序,从而实现将“业务功能实现代码”和“错误处理代码”分离。提供更好的可读性。
以下就我在疯狂JAVA讲义上的异常机制学习。总结一下,共同学习。
1、 假设执行try块里的业务逻辑代码时出现异常,系统自己主动生成一个异常对象。该异常对象被提交给JAVA执行时环境,这个过程被称为抛出(throw)异常。
当程序进入负责异常处理的catch块时,系统生成的异常对象将会传给catch块后的异常形參,从而同意catch块通过该对象来获得异常的具体信息。
try{
//业务实现代码
`````````````
}
catch(Exception e)
{
alert 输入不合法
}
2、进行异常捕获时,一定要记住先捕获小异常,再捕获大异常。 由于RuntimeException已经包括了NullPointerException,所以②处的catch块永远也不会获得运行的机会。
public class NullTest {
public static void main(String[] args){
Date d=null;
try{
System.out.println(d.after(new Date()));
}catch(RuntimeException e){ ① //会报错
System.out.println("执行时异常");
}catch(NullPointerException ne){ ②
System.out.println("空指针异常");
}
}
}
3、捕获多种类型的异常时,异常变量有隐式的final修饰,因此程序不嗯可以对异常变量又一次赋值。捕获一种类型的异常时,异常变量没有final修饰。
public class MultiExceptionTest {
public static void main(String[] args){
try{
int a=Integer.parseInt(args[0]);
int b=Integer.parseInt(args[1]);
int c=a/b;
System.out.println("你输入的两个数相除的结果是: "+c);
}catch(IndexOutOfBoundsException | NumberFormatException | ArithmeticException ie){
System.out.println("程序发生了数组越界、数字格式异常、算术异常之中的一个");
//捕获多异常时,异常变量默认有final修饰,所以以下的代码报错。
//ie=new ArithmeticException("test");
}catch(Exception e){
System.out.println("未知异常");
//捕获一种类型的异常时,异常变量没有final修饰。所以以下代码全然正确。
e=new RuntimeException("test");
}
}
}
4、JAVA的垃圾回收机制不会回收不论什么物理资源,垃圾回收机制仅仅能回收堆内存中对象所占用的内存。为了保证一定能回收try块中打开的物力资源,异常处理机制提供了finally块。无论try块中的代码是否出现异常,也无论哪一个catch块被运行。甚至在try块或catch块中运行了return语句。finally块总会被运行。
可是假设在异常处理代码中使用System.exit(1)语句来退出虚拟机,则finally块将会失去运行机会。
public class FinallyTest {
public static void main(String[] args){
FileInputStream fis=null;
try{
fis=new FileInputStream("a.txt");
}catch(IOException ioe){
System.out.println(ioe.getMessage());
//ioe.printStackTrace(); //将该异常的跟踪栈信息输出到标准错误输出。
//return; //尽管return语句也强制方法结束,但一定会先运行finally块里的代码。
System.exit(1); //假设在异常处理代码中使用System.exit(1)语句来推出虚拟机。则finally语句将失去运行的机会。
}finally{
if(fis!=null){
try{
fis.close();
}catch(IOException ioe){
ioe.printStackTrace();
}
}
System.out.println("运行finally块里的资源回收!
");
}
}
}
5、不要在finally块中使用如return或throw等导致方法终止的语句。当java程序运行try块、catch块时遇到了return或throw语句。这两个语句都会导致该方法马上结束,可是系统运行这两个语句并不会结束该方法。而是去寻找该异常处理流程中是否包括finally块,假设没有finally块,程序马上运行return或throw语句,方法终止;假设有finally块,系统马上開始运行finally块——仅仅有当finally块运行完毕后,系统才会再次跳回来运行try块、catch块里的return或throw语句;假设finally 块里也使用了return或throw等导致方法终止的语句,finally块已经终止了方法,系统将不会跳回去 运行try块、catch块里的不论什么代码。
public class FinallyFlowTest {
public static void main(String[] args)throws Exception{
boolean a=test();
System.out.println(a);
}
public static boolean test(){
try{
return true;
}finally{
return false;
}
}
}
6、使用throws声明抛出异常的思路是,当前方法不知道怎样处理这样的类型的异常,该异常应该由上一级调用者处理;假设main方法也不知道怎样处理这样的类型的异常,也能够使用throws声明抛出异常。该异常将交给JVM处理。JVM对异常的处理方法是,打印异常的跟踪栈信息。并终止程序执行。
一旦使用throws语句声明抛出该异常,程序就无需使用try...catch块来捕获该异常了。
使用throws声明抛出异常时有一个限制。就是方法重写时“两小”中的一条规则:子类方法声明抛出的异常类型应该是父类方法声明抛出的异常类型的子类或同样。子类方法声明抛出的异常不同意比父类方法声明抛出的异常多。
7、throw语句抛出的不是异常类,而是一个异常实例,并且每次仅仅能抛出一个异常实例。
假设throw语句抛出的异常时Checked异常。则该throw语句要么处于try块里,显示捕获该异常,要么放在一个带throws声明抛出的方法中。即把该异常交给该方法的调用者处理。假设throw语句抛出的异常是Runtime异常,则该语句无需放在try块里,也无需放在带throws声明抛出的方法中;程序既能够显示使用try..catch来捕获并处理该异常,也能够全然不理会该异常,把该异常交给该方法调用者处理。
public class ThrowTest {
public static void main(String[] args) throws Exception{
/*try{
//调用声明抛出checked异常的方法。要么显示捕获该异常,要么在main方法中再次声明抛出
throwChecked(3);
}
catch(Exception e){
System.out.println(e.getMessage());
}*/
//调用声明抛出Runtime异常的方法既能够显示捕获该异常。也可不理会该异常。
//throwRuntime(3);
throwChecked(3);
}
public static void throwChecked(int a)throws Exception{
if(a>0){
throw new Exception("a的值大于0,不符合要求");
}
}
public static void throwRuntime(int a){
if(a>0){
throw new RuntimeException("a的值大于0,不符合要求");
}
}
}
8、在出现异常的方法内捕获并处理异常,该方法的调用者将不能再次捕获该异常。
该方法签名中声明抛出异常,将该异常全然交给方法调用者处理。
为了实现这样的通过多个方法协作处理同一个异常的情形,能够在catch块中结合throw语句来完毕。
public class AuctionTest {
private double initPrice = 30.0;
public void bid(String bidPrice)throws AuctionException{
double d=0.0;
try{
d=Double.parseDouble(bidPrice);
}catch(Exception e){
e.printStackTrace();
throw new AuctionException("竞拍价必须是数值,不能包括其它字符!");
}
if(initPrice > d ){
throw new AuctionException("竞拍价比起拍价低,不同意竞拍!");
}
initPrice=d;
}
public static void main(String[] args){
AuctionTest at=new AuctionTest();
try{
at.bid("df");
}catch(AuctionException ae){
System.err.println(ae.getMessage());
}
}
}
9、面向对象的应用程序执行时,常常会发生一系列方法调用,从而形成“方法调用栈”。异常的传播则相反:仅仅要异常没有被全然捕获(包含异常没有被捕获,或异常被处理后又一次跑出了新异常)。异常从发生异常的方法逐渐向外传播,首先传给该方法的调用者,该方法低啊用者再次传给其调用者。。
。
。
直至最后传到main方法,假设main方法依旧没有处理该异常。JVM会中止该程序。并打印异常的跟踪栈信息。
10、异常处理机制的初衷试讲不可预期异常的处理代码和正常的业务逻辑处理代码分离。因此绝不要使用异常处理来取代正常的业务逻辑推断。
异常机制的效率比正常的流程控制效率差,所以不要使用异常处理来取代正常的程序流程控制。
JAVA异常处理机制