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 <init>
严重: 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);
}
}
}