zoukankan      html  css  js  c++  java
  • 违例差错控制

    违例差错控制这个给程序的编写带来了很大的好处:

     1 public class test {
    2 public static void f() throws Exception {
    3 System.out.println(
    4 "originating the exception in f()");
    5 throw new Exception("thrown from f()");
    6 }
    7 public static void g() throws Throwable {
    8 try {
    9 f();
    10 } catch(Exception e) {
    11 System.out.println(
    12 "Inside g(), e.printStackTrace()");
    13 e.printStackTrace();
    14 throw e;
    15 }
    16 }
    17 public static void main(String[] args) throws Throwable {
    18 try {
    19 g();
    20 } catch(Exception e) {
    21 System.out.println(
    22 "Caught in main, e.printStackTrace()");
    23 e.printStackTrace();
    24 }
    25 }
    26 }
    output:
    java.lang.Exception: thrown from f()
    originating the exception in f()
    Inside g(), e.printStackTrace()
    	at test.f(test.java:5)
    	at test.g(test.java:9)
    	at test.main(test.java:21)
    java.lang.Exception: thrown from f()
    	at test.f(test.java:5)
    	at test.g(test.java:9)
    	at test.main(test.java:21)
    Caught in main, e.printStackTrace()

    违例路径堆栈无论如何都会记住它的真正起点,无论自己被重复“投掷”了多少次。printStackTrace()在什么时候会被执行呢?为什么在不同的时候输出的顺序并不相同?什么时候记录调用记录的?从这个程序中都可以看出来了。再来一个例子说明问题:

     1 public class test {
    2 public static void f() throws Exception {
    3 System.out.println(
    4 "originating the exception in f()");
    5 throw new Exception("thrown from f()");
    6 }
    7 public static void main(String[] args) {
    8 try {
    9 f();
    10 } catch(Exception e) {
    11 System.out.println(
    12 "Caught in main, e.printStackTrace()");
    13 e.printStackTrace();
    14 throw new NullPointerException("from main");
    15 }
    16 }
    17 }
    output
    originating the exception in f()
    Caught in main, e.printStackTrace()
    java.lang.Exception: thrown from f()
    	at test.f(test.java:5)
    	at test.main(test.java:9)
    Exception in thread "main" java.lang.NullPointerException: from main
    	at test.main(test.java:14)

    异常和异常之间只是名字的不同(所以名字很重要)。Throwable有两种常规类型:Exception和Error。Error是指编译期和系统错误,我们不必特意捕获他们。Exception是可以从任何标准Java库的类方法中“throw”出的基本类型。RuntimeException在默认情况下自动会处理,如果必须检查RuntimeException那我们的代码就会变得相当复杂(难道我们时不时顶着空指针还得自己处理?)。一个例子:

     1 public class test {
    2 static void f() {
    3 throw new RuntimeException("From f()");
    4 }
    5 static void g() {
    6 f();
    7 }
    8 public static void main(String[] args) {
    9 g();
    10 }
    11 }
    output
    Exception in thread "main" java.lang.RuntimeException: From f()
    	at test.f(test.java:3)
    	at test.g(test.java:6)
    	at test.main(test.java:9)

    如果RuntimeException获得到达main()的所有途径,同时不被捕获,那么程序在退出的时候会自动调用printStackTrace()。

    创建自己的“Exception”还是很简单的吧,举个例子:

     1 class MyException extends Exception {
    2 public MyException() {}
    3 public MyException(String msg) {
    4 super(msg);
    5 }
    6 }
    7 public class test {
    8 public static void f() throws MyException {
    9 System.out.println(
    10 "Throwing MyException from f()");
    11 throw new MyException();
    12 }
    13 public static void g() throws MyException {
    14 System.out.println(
    15 "Throwing MyException from g()");
    16 throw new MyException("Originated in g()");
    17 }
    18 public static void main(String[] args) {
    19 try {
    20 f();
    21 } catch(MyException e) {
    22 e.printStackTrace();
    23 }
    24 try {
    25 g();
    26 } catch(MyException e) {
    27 e.printStackTrace();
    28 }
    29 }
    30 }
    output
    MyException
    	at test.f(test.java:11)
    	at test.main(test.java:20)
    MyException: Originated in g()
    	at test.g(test.java:16)
    	at test.main(test.java:25)Throwing MyException from f()
    Throwing MyException from g()
    

    如何限制违例?在捕获到一个异常的时候怎么知道我们抓到的东西是正确的东西:

     1 class BaseballException extends Exception {}
    2 class Foul extends BaseballException {}
    3 class Strike extends BaseballException {}
    4 abstract class Inning {
    5 Inning() throws BaseballException {}
    6 void event () throws BaseballException {
    7 }
    8 abstract void atBat() throws Strike, Foul;
    9 void walk() {}
    10 }
    11 class StormException extends Exception {}
    12 class RainedOut extends StormException {}
    13 class PopFoul extends Foul {}
    14 interface Storm {
    15 void event() throws RainedOut;
    16 void rainHard() throws RainedOut;
    17 }
    18 public class test extends Inning implements Storm {
    19 test() throws RainedOut, BaseballException {}
    20 test(String s) throws Foul, BaseballException {}
    21 public void rainHard() throws RainedOut {}
    22 public void event() {}
    23 void atBat() throws PopFoul {}
    24 public static void main(String[] args) {
    25 try {
    26 test si = new test();
    27 si.atBat();
    28 } catch(PopFoul e) {
    29 } catch(RainedOut e) {
    30 } catch(BaseballException e) {
    31 }
    32 try {
    33 Inning i = new test();
    34 i.atBat();
    35 } catch(Strike e) {
    36 } catch(Foul e) {
    37 } catch(RainedOut e) {
    38 } catch(BaseballException e) {
    39 }
    40 }
    41 }

    Java提供了用finally来清除(也是一个从异常中恢复运行的例子):

     1 public class test {
    2 static int count = 0;
    3 public static void main(String[] args) {
    4 while(true) {
    5 try {
    6 if(count++ == 0)
    7 throw new Exception();
    8 System.out.println("No exception");
    9 } catch(Exception e) {
    10 System.out.println("Exception thrown");
    11 } finally {
    12 System.out.println("in finally clause");
    13 if(count == 2) break;
    14 }
    15 }
    16 }
    17 }
    output
    Exception thrown
    in finally clause
    No exception
    in finally clause

    finally中的代码不管是在什么情况下都是会执行的。finally能做什么呢?比如打开文件或者套接字的时候,在finally中释放这些资源。如果没有finally要怎么实现:

     1 class Switch {
    2 boolean state = false;
    3 boolean read() { return state; }
    4 void on() { state = true; }
    5 void off() { state = false; }
    6 }
    7 public class test {
    8 static Switch sw = new Switch();
    9 public static void main(String[] args) {
    10 try {
    11 sw.on();
    12 sw.off();
    13 } catch(NullPointerException e) {
    14 System.out.println("NullPointerException");
    15 sw.off();
    16 } catch(IllegalArgumentException e) {
    17 System.out.println("IOException");
    18 sw.off();
    19 }
    20 }
    21 }

    可以看出finally的好处了吧。即使异常不在当前的“catch”中捕获,“finally”都会在违例控制机制转到更高级别搜索一个控制器之前得到执行。eg:

     1 class Ex extends Exception {}
    2 public class test {
    3 public static void main(String[] args) {
    4 System.out.println("Entering first try block");
    5 try {
    6 System.out.println("Entering second try block");
    7 try {
    8 throw new Ex();
    9 } finally {
    10 System.out.println("finally in 2nd try block");
    11 }
    12 } catch(Ex e) {
    13 System.out.println("Caught Ex in first try block");
    14 } finally {
    15 System.out.println("finally in 1st try block");
    16 }
    17 }
    18 }
    output
    Entering first try block
    Entering second try block
    finally in 2nd try block
    Caught Ex in first try block
    finally in 1st try block

    Java的异常控制机制还是有缺陷滴,一个异常可能被简单地“丢弃”,eg:

     1 class VeryImportantException extends Exception {
    2 public String toString() {
    3 return "A very important exception!";
    4 }
    5 }
    6 class HoHumException extends Exception {
    7 public String toString() {
    8 return "A trivial exception";
    9 }
    10 }
    11 public class test {
    12 void f() throws VeryImportantException {
    13 throw new VeryImportantException();
    14 }
    15 void dispose() throws HoHumException {
    16 throw new HoHumException();
    17 }
    18 public static void main(String[] args)
    19 throws Exception {
    20 test lm = new test();
    21 try {
    22 lm.f();
    23 } finally {
    24 lm.dispose();
    25 }
    26 }
    27 }
    output
    Exception in thread "main" A trivial exception
    	at test.dispose(test.java:16)
    	at test.main(test.java:24)

    这样的话“try”块中的异常就被忽略掉了,而输出的异常是“finally”模块中的。用一个例子来看看清除有构建器的文件、套接字等资源的释放(感觉这个还是不错的):

     1 import java.io.*;
    2 class InputFile {
    3 private BufferedReader in;
    4 InputFile(String fname) throws Exception {
    5 try {
    6 in = new BufferedReader(new FileReader(fname));
    7 } catch(FileNotFoundException e) {
    8 System.out.println("Could not open " + fname);
    9 throw e;
    10 } catch(Exception e) {
    11 try {
    12 in.close();
    13 } catch(IOException e2) {
    14 System.out.println("in.close() unsuccessful");
    15 }
    16 throw e;
    17 } finally {}
    18 }
    19 String getLine() {
    20 String s;
    21 try {
    22 s = in.readLine();
    23 } catch(IOException e) {
    24 System.out.println("readLine() unsuccessful");
    25 s = "failed";
    26 }
    27 return s;
    28 }
    29 void cleanup() {
    30 try {
    31 in.close();
    32 } catch(IOException e2) {
    33 System.out.println("in.close() unsuccessful");
    34 }
    35 }
    36 }
    37 public class test {
    38 public static void main(String[] args) {
    39 try {
    40 InputFile in = new InputFile("test.java");
    41 String s;
    42 int i = 1;
    43 while((s = in.getLine()) != null)
    44 System.out.println(""+ i++ + ": " + s);
    45 in.cleanup();
    46 } catch(Exception e) {
    47 System.out.println("Caught in main, e.printStackTrace()");
    48 e.printStackTrace();
    49 }
    50 }
    51 }

    可以用异常来做些什么:

    1. 解决问题并再次调用引起异常的方法;
    2. 平息事态的发展,并在不重新尝试的情况下继续;
    3. 计算另一些结果,而不是希望方法产生的结果;
    4. 在当前环境中尽可能地处理,将相同的异常重新“throw”到一个更高级的环境;
    5. 终止程序的执行;
    6. 简化代码;
    7. 使自己的库和程序更加安全。

    -----------------------------

    个人理解,欢迎拍砖。

  • 相关阅读:
    看书笔记《python基础》__1
    MQTT
    杂记
    类型转化
    soc
    时钟同步
    设置地址
    清理日志
    pandas_matplot_seaborn
    Qt_Quick开发实战精解_4
  • 原文地址:https://www.cnblogs.com/ggzwtj/p/2123872.html
Copyright © 2011-2022 走看看