Thinking in java Chapter12 Java 通过异常处理错误信息

java的基本理念是"结构不佳的代码不能够运行"

发现错误的理想时机是编译阶段,然而,编译期间并不能找出所有的错误,余下的问题必须在运行时期解决。

1 概念

2 基本异常

异常情形(exceptional conditin)是指阻止当前方法或作用域继续执行的问题.

普通问题是指在当前环境下能得到足够的信息,总能处理这个错误

当抛出异常后,有几件事会随之发生。首先,同Java中其它对象的创建一样,将使用new在堆上创建异常对象。然后,当前的执行路径被终止,并且从当前环境中弹出对异常对象的引用。此时,异常处理机制接管程序,并开始寻找一个恰当的地方来继续执行程序。这个恰当的地方就是异常处理程序,它的任务是将程序从错误状态中恢复,以使程序要么换一种方式运行,要么继续运行下去。
if(t == null) throw new NullPointerException();//这样就把错误信息传播到更大的环境中,
标准异常都有两个构造器:一个是默认构造器,一个是接受字符串作为参数,以便能把有关信息放入异常对象的构造器;

能够抛出任意类型的Throwable对象,它是异常的根类

3 捕获异常

监控区域(guarded region):一段可能产生异常的代码,并且后面跟着处理这些异常的代码

  1. try块

如果在方法内部抛出异常后,这个方法将在抛出异常的过程中结束,如果不想就此结束,可以设置一个try块来捕获异常

try{
//Code that might generate exception
}
2.异常处理程序

异常处理程序紧跟在try块之后,以关键字catch表示,异常处理程序必须紧跟在try块之后,当异常被抛出时,异常处理机制将负责搜寻参数与异常类型想匹配的第一个处理程序,然后进入catch子句执行,此时认为异常得到了处理,一旦catch子句结束才处理程序的查找过程结束,并不会在调用其它catch子句.

异常处理模型

终止模型:错误非常关键,一旦异常被抛出,即终止程序

4 创建自定义异常

编译器创建了默认构造器,它将自动调用基类的默认构造器,一般不会用Excetption(String)这样的构造器,这种构造器不实用,对异常来说最重要的是类名

package exceptions;

class SimpleException extends Exception{} 
// 编译器创建了默认构造器,自动调用基类的默认构造器  
/*
public class Exception extends Throwable 
    public Exception() {
        super();
    }
 
 public class Throwable implements Serializable    
        public Throwable() {
        fillInStackTrace();
    }

 */

public class InheritingExceptions{
    public void f() throws SimpleException{
        System.out.println("Throw SimpleException from f()");
        throw new SimpleException();
    }

    public static void main(String[] args) {
        InheritingExceptions sed = new InheritingExceptions();
        try{
            sed.f();
        }catch (SimpleException e){
            System.out.println("Caught it");
        }
    }
}
/*
Throw SimpleException from f()
Caught it
 */

也可以通过写入System.err而将错误发送给标准错误流,更容易被用户注意。

通常这比System.out要好,因为System.out也许被重定向

package exceptions;

class MyException extends Exception{
    public MyException(){}
    public MyException(String msg){ super(msg);} //接受字符串参数的构造器
}

public class FullConstructors {
    public static void f() throws MyException {
        System.out.println("Throwing MyException from f()");
        throw new MyException();
    }

    public static void g() throws MyException {
        System.out.println("Throwing MyException from g()");
        throw new MyException("Originate in g()");
    }

    public static void main(String[] args) {
        try {
            f();
        } catch (MyException e) {
//            e.printStackTrace(); // 默认 标准错误流,不会被重定向,容易引起用户注意
            e.printStackTrace(System.err); // 标准错误流,不会被重定向,容易引起用户注意
            e.printStackTrace(System.out); // 标准输出流,也许会被重定向
        }

        try {
            g();
        } catch (MyException e) {
            e.printStackTrace(System.out);
        }
    }
}
/*
Throwing MyException from f()
exceptions.MyException
    at exceptions.FullConstructors.f(FullConstructors.java:11) // printStackTrace 打印 从方法调用处 直到异常抛出处的方法调用序列。
    at exceptions.FullConstructors.main(FullConstructors.java:21)
Throwing MyException from g()
exceptions.MyException: Originate in g()
    at exceptions.FullConstructors.g(FullConstructors.java:16)
    at exceptions.FullConstructors.main(FullConstructors.java:28)
 */
作业1
package exceptions.e1;

public class E1 {
    public static void main(String[] args) {
        try {
            throw new Exception("An exception in E1 main");

        } catch (Exception e) {
            System.out.println(e.getMessage());
//            e.printStackTrace();
        }finally {
            System.out.println("In finally clause");
        }
    }
}
/*
An exception in E1 main
In finally clause
 */
作业2

package exceptions.e2;

public class E2 {
public static void main(String[] args) {
String s = null;
try{
s.toString();
}catch (Exception e){
e.printStackTrace();
}
}
}
/
java.lang.NullPointerException
at exceptions.e2.E2.main(E2.java:8)
/

作业3
package exceptions.e3;

public class E3 {

    public static void main(String[] args) {
        String[] strings = new String[5];
        for (int i = 0; i < strings.length; i++) {
            strings[i] = Integer.toString(i);
        }
        try {
            System.out.println(strings[6]);
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("e: " + e);
        }
    }
}
/*
e: java.lang.ArrayIndexOutOfBoundsException: 6
 */
作业4
package exceptions.e4;


class MyException extends Exception {
    String msg;

    public MyException(String msg) {
        this.msg = msg;
    }

    public void printMsg() {
        System.out.println("msg = " + msg);
    }
}

// Or take a more clever approach,
// noting that string storage and printing are
// built into Exception:
class MyException2 extends Exception {
    public MyException2(String s) {
        super(s);
    }
}

public class E4 {
    public static void main(String[] args) {
        try {
            throw new MyException("MyException message");
        } catch (MyException e) {
            e.printMsg();
        }
        try {
            throw new MyException2("MyException2 message");
        } catch (MyException2 e) {
            System.out.println(
                    "e.getMessage() = " + e.getMessage());
        }
    }
}
作业5
package exceptions.e5;

/*终止模型 Java支持
错误非常关键,一旦异常被抛出,即终止程序
 */

/*恢复模型
恢复模型:意思是异常处理程序的工作是修正错误,然后重新尝试调用出问题的方法,并认为第二次可以成功
如果要用java实现类似的恢复行为,那么在遇到错误时,就不能抛出异常,
而时调用正确的方法来修正该错误,或者把try块放进一个while循环里,这样就不断进入while块,直到得到满意的结果。
 */


class ResumerException extends Exception {
}

class Resumer {
    static int count = 3;

    static void f() throws ResumerException {
        if (--count > 0)
            throw new ResumerException();
    }
}

public class E5 {
    public static void main(String[] args) {
        while (true) {
            try {
                Resumer.f();
            } catch (ResumerException e) {
                e.printStackTrace();
                continue;// 停止当前while迭代,退回循环起始处,开始下一次迭代
            }
            System.out.println("Got through...");
            break;//强行退出while循环,不执行剩余语句
        }
        System.out.println("Successful execution");
    }
}
/*
exceptions.e5.ResumerException
    at exceptions.e5.Resumer.f(E5.java:22)
    at exceptions.e5.E5.main(E5.java:30)
exceptions.e5.ResumerException
    at exceptions.e5.Resumer.f(E5.java:22)
    at exceptions.e5.E5.main(E5.java:30)
Got through...
Successful execution

 */

4.1异常与记录日志

1.利用java.util.logging工具将输出记录到日志中

package exceptions;

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

class LoggingException extends Exception{
    private static Logger logger = Logger.getLogger("LoggingException");
    //Logger.getLogger()方法创建了一个String参数相关联的Logger对象(通常是与错误相关的包名或类名)
    //这个Logger对象会将其输出发送到System.err
    public LoggingException(){
        StringWriter trace = new StringWriter();
        printStackTrace(new PrintWriter(trace));
        //printStackTrace不会产生默认字符串,为了获取字符串,我们使用重载的
        //printStackTrace()方法,它接受一个java.io.PrintWriter()对象作为参数,如果我们将一个SrtingWriter对象传递给
        //这个Printwrite()构造器,那么就可以调用toString()方法,就可以抽取为一个String
        logger.severe(trace.toString());//severe写入日志
    }

}
public class LoggingExceptions {
    public static void main(String[] args) {
        try{
            throw new LoggingException();
        }catch (LoggingException e){
            System.out.println("Caught " + e);
        }

        try{
            throw new LoggingException();
        }catch (LoggingException e){
            System.out.println("Caught " + e);
        }
    }
}
/*
十一月 19, 2019 5:45:16 下午 exceptions.LoggingException <init>
严重: exceptions.LoggingException
    at exceptions.LoggingExceptions.main(LoggingExceptions.java:24)

Caught exceptions.LoggingException
十一月 19, 2019 5:45:16 下午 exceptions.LoggingException <init>
严重: exceptions.LoggingException
    at exceptions.LoggingExceptions.main(LoggingExceptions.java:30)

Caught exceptions.LoggingException
 */

2.捕获和记录其它人编写的异常

尽管LoggingException将所有记录日志的基础设施都构建在了异常自身中,使用它非常方便.

但更常见的是我们需要捕获和记录其它人编写的异常,必须在异常处理程序中生成日志消息

package exceptions;

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

public class LoggingExceptions2 {
    private static Logger logger =
            Logger.getLogger("LoggingExceptions2");
    static void logException(Exception e) {
        StringWriter trace = new StringWriter();
        e.printStackTrace(new PrintWriter(trace));
        logger.severe(trace.toString());
    }
    public static void main(String[] args) {
        try {
            throw new NullPointerException();
        } catch(NullPointerException e) {
            logException(e);
        }
    }
}
/*
十一月 19, 2019 5:56:10 下午 exceptions.LoggingExceptions2 logException
严重: java.lang.NullPointerException
    at exceptions.LoggingExceptions2.main(LoggingExceptions2.java:17)
 */

3.自定义异常

自定义异常,比如加入额外的构造器和成员,因为我们必须在异常处理信息中生成日志信息

对异常类来说,覆盖了 Throwable的 getMessage
public String getMessage() {
return detailMessage;
}

getMessage() { //相当于toString()方法
package exceptions;

import static net.mindview.util.Print.print;

class MyException2 extends Exception {
    private int x;
    public MyException2() {}
    public MyException2(String msg) { super(msg); }
    public MyException2(String msg, int x) {
        super(msg);
        this.x = x;
    }
    public int val() { return x; }
    public String getMessage() { //相当于toString()方法
        return "Detail Message: "+ x + " "+ super.getMessage();
    }
}

public class ExtraFeatures {
    public static void f() throws MyException2 {
        print("Throwing MyException2 from f()");
        throw new MyException2();
    }
    public static void g() throws MyException2 {
        print("Throwing MyException2 from g()");
        throw new MyException2("Originated in g()");
    }
    public static void h() throws MyException2 {
        print("Throwing MyException2 from h()");
        throw new MyException2("Originated in h()", 47);
    }
    public static void main(String[] args) {
        try {
            f();
        } catch(MyException2 e) {
            e.printStackTrace(System.out);
        }
        try {
            g();
        } catch(MyException2 e) {
            e.printStackTrace(System.out);
        }
        try {
            h();
        } catch(MyException2 e) {
            e.printStackTrace(System.out);
            System.out.println("e.val() = " + e.val());
        }
    }
}
/*
Throwing MyException2 from f()
exceptions.MyException2: Detail Message: 0 null
    at exceptions.ExtraFeatures.f(ExtraFeatures.java:22)
    at exceptions.ExtraFeatures.main(ExtraFeatures.java:34)
Throwing MyException2 from g()
exceptions.MyException2: Detail Message: 0 Originated in g()
    at exceptions.ExtraFeatures.g(ExtraFeatures.java:26)
    at exceptions.ExtraFeatures.main(ExtraFeatures.java:39)
Throwing MyException2 from h()
exceptions.MyException2: Detail Message: 47 Originated in h()
    at exceptions.ExtraFeatures.h(ExtraFeatures.java:30)
    at exceptions.ExtraFeatures.main(ExtraFeatures.java:44)
e.val() = 47
 */
作业6
package exceptions.e6;

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

class LoggingException1 extends Exception {
    private static Logger logger = Logger.getLogger("LoggingException1");

    public LoggingException1() {
        StringWriter trace = new StringWriter();
        printStackTrace(new PrintWriter(trace));
        logger.severe(trace.toString());
    }

}

class LoggingException2 extends Exception {
    private static Logger logger = Logger.getLogger("LoggingException2");

    public LoggingException2() {
        StringWriter trace = new StringWriter();
        printStackTrace(new PrintWriter(trace));
        logger.severe(trace.toString());
    }


}

public class E6 {
    public static void main(String[] args) {
        try {
            throw new LoggingException1();
        } catch (LoggingException1 e) {
            System.out.println("Caught" + e);
        }

        try {
            throw new LoggingException2();
        } catch (LoggingException2 e) {
            System.out.println("Caught  " + e);
        }
    }
}
/*
每个异常都使用自己的logger实例,分别是LoggingException1和LoggingException2。
十一月 19, 2019 6:15:02 下午 exceptions.e6.LoggingException1 <init>
严重: exceptions.e6.LoggingException1
    at exceptions.e6.E6.main(E6.java:33)

Caughtexceptions.e6.LoggingException1
十一月 19, 2019 6:15:02 下午 exceptions.e6.LoggingException2 <init>
严重: exceptions.e6.LoggingException2
    at exceptions.e6.E6.main(E6.java:39)

Caught  exceptions.e6.LoggingException2
 */
作业7
package exceptions.e7;

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

public class E3 {
    private static Logger logger = Logger.getLogger("E3");

    static void logExcption(Exception e) {
        StringWriter trace = new StringWriter();
        e.printStackTrace();
        new PrintWriter(trace);
        logger.severe(trace.toString());
    }

    public static void main(String[] args) {
        String[] strings = new String[5];
        for (int i = 0; i < strings.length; i++) {
            strings[i] = Integer.toString(i);
        }
        try {
            System.out.println(strings[6]);
        } catch (ArrayIndexOutOfBoundsException e) {
            logExcption(e);
        }
    }
}
/*
e: java.lang.ArrayIndexOutOfBoundsException: 6
 */

5 异常说明

异常说明使用了附加的关键字 throws ,后面接一个所有潜在异常类型的列表,方便客户端程序员查看.

public static void main(String[] args) 
throws NullPointerException,NoSuchFieldError //这里就是异常说明
  {
    try {
      throw new NullPointerException();
    } catch(NullPointerException e) {
      logException(e);
    }
  }

自顶向下强制执行对异常说明机制,java在编译时候就保证一定水平对异常准确性。

要么处理这个异常,要么就在异常说明中表面此方法将产生异常。

“作弊”方法:声明方法将抛出异常,实际不抛出:为异常占个位置,以后就可以抛出异常而不用修改已有代码。在抽象基类和接口定义时这种能力很重要,派生类或接口实现就能抛出预先声明的异常。

作业7
package exceptions.e8;


class MyException extends Exception {
    public MyException(String s) {
        super(s);
    }
}

class Thrower {
//    public void f(){
//        throw new MyException("MyException in f()");
//    }
    public void g() throws MyException {
        throw new MyException("MyException in g()");
    }
}

public class E8 {
    public static void main(String[] args) {
        Thrower t = new Thrower();
        try{
            t.g();
        } catch (MyException myException2) {
            myException2.printStackTrace();
        }
    }
}
/*
exceptions.e8.MyException: MyException in g()
    at exceptions.e8.Thrower.g(E8.java:15)
    at exceptions.e8.E8.main(E8.java:23)
 */

猜你喜欢

转载自www.cnblogs.com/erinchen/p/11888357.html