《Think in Java》阅读笔记·第三卷

通过异常处理错误

异常情形:是指阻止当前方法或作用域继续执行的问题。

监控区域:一段可能产生异常的代码区域,即try区域。

异常处理程序:处理异常的地点,即catch区域。

异常处理的两种模型

终止模型:一旦抛出异常,将无法返回产生异常处。

恢复模型:在产生异常时不抛出异常,而是通过方法或者将try放到循环语句中以修补异常。

注意:恢复模型容易增强程序耦合性

自定义异常

import java.util.logging.Logger;

public class MyException {
    private static void f() throws CustomException{
        System.out.println("f:");
        throw new CustomException();
    }
    private static void g(String msg)throws  CustomException{
        System.out.println("g:");
        throw new CustomException(msg);
    }
    private static void h(){
        int x,y,z;
        x=4;
        y=0;
        try {
            z=x/y;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static void main(String... args) {
        try {
            f();
        } catch (CustomException e) {

            e.printStackTrace(System.out);
        }
        try {
            g("msg");
        } catch (CustomException e) {
            e.printStackTrace(System.out);
        }
        h();
    }
}
class CustomException extends Exception{
    private Logger logger=Logger.getLogger("CustomException");
    public CustomException(){
    }
    public CustomException(String msg){
        super(msg);
    }

    @Override
    public String getMessage() {
        //return super.getMessage();
        return "This is my custom error info";
    }
}

当注释掉return super.getMessage():

f:
thinkinjava.CustomException: This is my custom error info
at thinkinjava.MyException.f(MyException.java:7)
at thinkinjava.MyException.main(MyException.java:26)
g:
thinkinjava.CustomException: This is my custom error info
at thinkinjava.MyException.g(MyException.java:11)
at thinkinjava.MyException.main(MyException.java:32)
h:
java.lang.ArithmeticException: / by zero
at thinkinjava.MyException.h(MyException.java:19)
at thinkinjava.MyException.main(MyException.java:36)

当注释掉return “This is my custom error info”:

f:
thinkinjava.CustomException
at thinkinjava.MyException.f(MyException.java:7)
at thinkinjava.MyException.main(MyException.java:26)
g:
thinkinjava.CustomException: msg
at thinkinjava.MyException.g(MyException.java:11)
at thinkinjava.MyException.main(MyException.java:32)
h:
java.lang.ArithmeticException: / by zero
at thinkinjava.MyException.h(MyException.java:19)
at thinkinjava.MyException.main(MyException.java:36)

getMessage类似于toString方法

异常与记录日志

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.logging.Logger;

public class LoggerException {
    private static  Logger logger=Logger.getLogger("LoggerException");
    private static void logprint(Exception e){
        StringWriter sw=new StringWriter();
        PrintWriter pw=new PrintWriter(sw);
        e.printStackTrace(pw);
        logger.severe(pw.toString());
    }
    public static void main(String...args){
        try {
            throw new NullPointerException();
        } catch (NullPointerException e) {
            logprint(e);
        }
    }
}

五月 01, 2018 9:31:36 下午 thinkinjava.LoggerException logprint
严重: java.io.PrintWriter@330bedb4

throw:抛错误给上一层处理

public class Thrower {
    static void demoproc() {
        try {
            throw new NullPointerException("demo");
        } catch(NullPointerException e) {
            System.out.println("Caught inside demoproc.");
            throw e;
        }
    }
    public static void main(String args[]) {
        try {
            demoproc();
        } catch(NullPointerException e) {
            System.out.println("Recaught: " + e);
        }
    }
}

Caught inside demoproc.
Recaught: java.lang.NullPointerException: demo

栈轨迹

public class StackTracer {
    private static void a(){
        try{
            throw new Exception();
        }catch (Exception e){
            for(StackTraceElement stackTraceElement:e.getStackTrace())
                System.out.println(stackTraceElement.getMethodName());
        }
    }
    private static void b(){
       a();
    }
    private static void c(){
        b();
    }
    public static void main(String...args){
        a();
        System.out.println("-------------");
        b();
        System.out.println("-------------");
        c();

    }
}

输出:

a
main
-------------
a
b
main
-------------
a
b
c
main

从栈底开始调用,类似于递归

若把当前异常重新抛出,printStackTrace()显示的仍然是原来异常抛出点的调用栈信息
    private static void  d() throws Exception{
        throw new Exception("throw new Exception from d");
    }

    private static void e() throws Exception{
        try{
            d();
        }catch (Exception e){
            System.out.println("e try catch");
            e.printStackTrace(System.out);
            throw e;
        }
    }

    private static void f() throws Exception{
        try{
            d();
        }catch (Exception e){
            System.out.println("f try catch");
            e.printStackTrace(System.out);
            throw (Exception) e.fillInStackTrace();
        }
    }
    public static void main(String...args){
        try {
            e();
        }catch (Exception e){
            System.out.println("main try catch from e");
            e.printStackTrace(System.out);
        }
        try {
            f();
        }catch (Exception e){
            System.out.println("main try catch from f");
            e.printStackTrace(System.out);
        }
    }

e try catch
java.lang.Exception: throw new Exception from d
at thinkinjava.StackTracer.d(StackTracer.java:19)
at thinkinjava.StackTracer.e(StackTracer.java:24)
at thinkinjava.StackTracer.main(StackTracer.java:44)
main try catch from e
java.lang.Exception: throw new Exception from d
at thinkinjava.StackTracer.d(StackTracer.java:19)
at thinkinjava.StackTracer.e(StackTracer.java:24)
at thinkinjava.StackTracer.main(StackTracer.java:44)
f try catch
java.lang.Exception: throw new Exception from d
at thinkinjava.StackTracer.d(StackTracer.java:19)
at thinkinjava.StackTracer.f(StackTracer.java:34)
at thinkinjava.StackTracer.main(StackTracer.java:51)
*main try catch from f
java.lang.Exception: throw new Exception from d
at thinkinjava.StackTracer.f(StackTracer.java:38)
at thinkinjava.StackTracer.main(StackTracer.java:51)

如最后一个输出结果,其已经不再输出原来的那个抛出点了d了

若抛出的是两个不同的自定义异常,那么就无法关联,即第二次抛出点打印出的栈轨迹不会有第一次的任何信息,这是如果我们也要打印第一次抛出点的栈轨迹,则需要用到异常链:

public class ExceptionLink {
    class MyException2 extends Exception{
        public MyException2(Throwable throwable){
            super(throwable);
        }
        public MyException2(){
            super();
        }
    }
    class MyException1 extends Exception{
        public  MyException1(){
            super();
        }
    }
    private void a() throws MyException1{
        throw new MyException1();
    }
    private  void b() throws MyException2{
        try {
            a();
        }catch (MyException1 exception1){
            System.out.println("b try catch");
            exception1.printStackTrace(System.out);
            throw new MyException2();
            //throw new MyException2(exception1);
        }
    }
    public static void main(String...args){
        ExceptionLink exceptionLink=new ExceptionLink();
        try {
            exceptionLink.b();
        } catch (MyException2 myException2) {
            System.out.println("main try catch");
            myException2.printStackTrace(System.out);
        }
    }
}

输出:

b try catch
thinkinjava.ExceptionLink$MyException1
    at thinkinjava.ExceptionLink.a(ExceptionLink.java:18)
    at thinkinjava.ExceptionLink.b(ExceptionLink.java:22)
    at thinkinjava.ExceptionLink.main(ExceptionLink.java:32)
main try catch
thinkinjava.ExceptionLink$MyException2
    at thinkinjava.ExceptionLink.b(ExceptionLink.java:26)
    at thinkinjava.ExceptionLink.main(ExceptionLink.java:32)

如上在第二个抛出点并没有抛出第一个抛出点所抛出的信息,因为这是两个不同异常类
若将注释掉的那行取消掉注释则会输出:

b try catch
thinkinjava.ExceptionLink$MyException1
    at thinkinjava.ExceptionLink.a(ExceptionLink.java:18)
    at thinkinjava.ExceptionLink.b(ExceptionLink.java:22)
    at thinkinjava.ExceptionLink.main(ExceptionLink.java:32)
main try catch
thinkinjava.ExceptionLink$MyException2: thinkinjava.ExceptionLink$MyException1
    at thinkinjava.ExceptionLink.b(ExceptionLink.java:26)
    at thinkinjava.ExceptionLink.main(ExceptionLink.java:32)
Caused by: thinkinjava.ExceptionLink$MyException1
    at thinkinjava.ExceptionLink.a(ExceptionLink.java:18)
    at thinkinjava.ExceptionLink.b(ExceptionLink.java:22)
    ... 1 more

这便是异常链

finally语句在return语句中使用
try{
    return;
}finally{
    System.out.println("before return")
}

其会在返回前输出”before return”

异常丢失

造成异常丢失的两种情况:

try{
    throw new Exception1();
}finally{
    throw new Exception2();
}
try{
    throw new MyException();
}finally{
    return;
}

猜你喜欢

转载自blog.csdn.net/figurers/article/details/80160438