Thinking in Java异常笔记与习题


Thinking in Java异常笔记

创建自定义异常

package exception;

class MyException extends Exception {
    public MyException() {}

    public MyException(String message) {
        super(message);
    }
}

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

    public static void main(String[] args) {
        try {
            f();
        } catch (MyException e) {
            e.printStackTrace(System.out);
        }
        try {
            g();
        } catch (MyException e) {
            e.printStackTrace(System.out);
        }
    }
}
/* output
Throwing My exception from f()
exception.MyException
	at exception.FullConstructors.f(FullConstructors.java:14)
	at exception.FullConstructors.main(FullConstructors.java:23)
Throwing My exception from g()
exception.MyException: Originated in g()
	at exception.FullConstructors.g(FullConstructors.java:18)
	at exception.FullConstructors.main(FullConstructors.java:28)
*/

如果使用e.printStackTrace(System.err)将错误发送给标准错误流,通常这比错误输出到System.out要好,因为System.out也许会被重定向,System.err不会,更容易引起用户注意

调用在Throwable类(Exception 从此类继承)中声明的printStackTrace()方法,将打印从方法调用处直到异常抛出处,信息被发送到System.out。但如果调用了默认版本e.printStackTrace(),则输入到标准错误流。

异常说明

属于方法声明的一部分,紧跟在参数列表之后,使用了附加的关键字throws,后面接一个所有潜在异常类型的列表。使你告知客户端程序员某个方法可能会抛出的异常类型,然后客户端程序员就可以进行相应的处理。代码必须与异常保持一致,如果方法里面的代码产生了异常,却没有进行处理,编译器会发现这个问题

异常丢失

某些特殊的方式使用finally造成异常丢失

package exceptions;

class VeryImportantException extends Exception {
    @Override
    public String toString() {
        return "A very important exception!";
    }
}

class ImportantException extends Exception {
    @Override
    public String toString() {
        return "An important exception!";
    }
}
class HoHumException extends Exception {//HoHum令人生厌的
    @Override
    public String toString() {
        return "A trivial exception!";//trivial:不重要的
    }
}


public class LostMessage {
    void f() throws VeryImportantException {
        throw new VeryImportantException();
    }

    void g() throws ImportantException {
        throw new ImportantException();
    }

    void dispose() throws HoHumException {
        throw new HoHumException();
    }

    public static void main(String[] args) {
        try {
            LostMessage lm = new LostMessage();
            try {
                lm.f();
            } finally {
                lm.dispose();
            }
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}
/* 
A trivial exception!
*/

更加简单的丢失异常的方式:从finally子句中返回

package exceptions;

public class ExceptionSilencer {
    public static void main(String[] args) {
        try {
            throw new RuntimeException();
        } finally {
            return;
        }
    }
}

异常匹配

抛出异常的时候,异常处理系统会按照代码的书写顺序找出“最近”的处理程序,找的匹配的处理程序之后,它就认为异常得到处理,然后不再查找。查找的时候并不要求异常完全匹配,派生类的对象也可以匹配其基类的处理程序。

package exceptions;

class Annoyance extends Exception {}
class Sneeze extends Annoyance {}

public class Human {
    public static void main(String[] args) {
        try {
            throw new Sneeze();
        } catch (Sneeze s) {
            System.out.println("Caught Sneeze");
        } catch (Annoyance a) {
             System.out.println("Caught Annoyance");
        }

        try {
            throw new Sneeze();
        } catch (Annoyance a) {
            System.out.println("Caught Annoyance");
        }
    }
}

基本日志功能(将输出 记录到日志中)

package exception;

import java.util.logging.*;
import java.io.*;
class LoggingException extends Exception {
    private static Logger logger = Logger.getLogger("LoggingException");    
    public LoggingException() {
        StringWriter trace = new StringWriter();
        printStackTrace(new PrintWriter(trace));
        logger.severe(trace.toString());
    }

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

}
public static Logger getLogger(String name)
//name是Logger的名称,此名称创建过再次创建则返回原来的Logger
logger.severe(trace.toString());
/*output:
8月 12, 2020 5:02:56 下午 exception.LoggingException 
严重: exception.LoggingException at   exception.LoggingExceptions.main(LoggingExceptions.java:17)*/
StringWriter trace = new StringWriter();
public StringWriter() {
        buf = new StringBuffer();
        lock = buf;
}

Logger级别

severe 严重
warning 警告
info 信息
config 配置
fine 良好
finer 较好
finest 最好
all 开启所有级别日志记录
off 关闭所有级别日志记录

习题

练习1:编写一个类,在其main()方法的try块里抛出一个Exception类的对象。穿第一个字符串参数给Exception的构造器。在catch子句里捕获此异常对象,并且打印字符串参数。添加一个finally子句,打印一条信息以证明这里确实得到了执行。

package exceptions;

public class Test01 {
    public static void main(String[] args) {
        try {
            throw new Exception("This is a exception");
        } catch (Exception e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        } finally {
            System.out.println("try - catch finished");
        }
    }
}
/* 
This is a exception
try - catch finished
*/

练习2:定义一个对象引用并初始化为null,尝试用此引用调用方法。把这个引用放在try-catch子句里以捕获异常。

package exceptions;

class Monkey {
    void eat() {
        System.out.println("eating");
    }
}

public class Test02 {
    public static void main(String[] args) {
        Monkey monkey = null;
        try {
            monkey.eat();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

/*
java.lang.NullPointerException
	at exceptions.Test02.main(Test02.java:13)
*/

练习3:编写能产生并能捕获ArrayIndexOutOfBoundsException异常的代码。

package exceptions;

public class Test03 {
    public static void main(String[] args) {
        int[] a = new int[10];
        try {
            System.out.println(a[11]);
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("数组越界");
        }
    }
}
/*
数组越界
*/

练习4:使用extends关键宇建立-个自定义异常类。为这个类写一个接受字符串参数的构造器,把此参数保存在对象内部的字符串引用中。写一个方法显示此字符串。写- -个try-catch子句,对这个新异常进行测试。

package exceptions;

class Exception04 extends Exception {
    private String msg;

    public Exception04() {
    }

    public Exception04(String msg) {
        this.msg = msg;
    }
    public String getMsg() {
        return msg;
    }
}

public class Test04 {
    public static void main(String[] args) {
        try {
            throw new Exception04("异常内部字符串");
        } catch (Exception04 e) {
            System.out.println(e.getMsg());
        }
    }
}

/* 
异常内部字符串
*/

练习5:使用while循环建立类似恢复模型的异常处理行为,它将不断重复,直到异常不再抛出。

package exceptions;

public class Test05 {
    public static void main(String[] args) {
        int[] a = new int[] {1, 2, 3, 4, 5};
        byte index = 10;
        while (true) {
            try {
                System.out.println(a[index]);
                break;
            } catch (ArrayIndexOutOfBoundsException e) {
                System.out.println("Index: " + index + " is out of bounds");
                --index;
            }
        }
    }
}

/* 
Index: 10 is out of bounds
Index: 9 is out of bounds
Index: 8 is out of bounds
Index: 7 is out of bounds
Index: 6 is out of bounds
Index: 5 is out of bounds
5
*/

练习18:为LostMessage.java添加第二层异常丢失,以便用第三个异常来替代HoHumException异常。

package exceptions;

class VeryImportantException extends Exception {
    @Override
    public String toString() {
        return "A very important exception!";
    }
}

class ImportantException extends Exception {
    @Override
    public String toString() {
        return "An important exception!";
    }
}
class HoHumException extends Exception {//HoHum令人生厌的
    @Override
    public String toString() {
        return "A trivial exception!";//trivial:不重要的
    }
}


public class LostMessage {
    void f() throws VeryImportantException {
        throw new VeryImportantException();
    }

    void g() throws ImportantException {
        throw new ImportantException();
    }

    void dispose() throws HoHumException {
        throw new HoHumException();
    }

    public static void main(String[] args) {
        try {
            LostMessage lm = new LostMessage();
            try {
                lm.f();
            } finally {
                try {
                    lm.g();
                } finally {
                    lm.dispose();
                }
            }
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}