• Java 异常处理


    1.异常处理   

    1)异常处理机制    

      当程序中抛出一个异常后,程序从程序中导致异常的代码处跳出,Java虚拟机检测寻找和try关键字匹配的处理该异常的catch块,如果找到,将控制权交给catch块中的代码,然后继续往下执行程序,try块中发生异常的代码不会被重新执行。如果没有找到处理该异常的catch块,在所有的finnally块代码被执行和当前线程所属的ThreadGroup的uncaughtException方法被调用后,遇到异常的当前线程被终止。

    2)异常的捕获和处理

    2.1)Throwable、Error、Exception

      Java异常结构中定义有Throwable类,Error和Exception是其派生的两个子类。其中Exception表示由于网络故障、文件损坏、设备错误、用户输入非法等情况导致的异常,这类异常是可以通过Java异常捕获机制处理的。而Error表示Java运行时环境出现的错误,如JVM内存溢出等。

    2.2)try-catch

      try语句指定了一段代码,该段代码就是一次捕获并处理例外的范围。在执行过程中,该段代码可能会产生并抛出一种或几种类型的异常对象,它后面的catch语句分别对这些异常做相应的处理。

      如果没有例外产生,所有的catch代码段都被略过不执行。

      在catch语句块中是对异常进行处理的代码,catch中声明的异常对封装了异常事件发生的信息,在catch语句块中可以使用这个对象的一些方法获取这些信息。

    public class Try_catchDemo {
    	public static void main(String[] args) {
    		System.out.println("程序开始了");
    		try{
    			String str = null;
    			System.out.println(str);
    		}catch(NullPointerException e){
    			System.out.println("出现空指针异常");
    		}
    		System.out.println("程序结束了");
    	}
    }
    
    /*
    运行结果:
    程序开始了
    null
    程序结束了
    */
    

    2.3)多个catch

      每个try语句可以伴随一个或多个catch语句,用于处理可能产生的不同类型的异常。catch捕获的异常类型由上至下的捕获异常类型的顺序应该是子类到父类。

      通常在写代码的时候,应该在最后一个cathc中捕获Exception,这样可以保证不会因为出现一个未在catch中声明的异常而导致捕获失败使得程序终止。  

    public class Try_catchDemo {
    	public static void main(String[] args) {
    		System.out.println("程序开始了");
    		try{
    			String str = "A";
    			System.out.println(str);
    			System.out.println(str.charAt(0));
    			System.out.println(Integer.parseInt(str));
    			System.out.println("我是伪代码");
    		}catch(NullPointerException e){
    			System.out.println("出现空指针异常");
    		}catch(StringIndexOutOfBoundsException e){
    			System.out.println("字符串下标越界了");
    		}catch(Exception e){
    			System.out.println("发生异常了");
    		}
    		System.out.println("程序结束了");
    	}
    }
    

      try程序块中,如果出现了异常,那么从这一条异常代码开始后面的代码就不执行了,如上案例出现字符下标异常,后面的两行代码就不会执行。

    2.4)finally

      finally语句为异常处理提供一个统一的出口,使得在控制流程转到程序其他部分以前,能够对程序的状态作统一管理。

      无论try所指定的程序块中是否抛出异常,finally所指定的代码都要被执行,通常在finaly语句中可以进行资源的消除工作,如关闭打开的文件、删除临时文件等。

      finally语句块只能定义在try语句块之后,或者最后一个catch语句块之后,且只能定义一次。

    public class Try_catchDemo {
    	public static void main(String[] args) {
    		System.out.println("程序开始了");
    		try{
    			String str = null;
    			System.out.println(str);
    			System.out.println(str.charAt(0));
    			System.out.println(Integer.parseInt(str));
    			System.out.println("我是伪代码");
    		}catch(NullPointerException e){
    			System.out.println("出现空指针异常");
    		}catch(StringIndexOutOfBoundsException e){
    			System.out.println("字符串下标越界了");
    		}catch(Exception e){
    			System.out.println("发生异常了");
    		}finally{
    			System.out.println("我是真代码,必须执行");   //不管是否发生异常,finally语句块中代码都会执行
    		}
    		System.out.println("程序结束了");
    	}
    }
    
    /*
    运行结果:
    程序开始了
    null
    出现空指针异常
    我是真代码,必须执行
    程序结束了
     */
    

     

    2.5)throw关键字

      当程序发生错误而无法处理的时候,会抛出对应的异常对象,除此之外,在某些时候,你可能会想要自行抛出异常。例如在异常处理结束后,再将异常抛出,让下一层异常处理块来捕获,若想自行抛出异常,就需要throw关键字,并生成指定的异常对象。

    public class Exception_throw {
    	public static void main(String[] args)  {
    		Person p = new Person();
    		try {
    			p.setAge(1000);
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		System.out.println("年龄:"+p.getAge());
    	}
    }
    
    class Person{
    	private int age;
    	public int getAge(){
    		return age;
    	}
    	public void setAge(int age) throws Exception{
    		if(age<0||age>100){
    			throw new Exception("年龄不合法");
    		}
    		this.age = age;
    	}
    }
    
    /*
     运行结果:
    java.lang.Exception: 年龄不合法
    	at javase.day08.Person.setAge(Exception_throw.java:22)
    	at javase.day08.Exception_throw.main(Exception_throw.java:7)
    年龄:0
     */
    

     

    2.6)throws关键字

      程序中会声明许多方法(Method),这些方法中可能会因为某些错误而引发异常,但你不希望直接在这个方法中处理这些异常,而希望调用这个它的方法来统一处理,这时候可以使用throws关键字来声明这个方法将会抛出异常。

    public class Exception_throw {
    	public static void main(String[] args) throws Exception {
    		Person p = new Person();
    		p.setAge(1000);
    		System.out.println("年龄:"+p.getAge());
    	}
    }
    
    class Person{
    	private int age;
    	public int getAge(){
    		return age;
    	}
    	public void setAge(int age) throws Exception{
    		if(age<0||age>100){
    			throw new Exception("年龄不合法");
    		}
    		this.age = age;
    	}
    }
    
    /*
     运行结果:
     Exception in thread "main" java.lang.Exception: 年龄不合法
    	at javase.day08.Person.setAge(Exception_throw.java:18)
    	at javase.day08.Exception_throw.main(Exception_throw.java:6):
     */
    

      注意:通常在一个方法中主动抛出一个异常时就要在当前方法上使用throws声明该类异常的抛出以通知调用者处理该异常,只有抛出RuntimeException编译器不要求必须这样做,除此之外,不使用throws声明该类异常编译器就不通过。

    public class Exception_throw {
    	public static void main(String[] args) {
    		Person p = new Person();
    		p.setAge(1000);
    		System.out.println("年龄:"+p.getAge());
    	}
    }
    
    class Person{
    	private int age;
    	public int getAge(){
    		return age;
    	}
    	public void setAge(int age){
    		if(age<0||age>100){
    			throw new RuntimeException("年龄不合法");
    		}
    		this.age = age;
    	}
    }
    
    /*
     运行结果:
    Exception in thread "main" java.lang.RuntimeException: 年龄不合法
    	at javase.day08.Person.setAge(Exception_throw.java:18)
    	at javase.day08.Exception_throw.main(Exception_throw.java:6)
     */
    

      

     2.7)重写方法时的throws

      当使用继承时,在父类的某个方法上声明了throws抛出某些异常,而在子类中重写该方法时,我们可以做以下操作:

    • 不处理异常(重写方法时不声明throws)
    • 可仅在throws中声明父类中声明的部分异常
    • 可在throws中声明父类方法中抛出的异常的子类异常

      但是不能做以下操作:

    • 重写方法时在throws中声明抛出额外的异常
    • 重写方法时在throws中声明父类方法中声明的抛出异常的父类异常
    import java.awt.AWTException;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.sql.SQLException;
    
    public class Exception_throws {
    	public void dosome() throws IOException,AWTException{
    		
    	}
    }
    
    class Son extends Exception_throws{
    	//可以不再抛出任何异常
    //	public void dosome(){
    //		
    //	}
    //	
    	
    	//可以仅抛出部分异常
    //	public void dosome() throws IOException{
    //		
    //	}
    	
    	//可以抛出父类方法抛出异常的子类型异常
    //	public void dosome() throws FileNotFoundException{
    //			
    //	}
    	
    	//不允许抛出额外异常
    //	public void dosome() throws SQLException{
    //		
    //	}
    	
    	//不允许抛出父类方法抛出异常的父类型异常
    //	public void dosome() throws Exception{
    //		
    //	}
    }
    

      

    2.Java异常API

    1)RuntimeException

      Java异常分为可检测异常、非检测异常。

      可检测异常:可检测异常经编译器验证,对于声明抛出异常的任何方法,编译器将强制执行处理或声明规则,不捕捉这个异常,编译器就通不过,不允许编译。

      非检测异常:非检测异常不遵循处理或者声明规则。在产生此类异常时,不一定非要采取任何适当操作,编译器不会检查是否已经解决了这个异常。

      RuntimeException类属于非检测异常,因为普通JVM操作引起的运行时异常随时可能发生,此类异常一般是由特定操作引发。但这些操作在Java应用程序中会频繁出现。因此它们不受编译器检查与处理或声明规则的限制。

    2)常见RuntimeException

      IllegalArgumentException:抛出的异常表明向方法传递了一个不合法或不正确的参数

      NullPointerException:当应用程序试图在需要对象的地方使用null时,抛出该异常

      ArrayIndexOutOfBoundsException:当使用的数组下标超出数组允许范围时,抛出该异常

      ClassCastException:当试图将对象强制转换为不是实例的子类时,抛出该异常

      NumberFormatException:当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常

     

    3.Exception常用API

    1)printStackTrace

      Throwable中定义了一个方法可以输出错误信息,用来跟踪异常事件发生时执行堆栈的内容。

    方法定义:
    void printStackTrace()
    
    try{
        ...  
    }catch(Exception e){
        e.printStackTrace();  //输出执行堆栈信息
    }
    

    2)getMessage

      Throwable中定义了一个方法可以得到有关异常事件的信息。

    方法定义:
    String getMessage() 
    try{
        ...  
    }catch(Exception e){
        System.out.println(e.getMessage()); 
    }
    

    3)getCause

      很多时候,当一个异常由另一个异常导致异常而被抛出的时候,Java库和开放源代码会将一种异常包装成另一种异常。这时,日志记录和打印根异常就变得非常重要。Java异常类提供了getCause()方法来检索导致异常的原因,这些可以对异常根层次的原因提供更多的信息。该Java实践对代码的调试或故障排除有很大的帮助。另外,如果要把一个异常包装成另一个异常,构造一个新异常就要传递源异常。

    Throwable getCause()
    

     

    案例:printStackTrace getMessage演示

    public class Exception_throw {
    	public static void main(String[] args) {
    		Person p = new Person();
    		try {
    			p.setAge(1000);
    		} catch (Exception e) {
    			e.printStackTrace();
    			System.out.println(e.getMessage());
    		}
    		System.out.println("年龄:"+p.getAge());
    	}
    }
    
    class Person{
    	private int age;
    	public int getAge(){
    		return age;
    	}
    	public void setAge(int age) throws Exception{
    		if(age<0||age>100){
    			throw new Exception("年龄不合法");
    		}
    		this.age = age;
    	}
    }
    
    /*
     运行结果:
    java.lang.Exception: 年龄不合法
    	at javase.day08.Person.setAge(Exception_throw.java:23)
    	at javase.day08.Exception_throw.main(Exception_throw.java:7)
    年龄不合法
    年龄:0
     */
    

      

    4.自定义Exception

    1)自定义异常的意义

      Java异常机制可以保证程序更安全和更健壮。虽然Java类库已经提供很多可以直接处理异常的类,但是有时候为了更加精准的捕获和处理异常以呈现更好的用户体验,需要开发者自定义异常。

    2)继承Exception自定义异常

      创建自定义异常类语法:

    public class 自定义异常类名 extends Exception{
         ...
    }
    

    3)编写构造方法

      当定义好自定义异常后,可以通过Eclipse来自动生成相应的构造方法。

    1. 声明一个类并继承Exception
    2. 右键点击Source
    3. 选择Generate Constructors from Superclass
    4. 选中父类中所有构造方法后确认生成
    public class MyException extends Exception{
    
    	public MyException() {
    		super();
    		// TODO 自动生成的构造函数存根
    	}
    
    	public MyException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
    		super(message, cause, enableSuppression, writableStackTrace);
    		// TODO 自动生成的构造函数存根
    	}
    
    	public MyException(String message, Throwable cause) {
    		super(message, cause);
    		// TODO 自动生成的构造函数存根
    	}
    
    	public MyException(String message) {
    		super(message);
    		// TODO 自动生成的构造函数存根
    	}
    
    	public MyException(Throwable cause) {
    		super(cause);
    		// TODO 自动生成的构造函数存根
    	}
    	
    }
    

      

      

     

     

     

     

     

  • 相关阅读:
    轻量级调试api接口 Jquery.PlayingAPI v 1.0
    js验证整数加保留小数点
    简单漂亮bootstrap grid列表分页 demo.
    polemo-logger 分析
    POSIX 标准的获取(pdf 格式)
    游戏开发利器(工具、资源)
    仅有 265 行的第一人称引擎
    介绍一款非常适合做微网站并且免费的CMS系统
    兔子无限繁殖问题——婓波那契数列
    近似计算
  • 原文地址:https://www.cnblogs.com/jmwm/p/6941211.html
Copyright © 2020-2023  润新知