背景
继续查缺补漏
1.异常与记录日志
例如:
import java.io.*;
import java.util.logging.*;
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);
}
}
}
这里用了 java.util.logging 工具将输出记录到日志中。 Logger.getLogger()方法创建了一个String参数相关联
的Logger对象(通常与错误相关的包名和类名),这个Logger对象会将输出发送到System.err。向Logger写
入的最简单方式就是直接调用与日志记录消息级别想关联的方法,这里使用了severe()。
还可以自己写一个方法来记录其他人编写的异常,例如:
static void logException(Exception e){
StringWriter trace=new StringWriter();
e.printStackTrace(new PrintWriter(trace));
logger.severe(trace.toString());
}
2.printStackTrace()
printStackTrace()方法所提供的信息可以通过getStackTrace()方法来直接访问,返回一个由栈轨迹中的元素
构成的数组,元素0是栈顶元素,并且是调用序列中的最后一个方法调用。
3.重新抛出异常
重抛异常会把异常抛给上一级环境中的异常处理程序,同一个try快的后续catch子句将被忽略。
4.异常链
捕获一个异常后抛出另一个异常,并且希望把原始异常的信息保存下来,这被称为异常链。
Throwable的子类在构造器中都可以接受一个cause对象作为参数。cause用来表示原始异常,
通过把原始异常传递给新的异常,就可以保留原始的异常数据。
在Throwable的子类中,只有Error、Exception、RuntimeException提供了带cause参数的构造器。
如果要把其他类型的异常链接起来,就要使用initCause()方法。例如:
catch(NoSuchFieldException e){
throw new RuntimeException(e);
}
DynamicFieldsException dfe=new DynamicFieldsException();
dfe.initCause(new NullPointerException());
throw dfe;
5.异常
异常的基本概念是用名称代表发生的问题。
Throwable对象可分为两种类型,Error和Exception
Error:用来表示编译时和系统错误
Exception:是可以被抛出的基本类型,我们通常关心这个类型。
特例RuntimeException:如果RuntimeException没有被捕获而直达main(),那么在程序退出前将调用异常
printStackTrace()方法。
6.在return中使用finally
例如:
import static tools.Print.*;
public class MultipleReturns {
public static void f(int i){
print("Initialization that requires cleanup");
try{
print("Point 1");
if(i==1) return;
print("Point 2");
if(i==2) return ;
print("Point 3");
if(i==3) return;
print("End");
return;
}finally{
print("Performing cleanup");
}
}
public static void main(String[] args){
for(int i=1;i<=4;i++)
f(i);
}
}
在f()方法中,可以从多个点返回,并且可以保证finally中的语句仍然得到执行。
7.构造器
(1)在构造阶段可能对抛出异常,并且要求清理的类,最安全的使用方式是使用嵌套的try语句。例如:
try{
InputFile in=new InputFile("Cleanup.java");
try{
String s;
int i=1;
while((s=in.getLine())!=null)
;
}catch(Exception e){
System.out.println("Caught Exception in main");
e.printStackTrace(System.out);
}finally{
in.dispose();
}
}catch(Exception e){
System.out.println("InputFile construction failed");
}
如果构造出现异常就不会执行in.dispose()。构造成功后就一定会执行in.dispose()。
(2)在创建需要清理的对象之后,立即进入一个try-finally语句块。
NeedsCleanup nc1=new NeedsCleanup();
try{
//...
}finally{
nc1.dispose();
}
8.把“被检查的异常”转换为“不检查的异常”
直接把“被检查的异常”包装进RuntimeException里面
try{
///...
}catch(Exception e){
throw new RuntimeException(e);
}
用getCause()捕获并处理特定异常,例如:
catch(RuntimeException re){
try{
throw re.getCause();
}catch(FileNotFoundException e){
}catch(IOException e){
}catch(Throwable e){
}
}