本章内容:
* 处理错误
* 捕获异常
* 使用异常机制的技巧
* 使用断言
* 日志
* 调试技巧
* GUI程序排错技巧
* 使用调试器
try(Resource res = ...){work with res}
,try块退出时,会自动调用res.close()。assert 条件;
和assert 条件:表达式;
。这两种形式都会对条件进行检测,如果结果为false,则抛出一个AssertionError异常。在第二种形式中,表达式将被传入AssertionError的构造器,并转换成一个消息字符串。java -enableassertions MyApp
。需要注意的是,在启用或禁用断言时不必重新编译程序。启用或禁用断言时类加载器(class loader)的功能。当断言被禁用时,类加载器将跳过断言的代码,因此,不会降低程序运行的速度。e/lib/logging.properties
。要想使用另一个配置文件,就要将java.util.logging.config.file特性设置为配置文件的存储位置,并用下列命令启动应用程序:java -Djava.utll.logging.config.file=configFile MainClass
。.level=INFO
。可以通过添加以下内容来指定自己的日志记录级别com.mycompany.myapp.level=FINE
。也就是说,在日志记录名后面添加后缀.level。要想在控制台上看到FINE级别的消息,就需要进行下列设置java.util.logging.ConsoleHandler.level=FINE
。1.在默认情况下,日志记录器将记录发送到ConsoleHandler中,并由它输出到System,err流中。特别是,日志记录器还会将记录发送到父处理器中,而最终的处理器(命名为“”)有一个ConsoleHandler。
java.util.logging.ConsoleHandler.level=INFO
。配置属性 | 描述 | 默认 |
---|---|---|
java.util.logging.FileHandler.level | 处理器级别 | Level.ALL |
java.util.FileHandler.append | 控制处理器应该追加到一个已经存在的文件尾部;还是应该为每个运行的程序打开一个新文件 | false |
java.util.logging.FileHandler.limit | 在打开另一个文件之前允许写入一个文件的近似最大字节数(0表示无限制) | 在FileHandler类中为0(表示无限制);在默认的日志管理器配置文件中为50000 |
java.util.logging.FileHandler.pattern | 日志文件名的模式。 | %h/java%u.log |
java.util.logging.FileHandler.count | 在循环序列中的日志记录数量 | 1(不循环) |
java.util.logging.FileHandler.filter | 使用的过滤器类 | 没有使用过滤器 |
java.util.logging.FileHandler.encoding | 使用的字符编码 | 平台的编码 |
java.util.logging.FileHandler.formatter | 记录格式器 | java.util.logging.XMLFormatter |
变量 | 描述 |
---|---|
%h | 系统属性user.home的值 |
%t | 系统临时目录 |
%u | 用于解决冲突的唯一性编号 |
%g | 为循环日志记录生成的数值。(当使用循环功能且模式不包括%g时,使用后缀%g) |
%% | %字符 |
boolean isLoggable(LogRecord record)
在这个方法中,可以利用自己喜欢的标准,对日志记录进行分析,返回true表示这些记录应该包含在日志中。String format(LogRecord record)
。String formatMessage(LogRecord record)
,这个方法对记录中的部分信息进行格式化、参数替换和本地化应用操作。String getHead(Handler h)
和String getTail(Handler h)
。最后,调用setFormatter方法将格式化器安装到处理器中。一些最常用的操作:
(1)为一个简单的应用程序,选择一个日志记录器,并把日志记录器命名与应用程序包一样的名字,例如,com.mycompany.myprog,这个一种好的编程习惯。另外,可以通过调用下列方法得到日志记录器。Logger logger = Logger.getLogger("com.mycompany.myprog");
。为了方便起见,可能希望利用一些日志操作将下面的静态域添加到类中:private static final Logger logger = Logger.getLogger("com.mycompany.myprog");
。
(2)默认的日志配置将级别等于或高于INFO级别的所有消息记录到控制台。用户可以覆盖默认的配置文件。但是正如前面所述,改变配置需要做相当多的工作。因此,最好在应用程序中安装一个更加适宜的默认配置。
下面代码确保将所有的消息记录到应用程序特定的文件中。可以将这段代码防止在应用程序的main方法中。
if (System.getProperty("java.util.logging.config.class")==null
&& System.getProperty("java.util.logging.config.file")==null)
{
try{
Logger.getLogger("").setLevel(Level.ALL);
final int LOG_ROTATION_COUNT = 10;
Handler handler = new FileHandler("%h/myapp.log",0,LOG_ROTATION_COUNT);
}
catch(IOException e)
{
logger.log(Level.SERVERE,"Can‘t create log file handler",e);
}
}
(3)现在,可以记录自己想要的内容了。但需要牢记:所有级别为INFO、WARNIN和SEVERE的消息都将显示到控制台上。因此,最好只将对程序用户有意义的消息设置为这几个级别。将程序员想要的日志记录,设定为FINE是一个很好的选择。
当调用System.out.println时,实际上生成了下面的日志消息:logger.fine("File open dialog canceled");
记录那些不可预料的异常也是一个不错的想法。例如:
try
{
...
}
catch(SomeException e)
{
logger.log(Level.FINE,"explanation",e);
}
java.util.logging.Logger 1.4
调试技巧:
(1)可以用下面的方法打印或记录任意变量的值:System.out.println("x="+x);
或Logger.getGlobar().info("x="+x);
。
(2)一个不太为人所知但却非常有效的技巧是在每一个类中放置一个main方法,这样就可以对每一个类进行单元测试。
public class MyClass
{
methods and fields
...
public static void main(String[] args)
{
test code
}
}
利用这种技巧,只需要创建少量的对象,调用所有的方法,并检测每个方法是否能够正常地运行就可以了。另外,可以为每个类保留一个main方法,然后分别为每个文件调用Java虚拟机进行运行测试。在运行applet应用程序的时候,这些main方法不会被调用,而在运行应用程序的时候,Java虚拟机只调用启动类的main方法。
(3)JUnit是一个非常常见的单元测试框架,利用它可以很容易地组织几套测试用例。只要修改类,就需要运行测试。在发现bug时,需要补充一些其他的测试用例。
(4)日志代理(logging proxy)是一个子类的对象,它可以窃取方法调用,并进行日志记录,然后调用超类中的方法。
(5)利用Throwable类提供的printStackTrace方法,可以从任何一个异常对象中获得堆栈情况。
不一定要通过捕获异常来生成堆栈跟踪。只要在代码的任何位置插入下面这条语句就可以获得堆栈跟踪:Thread.dumptack()
。
(6)一般来说,堆栈跟踪显示在System.err上。也可以利用printStackTrace(PrintWriter s)方法将它发送到一个文件中。另外,如果想记录或显示堆栈跟踪,就可以采用下面的方式,将它捕获到一个字符串中:
ByteArrayOutputStream out = new ByteArrayOutputStream();
new Throwable().printStackTrace(out);
String description = out.toString();
(7)通常,将一个程序中的错误信息保存在一个文件中时非常有用的。然而,错误信息被发送到System.err中,而不是System.out中。因此,不能够通过运行下面的语句获取它们:java MyProgram 2> errors.txt
,而是采用下面的方式捕获错误流:java MyProgram 2> errors.txt
,这条命令将工作在Windows shell中。
(8)让非捕获异常的堆栈跟踪出现在System.err中并不是一个很理想的方法。如果在客户端偶尔看到这些信息,则会感到迷惑,并且在需要的时候也无法实现诊断目的。比较好的方式是将这些内容记录到一个文件中。可以调用静态的Thread.setDefaultUncaughtExceptionHandler方法改变非捕获异常的处理器:
Thread.setDefaultUncaughtExceptionHandler(
new Thread.UncaughtExceptionHandler()
{
public void uncaughtException(Thread t,Throwable t)
{
save information in log file
}
}
)
(9)要想观察类的加载过程,可以用-verbose标志启动Java虚拟机。
(10)Xlint选项告诉编辑器对一些普通容易出现的代码进行检查。例如,如果使用下面这条命令编译:javac -Xlint:fallthrough
,当switch语句中缺少break语句时,编译器就会给出报告。
下面列出了可以使用的选项:
-Xlint或-Xlint:all 执行所有的检查
-Xlint:deprecation 与-deprecation一样,检查废弃的方法
-Xlint:fallthrough 检查switch语句中是否缺少break语句
-Xlint:finally 警告finally子句不能正常地执行
-Xlint:none 不执行任何检查
-Xlint:path 检查类路径和源代码路径上的所有目录是否存在
-Xlint:serial 警告没有serialVersionUID的串行化类
-Xlint:unchecked 对通用类型与原始类型之间的危险转换给予警告
(11)Java虚拟机增加了对Java应用程序进行监控(monitoring)和管理(management)的支持。它允许利用虚拟机中的代理装置跟踪内存消耗、线程使用、类加载等情况。这个功能对于像应用程序服务器这样大型的、长时间运行的Java程序来说特别重要。
(12)可以使用jmap实用工具获得一个堆的转储,其中显示了堆中的每个对象。使用命令如下:
jmap -dump:format=b,file=dumpFileName processID
jhat dumpFileName
然后,通过浏览器进入localhost:7000,将会运行一个网络应用程序,借此探查转储对象时堆的内容。
(13)如果使用-Xprof标志运行Java虚拟机,就会运行一个基本的剖析器来跟踪那些代码中经常被调用的方法。剖析信息将发送给System.out。输出结果中还会显示哪些方法是由即时编译器编译的。
编译器的-X选项并没有正式支持,而且在有些JDK版本中并不存在这个选项。可以运行命令java -X得到所有非标准选项的列表。
RepaintManager.currentManager(getRootPane()).setDoubleBufferingEnabled(false);
((JComponent)getContentPane()).setDebugGraphicsOptions(DebugFraphics.FLASH_OPTION);
主需要将这几行代码放在框架构造函数的最后。程序运行时,就会看到内容窗格将缓慢地填充。或者,如果要完成更多本地化调试,只需要对单个组件调用setDebugGraphicsOptions。要控制闪烁,可以设置持续时间、次数和闪烁颜色。Java核心技术卷一基础知识-第11章-异常、断言、日志和调试-读书笔记
原文:https://www.cnblogs.com/zhangmiao14/p/9746294.html