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);
        }
    }
}