zoukankan      html  css  js  c++  java
  • 全面理解java异常机制

          在理想状态下,程序会按照我们预想的步骤一步一步的执行,但是即使你是大牛,你也不可避免出错,所以java为我们提供了异常机制。本文将会从以下几个方面介绍java中的异常机制:
    • 异常机制的层次结构
    • 异常的处理过程
    • 抛出异常
    • 捕获异常
    • 异常机制的实现细节

    一、异常机制的层次结构
          在java程序设计语言中,所有的异常对象都是派生于Throwable类,一般情况下,如果java中内置的异常类不能满足需求,可以自定义异常类只需要继承与Throwable类即可,下面是java 中的异常层次结构:
    这里写图片描述
          error类表示java内部错误,例如jvm出错或者内存不足等,这层一般不用我们关心(其实我们也无可奈何,如果出现此种问题),一旦出现此种错误程序会自动结束。
          我们主要还是需要研究Exception类及其子类,Exception主要有两个子类,IOException和RuntimeException我们一个个看。IOException是IO错误类问题导致的异常,是可预知的,例如由于文件不存在而打开文件失败引起的异常等。RuntimeException类异常表示运行时异常,例如数组下标越界,访问空指针等,是不可预知的,但是这类异常于编写程序时应当予以避免,例如你可以使用if(a==null).....,加以检查避免。
          以上从一种角度对这些主要的异常类进行了分类,其实我们还有一种分类方式,按照是否是检查类异常(checked)进行分类,什么是检查类异常?检查类异常(checked)就是指编译器会检查当前的代码块中,判断是否有这么一条语句在程序执行时可能产生异常,如果有就会建议程序员处理。(实际上你必须处理,不然编译不会通过),在以上的分层中,error类和RuntimeException类属于非检查异常类(unchecked),而IOException属于检查类异常。


    二、异常的处理过程

    public class Test2 {
    	public static void main(String[] args){
    		doMaths();
    	}
    	public static void doMaths(){
    		int a = 10/0;//此处将会出现异常
    		System.out.println(a);
    	}
    }
    
    
    输出结果:
    Exception in thread "main" java.lang.ArithmeticException: / by zero
    	at test.Test2.doMaths(Test2.java:8)
    	at test.Test2.main(Test2.java:5
    


          相信大家在看完上文之后,可以判断出此处的异常应该属于RuntimeException,属于unchecked异常,由输出的结果可以看出:main方法中调用方法doMaths();,于是进入该方法内部,执行int a = 10/0;产生异常,在本方法中未找到处理,于是返回调用处(即main函数中),发现main函数中依然没有处理方法,于是执行默认操作(打印异常信息)。
          我们的程序难免会出现问题,但是绝对不能让用户看出来你的程序出现问题,所以这些异常信息是绝对不能让用户看见的,且不说他是否能看懂,一旦遇到“行家”,你的程序就会存在安全隐患,由此可见,对异常的处理是多么重要。下面我们将讨论两种处理异常的机制。


    三、抛出异常
          以下所讨论的处理异常的方法,主要还是针对检查类异常(checked),因为对于error类的错误我们没法处理,对于RuntimeException类异常我们应当尽量在程序中加以避免,所以我们主要还是对检查类异常进行处理。
          我们使用关键字throws将本程序中可能遇到的异常向上抛出(向调用出抛出,让调用者处理),而本身不做处理。

    public void test() throws AppException{
    	................
    	...............
    }
    


          throws 紧跟方法的括号后面,这个叫异常的声明表示本方法不处理这个异常,谁调用我这个方法谁来处理(后面将讨论如何处理异常,因为总要有人来处理,否则就默认打印异常信息),可以声明多个异常,异常之间使用逗号相隔。
          那么throw关键字和throws关键字究竟有什么联系呢?throw可以理解为是在throws关键字的主动行为。先看代码:

    public class Test2 {
    	public static void main(String[] args){
    		show();
    	}
    	public static void show(){
    		String s = null;
    		s.charAt(0);
    	}
    }
    /*以上代码抛出NullPointerException,空指针异常*/
    
    public static void show() throws NullPointerException{
    		String s = null;
    		s.charAt(0);
    	}
    /*你可以选择抛给调用者*/
    
    public static void show(){
    		String s = null;
    		if(s==null){
    			throw new NullPointerException();
    		}
    		s.charAt(0);
    	}
    /但是如果你可以判断s处可能出现异常,就可以主动抛出异常*/
    
          小结一下,throws关键字表示:本函数中存在某个异常但是我不知道,如果出现此异常就抛给调用者。throw一般和判断语句if配合的多表示:如果满足条件就结束此函数并向调用者抛出异常,否则就继续执行接下来的代码。 **四、捕获异常**       以上说了那么多,我们知道如何将遇到的异常抛出,让别人处理,但是总是有人需要处理这个异常的,总不能让系统默认的将异常信息打印出来吧!再者说,一个strong的程序必须要有对错误的处理,让程序控制在手中而不是莫名卡死或者退出。接下来,我们一起探讨如何捕获异常对他进行处理。       捕获异常,我们使用try{}catch{}关键字,try中代码表示可能出现异常的代码块,catch中的代码块表示捕捉到该异常之后需要进行的后续操作。
    /*使用上述代码,添加try catch捕获异常*/
    public class Test2 {
    	public static void main(String[] args){
    		try{
    			show();//可能出现异常的代码块
    		}catch(NullPointerException z){
    			System.out.println("throw Exception");
    			//捕捉到异常后的操作
    		}
    	}
    	public static void show()throws NullPointerException {
    		//将异常抛给调用者
    		String s = null;
    		s.charAt(0);
    	}
    }
    
    
    输出结果:
    throw Exception
    
          对比于之前,打印自己控制的内容是不是比默认打印异常信息更加的友好?我们常常会遇到这么一个问题:打开一个文件,准备对文件进行操作,但是在对文件的操作过程中出现异常,退出程序了,但是文件并没有被显式的关闭,造成资源浪费。       我们常常使用关键字finally来完成类似这样的操作。finally关键字紧跟catch后面,表示无论是否发生异常都会执行的代码块。finally不是必须的可以没有。
    try{
      //可能出现异常的代码块
    }catch{
      //捕获异常之后的代码块
    }finally{
      //肯定要执行的代码块
    }
    
    **五、异常机制的实现细节**       第一个我想说的是try{}catch{}这种结构并不是唯一的,可以由多个catch语句的,对多个不同的异常进行捕获。       第二个很重要的finally这个关键字中如果出现return等关键字程序的接下来的执行顺序问题。例如:
    try{
      int a=0;
      //出现异常
      return a;
    }catch(..){
     a=1;
     return a;
    }finally{
     a=2;
     return a; 
    }
    
    程序返回:2;
    
          能想明白么?其实不难,只要知道finally语句块中是最后执行的就可以理解了,当try中出现异常,被catch接住,将a赋值为1,在返回之前跳转到finally语句块中,最后在finally语句块中返回2,这种在finally语句块中有return语句的会阻止catch中的return执行。       所以,我们建议finally语句块中不要使用return语句。       **以上便是java异常机制的基本内容,如果错误,望大家指出。tk**
  • 相关阅读:
    防删没什么意思啊,直接写废你~
    绝大多数情况下,没有解决不了的问题,只有因为平时缺少练习而惧怕问题的复杂度,畏惧的心理让我们选择避让,采取并不那么好的方案去解决问题
    Java 模拟面试题
    Crossthread operation not valid: Control 'progressBar1' accessed from a thread other than the thread it was created on
    一步步从数据库备份恢复SharePoint Portal Server 2003
    【转】理解 JavaScript 闭包
    Just For Fun
    The database schema is too old to perform this operation in this SharePoint cluster. Please upgrade the database and...
    Hello World!
    使用filter筛选刚体碰撞
  • 原文地址:https://www.cnblogs.com/yangming1996/p/6429922.html
Copyright © 2011-2022 走看看