• 异常处理(Exception Handling)


    java里的异常处理(Exception)
    Exception 是在程序执行过程中发生的一些不希望发生的事情,这些事情如果不被好好处理,就会导致奇怪的结果或者是程序终结。Exception Handler是那些当异常发生时处理这些异常的代码。所以这里只讲三个事儿:

    1. 什么是异常(Exception)
    1.1 Exceptions in java
    1.2 checked 和 unchecked的异常
    1.3 error和unchecked exception的不同
    2. 如何处理异常 (how to handle exception)
    2.1 try-catch-finally
    2. 2. throws exception
    3.如何创建一个custom的exception类
    3.1 如何创建一个custom的exception类
    3.2 如何扔throw一个custom的exception
    1. 什么是异常(Exception)
    Exception 是在程序执行过程中发生的一些不希望发生的事情,这些事情如果不被好好处理,就会导致奇怪的结果或者是程序终结。Exception Hander是那些当异常发生时处理这些异常的代码。java和javascript都用try/catch来处理异常。

    1.1 Exceptions in java
    exception在java里也是个object。
    来个图先


    图片来源: http://voyager.deanza.edu/~hso/cis35a/lecture/java13/intro/hier.html
    它爸爸是Throwable(面试会考,敲黑板)。它还有个兄弟叫Error。

    error and exception的不同:
    An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch.

    The class Exception and its subclasses are a form of Throwable that indicates conditions that a reasonable application might want to catch.

    1.2 checked 和 unchecked的异常
    Checked exception 是编译的时候就要求被handle的。编译的时候会检测Checked exception如果发生了有没有被handler(有没有加handler)所以也被称为compile-time exception。如果一个class是 Exception的孩子但不是 RuntimeException的孩子,那么它就是checked,写代码的时候被要求加handler 。如果用IDE, 会在写代码时要求handle这类异常。
    例如: CloneNotSupportedException, IOException, SQLException,
    InterruptedException, FileNotFoundException
    Unchecked exception 也被称为runtime exception因为它发生在程序执行时。我们可以添加handler去处理这类异常,也可以不加handler不处理这类异常。如果一个class是 RuntimeException的子孙,那它就是一个unchecked exception。
    例如: IllegalMonitorStateException,
    ConcurrentModificationException, NullPointerException,
    IndexOutOfBoundException, NumberFormatException
    1.3 error和unchecked exception的不同
    虽然都发生在runtime,但是error不被建议去handle。 大部分情况下即使是加了catch也无法修复。而RuntimeException可以去handle。

    2. 如何处理异常 (how to handle exception)
    有一些方法在声明的时候就声明扔出一个exception。如果这个exception是checked exception,则调用这个方法的时候就必须handle它。
    checked exception就像一个炸弹,如果说方法A的某处扔出一个炸弹,或者从别处接到一个炸弹(调用了另一个扔出exception的方法), 有两种解决方案:

    自己把它拆了( try-catch-finally)。 这样的话调用方法A的方法不用担心这个炸弹(异常)了
    继续丢出去, 谁调用方法A谁来处理(在A的method declaration的时候加上throws.)
    如果采用第一种方案,当方法B调用方法A的时候,方法A已经把炸弹拆了,方法B不用担心任何事情。
    如果采用第二种方法,方法B调用方法A的时候知道同时要接到一个炸弹,于是它有两种解决方案,拆了,或者继续throws。

    2.1 如何拆炸弹 用try-catch-finally
    try-catch:
    一个常见的数组越界exception。是个unchecked的exception,因为编译时没有要求handle,所以是个常见的新手 runtime异常。(不要求被handle,但是如果想handle也是可以的。)

    import java.io.*;
    public class ExceptionTest1 {
       public static void main(String args[]) {
          try {
             int a[] = new int[2];
             System.out.println(a[3]); //数组越界访问
          } catch (ArrayIndexOutOfBoundsException e) {
             System.out.println(e);//虽然没有做有意义的事情,但是阻止了程序死在半截。
          }
          System.out.println("run successfully");
       }
    }

    一个try可以跟着好几个catch, 为了分开处理不同的错误:

    try {
       //doing something
    } catch (Exception1 e) {
        // handle the first type exception
        System.out.println("Exception1 happened")
    } catch (Exception2 f){
        // handle the first type exception
        System.out.println("Exception2 happened")
    }

    一个exception发生之后,如果是Exception1类型的,就会被第一个handle,如果不是Exception1类型的就会接着往下找catch,如果是Exception2类型的,就会被第二个catch块handle。
    如果Exception1和Exception2是父子关系,则儿子要先被检测,因为如果爸爸先被检测,就永远也到不了儿子那个catch块了。

    finally block:
    finally block 是无论如何也会发生的一个block。 catch里的代码如果不发生异常就不会被执行,但是finally里面的代码无论如何都会执行。(除非是在try或者catch里面用System.exit(1)结束jvm。)通常用来关闭文件。

          try {
             //doing something
          } catch (Exception e) {
              //handle the exception
          }finally {
             //一定会被执行的代码。
          }
       }
    }

    另外, try-finally也是合法的。

    2.2 如何继续甩锅 throws exception
    用throws关键词

    //m1抛出了一个异常
    void m1 throws FileNotFoundException(){
        //大概是想读一些文件,又不想考虑如果文件找不到咋整。(甩锅)
    }
    //m2调用了m1,相当于从m1手里接到了这个异常,自己不处理,继续往外甩。
    void m2 throws FileNotFoundException(){
        m1();//想用m1方法,m1声明如果想用我就要考虑文件找不到的情况。
        //但是m2依然不想考虑文件找不到咋整。
    }

    来看个综合的例子:
    下面代码由于接到了exception没有正确handle而产生编译错误:

    import java.io.File;
    import java.io.FileReader;
    //会有编译错误
    public class ReadFileTest {
       public static void main(String args[]) {
          getFile();
       }
       public static void getFile(){
              File file = new File("file.txt");
           FileReader fr = new FileReader(file);//error: unreported exception FileNotFoundException; must be caught or declared to be thrown
       }
    }

    因为FileReader的constructor throws了一个异常

    public FileReader(String fileName) throws FileNotFoundException
    1
    所以当getFile方法调用FileReader的时候必须handle这个异常。

    下面是一个例子用上面两种方法处理异常:

    import java.io.File;
    import java.io.FileReader;
    import java.io.FileNotFoundException;
    public class ReadFileTest {
       public static void main(String args[]) {
               getFile1();
               System.out.println("=============");
            try{
               // 因为getFile2又把exception甩出来了,所以main方法得处理它。
               getFile2();
            }catch(FileNotFoundException e){
               System.out.println("Exception handled in main");
            }
          
       }
       //getFile1选择了自己处理,不麻烦调用它的方法
       public static void getFile1() {
            try{
                      File file = new File("file.txt");
                   FileReader fr = new FileReader(file);
               }catch(FileNotFoundException e){
                   System.out.println("Exception handled in getfile1");
           }
       }
       //getFile2选择了不处理,继续throws
       public static void getFile2() throws FileNotFoundException{
              File file = new File("file.txt");
           FileReader fr = new FileReader(file);
       }
    }

    运行结果:

    Exception handled in getfile1
    =============
    Exception handled in main

    一般来讲,所有的exception到了main方法这里都应该已经被解决了。如果,main方法也不负责任的往外扔。。。

    import java.io.File;
    import java.io.FileReader;
    import java.io.FileNotFoundException;
    public class ReadFileTest {
       public static void main(String args[]) throws FileNotFoundException{
               getFile1();
               System.out.println("=============");
            getFile2();
          
       }
       public static void getFile1() {
            try{
                      File file = new File("file.txt");
                   FileReader fr = new FileReader(file);
               }catch(FileNotFoundException e){
                   System.out.println("Exception handled in getfile1");
           }
       }
       public static void getFile2() throws FileNotFoundException{
              File file = new File("file.txt");
           FileReader fr = new FileReader(file);
       }
    }

    这样做是可以的。。。在没有文件的情况下(触发exception)运行结果:

    Exception handled in getfile1
    =============
    Exception in thread "main" java.io.FileNotFoundException: file.txt (No such file or directory)
        at java.io.FileInputStream.open0(Native Method)
        at java.io.FileInputStream.open(FileInputStream.java:195)
        at java.io.FileInputStream.<init>(FileInputStream.java:138)
        at java.io.FileReader.<init>(FileReader.java:72)
        at ReadFileTest.getFile2(ReadFileTest.java:21)
        at ReadFileTest.main(ReadFileTest.java:8)

    3.如何应用custom的exception
    3.1 如何创建一个custom的exception类
    extends exception和它的孩子们呀

    1. class New1Exception extends Exception { } // 创建一个checked exception
    2. class NewException extends IOExcpetion { } // 创建一个跟IO相关的exception
    3. class NewException extends RuntimeException { } // 创建一 UnChecked exception

    来个例子(就是这么简单):

    import java.io.*;
    class MyException extends Exception
    {
        public MyException(String s)
        {
            super("a MyException happens: " + s);
            //还可以做一些其他的事
        }
    }

    3.2 如何甩出(throw)一个custom的exception
    throw 和throws
    throw是在方法或者代码块里面,用来扔炸弹 抛出异常。
    throws是在方法声明的时候,说明这个方法抛出了异常。

    用刚才的MyException写个例子:

    import java.io.*;
    public class Main
    {
        public static void main(String args[])
        {
            try {
                throwTest();
            } catch (MyException e) {
                System.out.println("Caught something");
                System.out.println(e.getMessage());
            }
            //throwTest2是一个正常的方法,扔的exception被自己handle了。
            throwTest2();
            //另用一个block测试test3,
            //如果写在同一个block,throwTest()抛出异常后,throwTest3()不会被执行
            try {
                throwTest3();
            } catch (MyException e) {
                System.out.println("Caught something");
                System.out.println(e.getMessage());
            }
        }
        // 自己不handle,扔出来之后继续在方法声明里告诉调用自己的方法需要handle
        public static void throwTest() throws MyException {
            throw new MyException("something");
        }
        //自己handle了,变成一个正常的方法
        public static void throwTest2() {
            try {
                throw new MyException("somethingElse");
            } catch (MyException e) {
                System.out.println("Caught somethingElse");
                System.out.println(e.getMessage());
            }
        }
        //自己handle了,在catch里继续往外扔。
        public static void throwTest3() throws MyException{
            try {
                throw new MyException("somethingElse2");
            } catch (MyException e) {
               //一个非常不负责任的catch,但是是合法的。
               throw e;
            }
        }
    }  

    输出:

    Caught something
    a MyException happens: something
    Caught somethingElse
    a MyException happens: somethingElse
    Caught something
    a MyException happens: somethingElse2

  • 相关阅读:
    ASP.NET MVC 中的视图生成
    atm
    Oracle 客户端 NLS_LANG 的设置(转)
    log4jdbc
    java基本类型作为成员变量时的初始值
    使用activeMQ实现jms
    JAVA反射机制
    [notes] ImageNet Classification with Deep Convolutional Neual Network
    cocos2d-x3.0 ListView
    Mean Shift具体介绍
  • 原文地址:https://www.cnblogs.com/zhuyeshen/p/10968244.html
Copyright © 2020-2023  润新知