Java断言和日志

一.概述

上一篇讲了Java的异常机制,这个机制会让程序变得更加有健壮性。Java异常处理
这一篇讲Java的断言和用日志框架来查看程序的问题。最后讲一下调试的小技巧。

二.断言

1.基本概念

通俗来讲就是自己断定某个属性是否是我们想要的那个答案。比如希望一个方法调用的参数是一个非负数,可以使用抛异常的方式告诉调用这个参数不能为负数。因为异常存在多了,会使系统的效率降低,所以可以使用断言来它不可能是一个负数。当代码发布时,这些断言将会自动被移走。

/**
 * 断言的使用
 */
public class AssertDemo {
	public static void main(String[] args) {
		int x = 1;
		// 断言x一定是大于0
		assert x > 0;
		double y = Math.sqrt(x);
		// 断言的另一种写法后面跟一个表达式
		// 如果为false 则会抛出一个AssertionError异常。
		// 这种形式表达式的值将被传入AssertionError的构造器,并转换成一个消息字符串,但AssertionError并不会存储字符串的值
		assert x > 0 : Math.sqrt(x);
	}
}
2.启用断言

在默认情况下,断言是被禁用的。可以在运行时输入 java -enableassertions xxx 来启用。输入java -disableassertions xxx关闭。如果系统没有类加载器,需要使用 -enablesystemassrtions 来开启
注意:断言不需要重新编译程序。这个是类加载器的功能。但有些类是又虚拟机加载而不是类加载器。

3.断言完成参数校验

在Java语言中,处理系统错误的3种:

  • 抛出一个异常
  • 日志
  • 使用断言

在什么时候使用断言?

  • 断言失败是致命的,不可恢复的错误。
  • 断言检查只用于开发和测试阶段。

三.日志

1.记录日志的优点

在以前的实例中,通常都是使用System.out.println()方法来查看对象和变量的值。

  • 通过取消日志的级别来打开或关闭所有的日志,不用在删除和添加打印方法来查看日志。
  • 可以在控制台显示,也可以存储到指定的文件查看。
  • 可以采用不同的方式格式化,例如纯文本或者xml。
  • 日志的控制可以交由配置文件来控制。
2.基本日志
3.处理器

默认情况下,日志记录器将记录发送到ConsoleHandler处理器中,并送到System.err的流中,最后将记录发送到父处理器上。
注意:对于一个要被记录的日志,需要高于日志记录器的级别和处理器的级别,别忘了处理器!!
日志记录器是原始记录器的子类,而原始记录器会把所有等于或高于INFO级别的记录发送到控制台中。如果不想两次看到记录,应将useParentHandleers的属性设置为false。

4.过滤器
5.格式化器
import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.logging.*;

/**
 * 日志demo
 * 功能:在页面上生成日志
 * 主要关注日志管理的部分其余暂时不用考虑
 */
public class LogViewDemo {
	public static void main(String[] args) {
		// 判断系统是否修改了日志配置文件
		if (System.getProperty("java.util.logging.config.class") == null
				&& System.getProperty("java.util.logging.config.file") == null
		) {
			try {
				Logger.getLogger("LogViewDemo").setLevel(Level.ALL);
				final int LOG_ROTATION_COUNT = 10;
				// 创建一个处理器 循环序列的文件数量为10
				Handler handler = new FileHandler("%h/loggingImageViewer.log", 0, LOG_ROTATION_COUNT);
				Logger.getLogger("LogViewDemo").addHandler(handler);
			} catch (IOException e) {
				Logger.getLogger("LogViewDemo").log(Level.SEVERE, "Can't create log file handler", e);
			}
		}

		EventQueue.invokeLater(() -> {
					Handler windowHandler = new WindowHandler();
					windowHandler.setLevel(Level.ALL);
					Logger.getLogger("LogViewDemo").addHandler(windowHandler);

					JFrame frame = new ImageViewerFrame();
					frame.setTitle("loggingImageViewer");
					frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

					Logger.getLogger("LogViewDemo").fine("Showing frame");
					frame.setVisible(true);
				}
		);
	}
}


class ImageViewerFrame extends JFrame {

	private static final int DEFAULT_WIDTH = 300;
	private static final int DEFAULT_HEIGHT = 400;

	private JLabel label;
	/**
	 * 设置日志记录器的名称
	 */
	private static Logger logger = Logger.getLogger("LogViewDemo");

	public ImageViewerFrame() {
		// 跟踪方法进入时候的日志
		logger.entering("ImageViewerFrame", "<init>");
		setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);

		JMenuBar menuBar = new JMenuBar();
		setJMenuBar(menuBar);

		JMenu menu = new JMenu("File");
		menuBar.add(menu);

		JMenuItem item = new JMenuItem("Open");
		menu.add(item);

		item.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				logger.fine("Exiting");
				System.exit(0);
			}
		});

		label = new JLabel();
		add(label);
		logger.exiting("ImageViewerFrame", "<init>");
	}

	private class FileOpenListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			// 跟踪方法进入时候的日志
			logger.entering("ImageViewFrame.FileOpenListener", "actionPerformed", e);

			JFileChooser chooser = new JFileChooser();
			chooser.setCurrentDirectory(new File("."));

			chooser.setFileFilter(new FileFilter() {
				@Override
				public boolean accept(File f) {
					return f.getName().toLowerCase().endsWith(".gif") || f.isDirectory();
				}

				@Override
				public String getDescription() {
					return "GIF Images";
				}
			});

			int r = chooser.showOpenDialog(ImageViewerFrame.this);

			if (r == JFileChooser.APPROVE_OPTION) {
				String name = chooser.getSelectedFile().getPath();
				logger.log(Level.FINE, "Reading file {0}", name);
			} else {
				logger.fine("File open dialog canceled");
				// 跟踪退出方法退出时的日志
				logger.exiting("ImageViewerFrame.FileOpenListener", "actionPerformed");

			}
		}
	}

}

/**
 * 创建日志处理器 在窗口中显示日志记录
 */
class WindowHandler extends StreamHandler {
	private JFrame frame;

	public WindowHandler() {
		frame = new JFrame();
		final JTextArea output = new JTextArea();
		output.setEditable(false);
		frame.setSize(200, 200);
		frame.add(new JScrollPane(output));
		frame.setFocusableWindowState(false);
		frame.setVisible(true);
		setOutputStream(new OutputStream() {
			@Override
			public void write(int b) throws IOException {

			}

			// 每次写入到缓存区,待缓存区满了之后才会显示
			@Override
			public void write(byte[] b, int off, int len) {
				output.append(new String(b, off, len));
			}
		});
	}

	/**
	 * 获取每次记录之后就刷新缓存区
	 *
	 * @param record
	 */
	@Override
	public void publish(LogRecord record) {
		if (!frame.isVisible()) {
			return;
		}
		super.publish(record);
		flush();
	}
}

四.调试技巧

1.在方法的入口处打印出方法的入口参数,方法的结束打印出结果和入口参数日志。
2.利用printStackTrace()方法打印出堆栈轨迹

五.总结

下一篇学习泛型设计。这个方法可以确保类型的正确性。
有些可能我理解的不够深刻,大家如果觉得我说的不够详细可以参考我的推荐书,详细的看一下。欢迎大家评论。第一时间我会回复大家。谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值