JAVA异常处理机制

JAVA的异常机制主要依赖于try、catch、finally、throw和throws五个关键字,其中try关键字后紧跟一个花括号括起来的代码块(花括号)不可省略,简称try块,它里面放置可能引发异常的代码。catch后对应异常类型和一个代码块,用于表明该catch块用于处理这种类型的代码块。多个catch块后还可以跟一个finally块,finally块用于回收在try块里打开的物理资源,异常机制会保证finally块总被执行。throws关键字主要在方法签名中使用,抛出一个具体的异常对象;而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、异常处理机制的初衷试讲不可预期异常的处理代码和正常的业务逻辑处理代码分离,因此绝不要使用异常处理来代替正常的业务逻辑判断。异常机制的效率比正常的流程控制效率差,所以不要使用异常处理来代替正常的程序流程控制。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值