Java异常处理

为什么需要异常?

以前用C写数据结构的时候,总有这样一个烦恼:比如写栈的Pop函数,除了在函数体中完成出栈的操作,还要使用一个返回值,表示出栈操作是否成功进行。

但是呢,为了将出栈的值返回给调用者,就要用return语句。但是return又被函数状态值占用了,于是只能用指针了,这就必须给pop函数加一个指针参数,用起来很不方便。

java内置了异常机制,函数可以尽管执行,如果出现了什么意外的事,异常就会发生,我们的程序可以通过异常来处理这些意外。这将函数的功能与函数的执行状态分离了,编写的代码更清晰。

java异常的继承结构和分类

java中所有的异常都是Throwable的子类,下面又分2个分支:Error和Exception。

Error不用我们管,当Error发生时,你应该责怪java自身。java运行时,本身系统出了问题,这并不是你的代码的问题。所以我们根本不用管Error这个分支。 Error一般很少发生。    

Exception又可以分为2类:RuntimeException和 非RuntimeException异常。

RuntimeException异常(非检查异常)发生时,一定你的的代码写的有问题,具体说是代码的逻辑有问题,而不是语法问题,语法问题在编译时就会提示你。

比如使用了空指针,数组下标越界,无限循环造成的StackOverflow等。当这些异常发生时,你应该尽量去修改你的代码,而不是想着去捕获他们。这些都是可以避免的。

非RuntimeException异常(检查异常,图中深蓝色标记的),与RuntimeException相反,他们都是程序员不可避免的,比如出现执行一个IO操作,电脑可能没磁盘容量了,或者用户移除了IO设备。数据下载时,网络断开了......

非RuntimeException异常是java异常处理中我们最关心的异常分支。

 另外:RuntimeException异常和非RuntimeException异常一个明显的区别是,如果使用Eclipse,编译器会提醒你,并强制你处理

RuntimeException异常,而对于RuntimeException异常,编译器不会提醒你处理。

UIManager.setLookAndFeel是Swing中设置UI感官的方法,它会抛出:ClassNotFoundException等非RuntimeException异常

StringIndexOutOfBoundsException 是一个RuntimeException,Eclipse不会提醒你. 

异常发生后会怎么样

首先要明确,异常是在方法内产生的,因为方法用来操作数据,操作数据就可能发生异常。

我们还要理解的是函数调用栈:函数的调用时以栈的形式管理的,层级调用,依次入栈。

当在某一个代码块中发生异常后,JVM就会去这个代码块层次中寻找异常处理器(形如:try....catch...finally),如果找到了相应的处理器,则执行处理器的代码,然后跳出,执行处理器后面的代码。如果在当前方法中找不到合适的处理器,则此方法终止执行(return 语句也不会执行),JVM递归的到这个函数的调用函数去找

一旦找到异常处理程序,则在那一层处理掉这个异常,然后,在那一层往后执行(异常在哪里被处理掉,执行流就在那里往后执行)。

如果一直回溯到栈底都没有异常处理程序,则此线程终止。

下面来看一个小例子:

public static void foo1() throws Exception
{
     foo2();
}
    
private static void foo2() throws Exception
{
     throw new Exception();
        
}


public static void main(String []args)
{
     try
     {
         foo1();
     } catch (Exception e){
            // TODO Auto-generated catch block
            e.printStackTrace();
     }
        
}
    

 

 我们可以使用异常的printStackTrace()方法打印异常的堆栈信息。

                          

在代码中处理异常

主要要会用try...catch....finally语句。

                      

1、catch(XXXException e)    ,在异常发生,catch匹配到XXXException时,运行时系统就会将生成的异常对象赋值给变量e.这样,通过对异常变量e分析,就可以获取异常的详细信息异常。

2、finally主要用在异常处理器的收尾工作。关闭一些资源。比如一个文读一个件,无论成功读取,还是读取时发生异常了,最后都要关闭文件流,这个时候就要用到finally。

3、catch语句的顺序应该从具体异常到广泛异常,从特殊异常到一般异常。

try{
    file.read();
  }catch(EOFException e){      //EOFException是IOException的子类
                
  }catch (IOException e){      //IOException是Exception的子类   
               
  }catch(Exception e){
                
                
  }
            

4、同一个处理块处理多个异常

try

{
... }
catch(AException | BException e) { System.out.println("抛出AExcpetion或者BException 都会执行这个代码块") }

5、如果子类复写了父类中一个会抛异常的方法,那么,子类的这个方法应该抛出父类相同的异常,或者是子类异常,或者不抛异常,总之要在父类异常的可控范围内。可以想一想,如果不遵循这个规则的话,那么多态就无法实现了。

6、如果一个方法出现异常了,也没处理,它会中断执行,不会有返回值。

7、如果在正常离开try是因为return,break ,continuer语句,则会先去执行finally,再执行他们。

在方法中抛出异常

如果一个方法中会抛出异常,并且这个方法本身不去处理,让调用者去决定如何处理。那么,它就必须使用throws语句在函数头进行声明它可能抛出的所有异常类型。

声明的作用就是告知调用者:我可能会抛出一个异常,你需要做好准备。

下面是Swing 中UIManager类中的setLookAndFeel的函数头,它声明自己会抛出的异常。

 public static void setLookAndFeel(String className)throws ClassNotFoundException,
                                                           InstantiationException,
                                                           IllegalAccessException,
                                                           UnsupportedLookAndFeelException
 {
                
                //...
 }
    

主动抛出异常

使用throw 语句,后接一个异常对象。抛出一个异常对象。

下面是一个将参数字符串转为大写的自定义函数。

private String toUpper(String s) throws Exception
{
        
        if(s==null)
            throw new Exception("Paramter is null");
        else if(s.equals(""))
            throw new Exception("Empty String");
        
        else 
            return s.toUpperCase();
        
}

处理异常,但又抛出异常

有时候,一个方法需要对发生的异常进行过滤,或者对调用者隐藏某些异常,只抛出调用者能理解的异常,那么,它就要对异常进行捕获处理,然后适当抛出。 

例子函数:打印一个字符串的第一个字符

private  void printFirst(String s) 
{
            
        try
        {
            System.out.println(s.charAt(0));
        }catch(NullPointerException e)
        {
            throw e;   //捕获到异常,然后抛给调用者
            
        }catch(StringIndexOutOfBoundsException e)
        {
            //do nothing。自己处理,不通告调用者。
        }
        
        
            
}

定义自己的异常

 异常的常用方法

e.getMessage()                打印异常的详细信息

e.printStackTrace()           打印异常的跟踪栈

e.getLocalizedMessage()         异常的本地化描述

class MyException extends Exception
{
    public MyException()
    {
        super();
    }
    
    public MyException(String msg)
    {
        super(msg);
    }
    
    
}
原文地址:https://www.cnblogs.com/lulipro/p/5507270.html