给大忙人看的Java核心技术笔记(5、异常、断言、日志处理)

当你抛出一个异常,控制权转移到最近的异常处理器

在java中,由编译器跟踪已检查异常

在正常执行完之后或者异常时,try-with-resources语句会自动关闭资源

堆栈踪迹信息描述了程序执行中挂起时所有方法的调用情况。

日志记录器按照层次来分类,可以接受从SEVERE到FINEST级别范围的日志信息

日志处理器可以将日志信息发送给替代目的地,格式化器控制信息格式

  Java异常处理最根本的有点是,将错误检测和错误处理过程解耦了。

  所有异常继承Throwable类,不期望程序处理的会抛出Error子类、程序员报告的异常属于Exception子类,其中分为uncheck exception 属于RuntimeException的子类。其他异常都是checked Exception.

  程序员必须要么捕获已检查异常,要么在方法头声明它,编译器会检查这些异常是否被妥善处理。

  当继承Exception、RuntimeException类或者其他已存在的异常类来创建你自己的异常时,最好是提供两个构造函数,一个不带参数,一个带消息字符串参数。

异常处理的黄金法则是:“早抛出,后捕获”。

如果父类方法没有throws语句,则覆盖后的方法不能抛出已检查异常。

2、异常捕获

  可以用catch语句从上到下匹配,所以最具体的异常类型必须放在前面。也可以多种异常共享一个处理器。

try{
}catch(ex1 | ex2 | ex3){
}

3、try-with-resources语句(Java7 新特性)

try(ResourceType res =init1; ResourcesType res = init2;){}

  每一个资源必须属于一个实现了AutoCloseable接口的类。还有Closeable接口,他是AutoCloseable的子接口,抛出IOException 

1     try (Scanner in = new Scanner(Paths.get("/usr/share/dict/words"))){
2       PrintWriter out = new PrintWriter("out.txt");
3         while(in.hasNext()){
4           out.println(in.next().toString());
5         }
6     } catch (IOException e) {
7       // TODO Auto-generated catch block
8       e.printStackTrace();
9     }

如果一个异常抛出导致了close事件触发,close中也产生一个异常,这个异常很可能比原先的异常小一点,这样原先的异常抛出,close异常被捕获,并作为被抑制的异常(suppressed)附加到原先的异常上。可以调用getSuppressed方法检索到第二个异常。

4、finally子句

  当你想要获取和释放锁、增加减少计数器、入栈和出栈、可能也会用到finally。不要在finally中抛异常,try中异常会被finally掩盖。finally中也不能有return,否则会掩盖try中的return。

5、异常链接。

  在异常重抛时,有的异常没有构造函数,这样就会丢掉Cause这时一定记得要调用initCause方法

catch(SQLException ex){
    throw new ServletException("database Error", ex);
}

//获取原始异常
Throwable cause = ex.getCause();

//自己设置Cause
catch(SQLException ex){
    Throwable ex2 =new CruftyOldException("Database Error");
    ex2.initCause(ex);
    throw ex2;
}

  ※如果提供了自己的异常类,则应该加入这两个构造函数

 1 public class MyException extends IOException{
 2   public MyException(Throwable cause){
 3     //this.initCause 这个方法在Throwable类中
 4     initCause(cause);
 5   }
 6   public MyException(String message, Throwable cause){
 7     super(message);
 8     initCause(cause);
 9   }
10 }

6、堆栈追踪

  如果想存储异常的堆栈踪迹,可以放入一个字符串中。

ByteArrayOutputStream out = new ByteArrayOutputStream ();
ex.printStackTrace(out);
String description = out.toString();

如果想要更详细的处理堆栈踪迹,则调用StackTrackElement[] frames = ex.getStackTrack()方法,然后分析StackTraceElement实例。

7、Objects.requireNonNull方法

1 //可以这样赋值
2 this.directions = Objects.requireNonNull(directions, "directions must not be null");
3 //如果空就会出空指针异常

8、断言

  assert condition;

  assert condition : expression;

  assert x>0;如果x<=0就会抛出AssertionError异常。

  assert x>0 : x 如果x<=0就会将x打出来

  运行程序时加上-ea就可以启用断言:java -ea MainClass 用-da禁用断言

  void ClassLoader.setDefaultAssertionStatus(boolean enabled);

  void ClassLoader.setClassAssertionStatus(String className, boolean enabled);

  void ClassLoader.setPackageAssertionStatus(String packageName, boolean enabled);

9、采用Logger

  日志管理系统通过调用Logger.getGlobal()获得默认日志记录器。

  Logger.getGlobal().info("info");

  调用Logger.global.setLevel(Level.OFF)。这样Info方法将不会记录日志。即使日志记录被禁用,消息还是被创建,如果担心创建的代价,可以用lambda表达式代替。

  Logger.getGlobal().info(()->"info");

  一般都不用全局日志记录器,而是用自定义的。

  Logger logger = Logger.getLogger("com.myCompany.myapp");如果关闭com.myCompany.myapp日志记录器,那么他的子日志记录器也被禁用。包和父包

  日志级别:  SEVERE、WARNING、INFO、CONFIG、FINE、FINER、FINEST

  用Level.All来打开所有级别的日志记录,用Level.Off来关闭所有级别的日志记录。默认是记录Info和更高级别的所有日志。

  如果日志级别设置比Info更细粒度级别,则要改变日志处理的配置。

1   public int read(String file, String pattern){
2     int count = 1;
3     Logger logger = Logger.getGlobal();
4     logger.entering(sourceClass, sourceMethod, param1);
5     logger.exiting(sourceClass, sourceMethod, result);
6     return count;
7   }

  这些调用会产生以字符串entry和return开始的Finer级别的日志记录。

  默认的日志配置文件位于jre/lib/logging.properties也可以指定配置文件的位置:

  java -Djava.util.logging.config.file=configFile MainClass

  ※在Main函数中调用System.setProperty("java.util.logging.config.file",configFile)没有效果,因为日志管理器是在VM启动阶段初始化的,这是在Main函数执行之前进行的。

  更多日志的介绍P197-199

 

  

posted on 2016-06-17 11:25  多看多学  阅读(342)  评论(0编辑  收藏  举报

导航