前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java基础系列(三十二):断言 + 日志入门

Java基础系列(三十二):断言 + 日志入门

作者头像
山禾说
发布2019-01-21 10:12:49
1.2K0
发布2019-01-21 10:12:49
举报
文章被收录于专栏:Vi的技术博客Vi的技术博客

断言

在Java语言中,给出了3种处理系统错误的机制:

  1. 抛出一个异常
  2. 日志
  3. 使用断言

那我们应该在什么情况下去使用断言呢?

  1. 断言失败是致命的,不可恢复的错误
  2. 断言失败只用于开发测试阶段。

不应该使用断言向程序的其他部分通告发生了可恢复性的错误,或者,不应该作为程序向用户通告问题的手段,断言只应该用于在测试阶段确定程序内部的错误信息。

在一个具有自我保护能力的程序中,断言很常用,假如确信某个属性符合要求,并且代码的执行非常的依赖这个属性,比如:

代码语言:javascript
复制
double a = Math.sqrt(x);

我们在这里确信x必须是一个正值,因为它是另一个计算的得出的非负结果,或者是某一个方法的参数,而这个方法要求它的调用者只能提供一个正整数。但是为了以防万一,我们还是会对这个参数进行检查:

代码语言:javascript
复制
if(x < 0) {
    throw new IllegalArgumentException("x < 0")
;}

但是,有一个问题就是,这段代码会一直保留在程序中,即使测试完毕也不会自动的进行删除,如果程序中含有大量的这样的检查,会严重的影响程序的运行速度。

而断言机制允许在测试期间向代码中插入一些检查语句。当代吗发布的时候,这些插入的检测语句将会自动地移走。

在Java中,断言有两种语法形式:

代码语言:javascript
复制
assert 条件;
assert 条件:表达式;

这两种形式都会对条件进行检测,如果结果为false,就会抛出一个AssertionError异常。在第二种形式中,表达式将会传入AssertionError的构造器,并转换成一个消息字符串。

在上述的程序中,如果我们想使用断言:

代码语言:javascript
复制
assert x >= 0;
//或者将x的实际值传给AssertionError对象
assert x >= : x;

但是在默认情况下,断言是被禁用的,我们可以通过在运行程序的时候输入参数来选择启用:

代码语言:javascript
复制
java -ea MyApp
//or
java -enableassertions MyApp

启动和禁用断言的时候不用重新编译程序,它是类加载器的功能,当断言被禁用的时候,类加载器将会跳过断言代码,所以,不会降低程序的运行速度。

同样的,我们也可以在某个类或整个包中使用断言,比如:

代码语言:javascript
复制
java - ea:MyClass -ea:com.viyoung... MyApp

这个命令将会开启MyClass类以及在com.viyoung包和它的子包中的所有类的断言。 选项 -ea 将会开启默认包中所有类的断言。 也可以使用选项 -disableassertions 或 -da 禁用某个特定类或包的断言:

代码语言:javascript
复制
java -ea: ... -da:MyClass MyApp

有些类不是由类加载器加载,而是直接由虚拟机加载。可以使用这些开关有选择的启用或禁用那些类的断言。

然而,启用和禁用所有断言的 -ea 和 -da 开关不能应用到那些没有类加载器的“系统类”上,对于这些系统类来说,需要使用 -enablesystemassertions/-esa 开关启用断言。

断言和日志的区别在于,断言是一种测试和调试阶段使用的战术性工具;而日志记录是一种在程序的整个生命周期都可以使用的策略性工具

记录日志

说起日志,大家可能会有点陌生,尤其是刚刚接触Java不久的初级程序员,我们在学习初期进行调试程序的时候回插入一些System.out.println方法来帮助我们对程序的运行状况进行一个把控和分析,但是如果说,我们解决了这个问题,就需要把这些语句从我们的代码中及时的删除,当遇到其他问题的时候,则需要再次添加,然后解决后再删除,Java中内置了一个包叫做:java.util.logging包中,在这个包中提供了一系列的API来解决我们的痛点,这些API的优点有许多:

  1. 可以很容易地取消全部日志记录,或者仅仅取消某个级别的日志,而且打开和关闭这个操作也是很容易的。
  2. 可以很简单地禁止日志记录的输出,因此,将这些日志代码留在程序的开销很小。
  3. 日志记录可以被定向到不同的处理器,用于在控制台中显示,用于存储在文件中等。
  4. 日志记录器和处理器都可以对记录进行过滤。过滤器可以根据过滤实现器制定的标准丢弃那些无用的记录项。
  5. 日志记录可以采用不同的方式格式化,例如,纯文本或XML。
  6. 应用程序可以使用多个日志记录器,它们使用类似包名的这种具有层次结构的名字,例如,com.viyoung.myapp。
  7. 在默认情况下,日志系统的配置由配置文件控制。如果需要的话,应用程序可以替换这个配置。

基础日志

如果只是想生成一个简单的日志记录,可以使用全局日志记录器(global logger)并调用其info方法:

代码语言:javascript
复制
Logger.getGloabal().info("This is a Logger Info");

他会在控制台上打印出:

代码语言:javascript
复制
INFO:This is a Logger Info

如果在适当的地方调用

代码语言:javascript
复制
Logger.getGlobal().setLevel(Level.OFF)

会取消所有的日志。

高级日志

上面的日志在我们日常的开发中是不常见的,在一个专业的应用程序中,不要讲所有的日志都记录到一个全局日志记录器中,而是可以自定义日志记录器。

可以调用Logger类的getLogger()方法获取记录器:

代码语言:javascript
复制
private static final Logger myLogger = Logger.getLogger("com.viyoung.myapp");

未被任何变量引用的日志记录器都可能会被垃圾回收,为了防止这种情况的发生,所以要用一个静态变量存储日志记录器的一个引用。

与包名类似,日志记录器名也具有层次结构,而且与包名相比,日志记录器的层次结构更强,如果你对某个包设置了日志级别,那么它的子记录器会去继承这个级别。

通常来说,存在以下7个日志记录器级别:

  1. SEVERE
  2. WARINING
  3. INFO
  4. CONFIG
  5. FINE
  6. FINER
  7. FINEST

通常来说,只会记录前三个级别,但是也可以设置其他的级别。比如:

代码语言:javascript
复制
logger.setLevel(Level.FINE);

当然,我们还可以使用Level.ALL开启所有级别的记录,或者使用Level.OFF关闭所有级别的记录。

对于所有级别有下面几种记录方法:

代码语言:javascript
复制
logger.warning(message);logger.fine(message);

同时,还可以使用log方法指定级别,例如:

代码语言:javascript
复制
logger.log(Level.FINE, message);

默认的日志配置记录了INFO或更高级别的所有记录,因此,应该使用CONFIG、FINE、FINER和FINESET级别来记录那些有助于诊断,但对于程序员又没有太大意义的调试信息。

默认的日志记录将显示包含日志调用的类名和方法名,如同堆栈所显示的那样,但是如果虚拟机对执行过程进行了优化,就会导致获取不到准确的调用信息,这时我们可以使用logp方法获得调用类和方法的确切位置:

代码语言:javascript
复制
void logp(Level l, String className, String MethodName, String message);

以及有一些用来追踪执行流的方法:

代码语言:javascript
复制
// 记录一个方法条目void entering(String className, String methodName);//记录一个方法条目,带有一个参数。void entering(String sourceClass, String sourceMethod, Object param1) // 记录一个方法条目,带有一组参数。void entering(String sourceClass, String sourceMethod, Object[] params) //记录一个方法返回。void exiting(String sourceClass, String sourceMethod) // 记录一个方法返回,带有结果对象。         void exiting(String sourceClass, String sourceMethod, Object result)     

记录日志的常见用途是记录那些不可预测的异常,可以使用下面的两个方法提供日志记录中包含的异常描述内容:

代码语言:javascript
复制
//正抛出异常的记录。
 void throwing(String sourceClass, String sourceMethod, Throwable thrown) //记录带有相关的可抛出信息的消息。void log(Level level, String msg, Throwable thrown)         

下节预告

Java自带日志框架的深入了解和应用~

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-09-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Vi的技术博客 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档