java 异常处理

异常处理

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

Throwable,Error和Exception

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

Java 中异常分为哪些种类
 
1)按照异常需要处理的时机分为编译时异常(也叫强制性异常)也叫 CheckedException 和运行时异常(也叫非强制性异常)也叫 RuntimeException。只有 java 语言提供了 Checked 异常,Java 认为 Checked
异常都是可以被处理的异常,所以 Java 程序必须显式处理 Checked 异常。如果程序没有处理 Checked 异常,该程序在编译时就会发生错误无法编译。这体现了 Java 的设计哲学:没有完善错误处理的代码根本没有机会被执行。对 Checked 异常处理方法有两种:
1 当前方法知道如何处理该异常,则用 try...catch 块来处理该异常。
2 当前方法不知道如何处理,则在定义该方法是声明抛出该异常。
运行时异常只有当代码在运行时才发行的异常,编译时不需要 try catch。Runtime 如除数是 0 和数组下标越界等,其产生频繁,处理麻烦,若显示申明或者捕获将会对程序的可读性和运行效率影响很大。所以由系统自动检
测并将它们交给缺省的异常处理程序。当然如果你有处理要求也可以显示捕获它们。

try-catch

java异常处理机制中的try——catch

 try 块用来包含可能出错的代码片段

 catch用来捕获try块中出现的错误并解决

/*
 *java异常捕获机制中的try-catch
 *结构:
 *try{
 *   可能出现错误的代码片段
 *  }catch(要捕获的异常类型){
 *    处理手段
 *  }
 * @author jiyiyuan
 *
 */
public class Exception_try_catch01 {

    public static void main(String[] args) {
        System.out.println("程序开始了");
        try {
            String str="a";
            System.out.println(str.length());
            System.out.println(str.charAt(0));
            //System.out.println(Integer.parseInt(str));
            /**
             * try块中出错的代码以下的内容都不会再执行。
             */
            System.out.println("!!!!!!!!!!");
        }catch(NullPointerException n) {
            System.out.println("空指针异常");
        }catch(StringIndexOutOfBoundsException n){
             System.out.println("字符串下标越界");
             /**
              * catch可以定义多个,针对不同异常有不同解决手段应对针对这些异常进行捕获。但是应当养成一个好的习惯,在最后捕获Exception,
              * 这样做可以避免因为try代码块中抛出一个未捕获异常导致程序中断。当捕获的异常存在继承关系时,应当将子类型异常定义在上面先行捕获。
              */
        }catch(Exception e){
            System.out.println("反对就是出了个错");
        }finally {
            System.out.println("程序结束了");
        }
    }

}

运行结果:

finally的作用

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

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

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

finally 块必须定义在异常处理机制的最后

finally块可以保证无论try块中的代码是否出现异常,finally块中的代码都会执行 通常会将诸如释放资源操作放在finally中确保执行

/*
 * finally块
 * finally只能定义在异常捕获机制的最后可以直接跟在try块之后或者最后一个catch之后
 * 
 * finally可以保证里面的代码一定执行。所以通常会将无乎异常而不需要运行的代码定义在finally确保它们可以被运行。比如流操作中关闭流就应当放在finally中。
 */
public class Exception_finally02 {

    public static void main(String[] args) {
        System.out.println("程序开始了。");
        try {
            String str="";
            System.out.println(str.length());
            return;
        }catch(Exception e){
            System.out.println("出错了。");
            
        }finally{
            System.out.println("finally中的代码执行");
        }
        System.out.println("程序结束了。");

    }

}

运行结果:

 

通常两种情况导致异常抛出

1.满足语法要求,但是不满足业务逻辑要求时,可以当作一个异常抛出给调用者。

 2.当前代码出现了异常,但是该异常的解决不应再当前代码中处理时可以将其抛出给调用者解决

throw关键字

当程序发生错误而无法处理的时候,会抛出对应的异常对象,除此之外,在某些时刻,您可能会想要自行抛出异常,例如在异常处理结束后,再将异常抛出,让下一层异常处理区块来捕捉,若想要自行抛出异常,您可以使用“throw关键词,并生成指定的异常对象。程序中会声明许多方法(Method),这些方法中可能会因某些错误而引发异常,但您不希望直接在这个方法中处理这些异常,而希望调用这个它的方法来统一处理,这时候您可以使用“throws”关键词来声明这个方法将会抛出异常

/**
 * 测试异常抛出相关操作
 * @author jiyiyuan
 *
 */
public class Person {

    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age)throws IllegalAgeException {
        if(age<0||age>100) {
            /**
             * throw用于主动抛出一个异常除了RuntimeException及其子类型异常外,抛出什么异常就必须在当前方法上使用
             * throws声明该类型异常的抛出定义以通知调用者处理该异常。
             */
            throw new IllegalAgeException("年龄不合法!");
        }
        this.age = age;
    }
}
public class Exception_throw04 {

    public static void main(String[] args) {
        System.out.println("开始了");
        
            
                try {
                    Person p=new Person();
                    /**
                     * 当调用一个含有throws声明异常抛出的方法时,编译器要求必须处理这 些异常。
                     * 处理方式有两种:
                     * 1.使用try-catch捕获并处理;
                     * 2.继续在当前方法上使用throws将该类异常声明抛出;
                     */
                    p.setAge(1000);
                    System.out.println(p.getAge());
                } catch (IllegalAgeException e) {
                    e.printStackTrace();
                }
                
        System.out.println("程序结束啦");
        
    }

}

运行结果:

重写方法时的throws

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

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

但是不能做以下操作:

  • 重写方法时在throws中声明抛出额外的异常

    重写方法时在throws中声明父类方法中声明的抛出异常的父类异常

/**
 * 子类在重写父类一个含有throws声明异常抛出的方法 时对throws的重写规则。
 * @author jiyiyuan
 *
 */
public class Exception_throws_override05 {

    public void dosome()throws IOException,AWTException{

     }

}

class Son extends Exception_throws_override05{
    /*
     * public void dosome()throws IOException,AWTException {
     * 
     * }
     */
    
    //仅抛出部分异常
    /*
     * public void dosome()throws IOException {
     * 
     * }
     */
    
    //不再抛出任何异常
    /*
     * public void dosome() {
     * 
     * }
     */
    
    //抛出父类方法抛出的异常的子类型异常
    /*
     * public void dosome()throws FileNotFoundException {
     * 
     * }
     */
    
    
    //不允许抛出额外异常
    /*
     * public void dosome()throws SQLException {
     * 
     * }
     */
    
    
    //不允许抛出父类方法抛出异常的父类型异常
    /*
     * public void dosome() throws Exception{
     * 
     * }
     */
        
}

 

Java异常API

/**
 * 异常常用方法
 * @author jiyiyuan
 *
 */
public class Exception_API06 {

    public static void main(String[] args) {
        System.out.println("程序开始了");
        try {
            String str="a";
            System.out.println(Integer.parseInt(str));
        }catch(Exception e) {
            //输出错误堆栈信息,有助于定位错误并调整。
            e.printStackTrace();
            String message=e.getMessage();
            System.out.println("message:"+message);
        }
        System.out.println("程序结束了");

    }

}

运行结果:

getCause

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



自定义Exception

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

如何编写构造方法

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

具体步骤如下:

  1. 声明一个类并继承自Exception
  2. 右键点击Source
  3. 选择Generate Constructors from Superclass
  4. 选中父类中所有构造方法后确认生成
/**
 * 年龄不合法异常
 * 
 * 自定义异常通常用来说明我们写的项目中的某个业务逻辑
 * 错误。
 * @author jiyiyuan
 *
 */
public class IllegalAgeException extends Exception {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    public IllegalAgeException() {
        super();
        // TODO Auto-generated constructor stub
    }

    public IllegalAgeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
        // TODO Auto-generated constructor stub
    }

    public IllegalAgeException(String message, Throwable cause) {
        super(message, cause);
        // TODO Auto-generated constructor stub
    }

    public IllegalAgeException(String message) {
        super(message);
        // TODO Auto-generated constructor stub
    }

    public IllegalAgeException(Throwable cause) {
        super(cause);
        // TODO Auto-generated constructor stub
    }
         
}
error 和 exception 的区别?

Error 类和 Exception 类的父类都是 Throwable 类,他们的区别如下。

1. Error 类一般是指与虚拟机相关的问题,如系统崩溃,虚拟机错误,内存空间不足,方法调用栈溢出等。对于这类错误的导致的应用程序中断,仅靠程序本身无法恢复和和预防,遇到这样的错误,建议让程序终止。

2. Exception 类表示程序可以处理的异常,可以捕获且可能恢复。遇到这类异常,应该尽可能处理异常,使程序恢复运行,而不应该随意终止异常。

3. Exception 类又分为运行时异常(Runtime Exception)和受检查的异常(Checked Exception ),运行时异常;ArithmaticException,IllegalArgumentException,编译能通过,但是一运行就终止了,程序不会处理运行时异常,

    出现这类异常,程序会终止。而受检查的异常,要么用 try。。。catch 捕获,要么用 throws 字句声明抛出,交给它的父类处理,否则编译不会通过。

java 异常处理机制
 
Java 对异常进行了分类,不同类型的异常分别用不同的 Java 类表示,所有异常的根类为 java.lang.Throwable,Throwable 下面又派生了两个子类:Error 和 Exception,Error 表示应用程序本身无法克服和恢复的一种严重问题。
Exception 表示程序还能够克服和恢复的问题,其中又分为系统异常和普通异常,系统异常是软件本身缺陷所导致的问题,也就是软件开发人员考虑不周所导致的问题,软件使用者无法克服和恢复这种问题,但在这种问题下还可以让软件系统继续运行或者让软件死掉,例如,数组脚本越界(ArrayIndexOutOfBoundsException),空指针异常(NullPointerException)、类转换(ClassCastException);普通异常是运行环境的变化或异常所导致的问题,是用户能够克服的问题,例如,网络断线,硬盘空间不够,发生这样的异常后,程序不应该死掉。java 为系统异常和普通异常提供了不同的解决方案,编译器强制普通异常必须 try..catch 处理或用 throws 声明继续抛给上层调用方法处理,所以普通异常也称为 checked 异常,而系统异常可以处理也可以不处理,所以,编译器不强制用 try..catch 处理或用 throws 声明,所以系统异常也称为 unchecked 异常。 
throw 和 throws 的区别
throw:
1)throw 语句用在方法体内,表示抛出异常,由方法体内的语句处理。
2)throw 是具体向外抛出异常的动作,所以它抛出的是一个异常实例,执行 throw 一定是抛出了某种异常。
throws:
1)throws 语句是用在方法声明后面,表示如果抛出异常,由该方法的调用者来进行异常的处理。
2)throws 主要是声明这个方法会抛出某种类型的异常,让它的使用者要知道需要捕获的异常的类型。
3)throws 表示出现异常的一种可能性,并不一定会发生这种异常。


2019-12-22 22:25:58

原文地址:https://www.cnblogs.com/jyy599/p/12081415.html