print大法
# print大法
最原始的日志输出方式
# 介绍
在我们编写程序的时候,为了方便观察变量的值,我们可以用 System.out.println()
打印变量。
有时候简单的加个打印语句,断点调试有点麻烦:需要设置断点,然后一步步执行观察;如果有问题,再重新打断点,重新调试……
当然,断点调试也有优点,对于复杂的的情况,能够很好的跟踪各个变量的值和变化情况,有助于理解和跟踪程序(如果全部用print打印出来,需要一大堆代码,并且打印出来一大堆信息,容易眼花缭乱)
这种直接打印到控制台的办法,也叫print大法。目前业内不少人认为printf方法很简单很low;但是只要能快速解决问题,用用也无妨,特别是自己练习一些简单的代码的时候。
# 缺点
接下来讲讲print大法的不足:
不知道输出的语句是在哪个类,哪个线程里出来的
不知道什么时候前后两句输出间隔了多少时间
日志内容混杂,比如正常执行的日志和错误的日志混杂在一起,难以跟踪。
如果想将日志保存到文件?保存到数据库?print不支持,只能自己写个IO程序去存储
需要频繁修改源代码。例如,代码已经编写完成,那么无用的prinf语句怎么办?肯定是删除,不然整个Java代码导出充斥着打印语句,可读性很差;
但如果后面发现又有问题,怎么办?把prinf语句加上去……
改来改去后,非常麻烦。要不改完代码后给print语句加个注释? 但这样可读性还是很差……
需要自己设置打印的格式,例如执行到哪一步了,就输出“目前执行到第x步,变量的值为:”, 或者输出“有异常!请即使处理”
..............................................
# 断言
断言(Assertion)是一种调试程序的方式。在Java中,使用assert
关键字来实现断言。
我们先看一个例子:
public static void main(String[] args) {
double x = Math.abs(-123.45);
assert x >= 0;
System.out.println(x);
}
2
3
4
5
语句assert x >= 0;
即为断言,断言条件x >= 0
预期为true
。如果计算结果为false
,则断言失败,抛出AssertionError
。
使用assert
语句时,还可以添加一个可选的断言消息:
assert x >= 0 : "x must >= 0";
这样,断言失败的时候,AssertionError
会带上消息x must >= 0
,更加便于调试。
Java断言的特点是:断言失败时会抛出AssertionError
,导致程序结束退出。因此,断言不能用于可恢复的程序错误,只应该用于开发和测试阶段。
对于可恢复的程序错误,不应该使用断言。例如:
void sort(int[] arr) {
assert arr != null;
}
2
3
应该抛出异常并在上层捕获:
void sort(int[] arr) {
if (arr == null) {
throw new IllegalArgumentException("array cannot be null");
}
}
2
3
4
5
当我们在程序中使用assert
时,例如,一个简单的断言:
// assert
public class Main {
public static void main(String[] args) {
int x = -1;
assert x > 0;
System.out.println(x);
}
}
2
3
4
5
6
7
8
9
断言x
必须大于0
,实际上x
为-1
,断言肯定失败。执行上述代码,发现程序并未抛出AssertionError
,而是正常打印了x
的值。
这是怎么肥四?为什么assert
语句不起作用?
这是因为JVM默认关闭断言指令,即遇到assert
语句就自动忽略了,不执行。
要执行assert
语句,必须给Java虚拟机传递-enableassertions
(可简写为-ea
)参数启用断言。所以,上述程序必须在命令行下运行才有效果:
$ java -ea Main.java
Exception in thread "main" java.lang.AssertionError
at Main.main(Main.java:5)
2
3
还可以有选择地对特定地类启用断言,命令行参数是:-ea:com.itranswarp.sample.Main
,表示只对com.itranswarp.sample.Main
这个类启用断言。
或者对特定地包启用断言,命令行参数是:-ea:com.itranswarp.sample...
(注意结尾有3个.
),表示对com.itranswarp.sample
这个包启动断言。
实际开发中,很少使用断言。更好的方法是编写单元测试,后续我们会讲解JUnit
的使用。
# 小结
print大法简单,人人都会用;但也有不少缺点,这些缺点决定了print大法不适合用在大型的项目中。
断言是一种调试方式,断言失败会抛出AssertionError
,只能在开发和测试阶段启用断言;对可恢复的错误不能使用断言,而应该抛出异常;断言很少被使用,更好的方法是编写单元测试。
接下来我们将介绍日志框架。