详述java异常和Log4j

什么是异常:

Java语言将程序运行过程中所发生的不正常严重错误称为异常,对异常的处理称为异常处理。

异常的后果:

它会中断正在运行的程序。
在这里插入图片描述

异常的分类:

在这里插入图片描述
注意:

1、这个连接关系是父类与子类的关系:即Throwable是Exception和Error的父类,同理,Exception也是RuntimeException的父类等等。

2、Throwable有两个常用方法:
① public String getMessage():获取异常信息。
② public void printStackTrace():输出异常堆栈中的异常信息。
因为是父类子类关系,所以Throwable后面的异常都可以继承这两个方法。

3、Throwable有两个直接子类,Error类和Exception类。
① Error : 指合理的应用程序在执行过程中发生的严重问题。当程序发生这种严重错误时,通常的做法是通知用户并中止程序的执行。
② Exception:异常可分为运行时异常(RuntimeException)和检查时异常(CheckedException)两种:
(1)RuntimeException:运行时异常,即程序运行时抛出的异常。这种异常在写代码时不进行处理,Java源文件也能编译通过。 RuntimeException异常类及其下面的子类均为运行时异常。

public class Test {
	public static void main(String[] args) {
		System.out.println(6);
		System.out.println(1/0); //如果程序出现异常,则同级代码不再运行。
		System.out.println(8);
	}
}

该代码可以编译运行,即便不对该代码进行处理,java源文件也能通过javac命令将该源文件编译成class文件。但是如果程序出现异常,则同级代码不再运行,所以输出结果为:
6
Exception in thread “main” java.lang.ArithmeticException: / by zero
at test.Test.main(Test.java:5)

此时,ArithmeticException是发生异常的名称,这个是算术异常。

(2)CheckedException:检查时异常,又称为非运行时异常,这样的异常必须在编程时进行处理,否则就会编译不通过。Exception异常类及其子类(除去RuntimeException异常类及其子类)都是检查时异常。

public class Test {
	public static void main(String[] args) {
		System.out.println(1/0);
		Class.forName(""); //此行会报错。必须显式对异常的处理,不然javac不会对程序进行编译。
	}
}

上面即为检查时异常,必须要在编程的时候更改,不然不能运行,改成:

public class Test {
	public static void main(String[] args) {
		System.out.println(1/0);
		try {
			Class.forName("");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
}

此时才可以运行,如果这时候有符合检查时异常的错误代码,Class.forName("");处会报错。
或者改成:

public class Test {
	public static void main(String[] args) throws ClassNotFoundException {
		System.out.println(1/0);
		Class.forName("");
	}
}

将错误代码传给ClassNotFoundException,才得以编译运行。

异常处理:

Java中对异常的处理有如下两种方式:
1、通过trycatchfinally关键字捕获异常;
2、通过throwthrows关键字抛出异常;

常见异常:

在这里插入图片描述

捕获异常:

1、捕获异常语法结构:

try{
      //可能抛出异常的语句块
}catch(SomeException1 e){ // SomeException1特指某些异常 
     //当捕获到SomeException1类型的异常时执行的语句块
} catch( SomeException2 e){
     //当捕获到SomeException2类型的异常时执行的语句块
}finally{
     //无论是否发生异常都会执行的代码
}

例如:

public class Test {
	public static void main(String[] args){
		try {
			System.out.println(6);
			System.out.println(1/0);
			System.out.println(8); //因为上一行代码出现异常,所以这行没有执行,输出没有8。
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			System.out.println(10); //无论是否发生异常该代码都会执行,一般用于释放资源(此处只是举例子)。
		}
		
	}
}

输出:
java.lang.ArithmeticException: / by zero
at test.Test.main(Test.java:7)
6
10

注意:
① try…catch…finally异常处理结构中,try语句块是必须的, catch和finally语句块至少出现一个,即try不能单独使用。
② 如果try语句块包含的是检查时异常,则在没有通过throws抛出该异常类的情况下,try必须和catch一起使用,当该行代码去掉或注销掉时,catch相应的异常语句块必须去掉,如下代码:

public class Test {	
	public static void main(String[] args){
		try {
			Class.forName("java.lang.Object"); //由于该行代码抛出检查时异常,所以该行代码去掉或注销掉时,catch相应的异常语句块必须去掉。
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
}

2、多重catch:try语句块中的代码可能会引发多种类型的异常,当引发异常时,会按顺序查看每个 catch 语句,并执行第一个与异常类型匹配的catch语句,其后 catch 语句被忽略。所以,在捕获异常的时候,应按照“从小到大”的顺序捕获异常,即先子类后父类。如果先父类后子类,会报错。
在这里插入图片描述

Log4j的作用和用法:

1、为什么要用Log4j:因为将异常穿到控制台的所占内存是有限的,当异常很多的时候,前面的异常会消失,这样我们就丢失了异常的数据,所以Log4j的作用就出来了。

2、Log4j的作用:Log4j是Apache的一个开源项目,通过使用Log4j,可以控制日志信息格式及其输送目的地(控制台、文件、数据库等),方便后期查找系统运行期间出现的问题,进而便于维护系统。这样我们就可以把异常传到一个文档里面,而我们硬盘的内存是很大的,相对于传到控制台的内存可以看成是无限大。

3、怎么配置Log4j:
① 第一步:导入log4j-1.2.15.jar依赖包。
在这里插入图片描述

② 第二步:在src根目录下创建名为log4j.properties的文件,文件内容如下:

# DEBUG设置输出日志级别,由于为DEBUG,所以ERROR、WARN和INFO 级别日志信息也会显示出来
log4j.rootLogger=DEBUG,Console,RollingFile

#将日志信息输出到控制台
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern= [%-5p]-[%d{yyyy-MM-dd HH:mm:ss}] -%l -%m%n
#将日志信息输出到操作系统D盘根目录下的log.log文件中
log4j.appender.RollingFile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.RollingFile.File=D://log.log           // D://log.log为文件的存放地址。
log4j.appender.RollingFile.layout=org.apache.log4j.PatternLayout
log4j.appender.RollingFile.layout.ConversionPattern=%d [%t] %-5p %-40.40c %X{traceId}-%m%n

在这里插入图片描述

③第三步:src目录创建Test类,代码如下:

import org.apache.log4j.Logger;
 
public class Test {
 
	private static final Logger logger = Logger.getLogger(Test.class);
 
	public static void main(String[] args) {
		try {
			Class.forName("ErrorClassName");
		} catch (ClassNotFoundException e) {
			logger.debug(e.getMessage(),e);//详细日报信息
			logger.info(e.getMessage(),e);//详细日报信息
			logger.warn(e.getMessage());//简单日报信息
			logger.error(e.getMessage());//简单日报信息
		}
          }
}

④ 经过上述三步,最终Java工程结构如下:

在这里插入图片描述
运行Test类方法,打开D盘根目录中log.log文件可以看到相应的日志信息,此时的日志信息都会显示出来,Log4j常用日志级别从高到低依次为:ERROR、WARN、INFO和DEBUG,由于上例所设置的Log4j日志级别为DEBUG,所以ERROR、WARN和INFO 级别的日志信息也会显示出来。

例如我使用的形式如下:

import org.apache.log4j.Logger;

public class HelloWorld {
	static Logger logger = Logger.getLogger(HelloWorld.class);

	public static void main(String[] args) {

		while (true) {

			try {
				System.out.println(1 / 0);
			} catch (ArithmeticException e) {
				logger.debug(e.getMessage(), e);
			}
		}
	}
}

执行一段时间后停止,在D:有文件:
在这里插入图片描述
直接用软件打开可以看到错误代码信息。

间歇性产生新日志文件:

上例配置文件是将所有的日志信息都收集到了一个文件中,那么随着时间的推移,该文件会越来越大,内容也会越来越多,这不利于后期对日志文件进行分析,为了解决该问题可以这样配置log4j.properties文件:

# DEBUG设置输出日志级别,由于为DEBUG,所以ERROR、WARN和INFO 级别日志信息也会显示出来
log4j.rootLogger=DEBUG,RollingFile
#每天产生一个日志文件(RollingFile)  
log4j.appender.RollingFile=org.apache.log4j.DailyRollingFileAppender
#当天的日志文件全路径
log4j.appender.RollingFile.File=d:/logs/sirius.log
#服务器启动日志是追加,false:服务器启动后会生成日志文件把老的覆盖掉
log4j.appender.RollingFile.Append=true
#日志文件格式  
log4j.appender.RollingFile.layout=org.apache.log4j.PatternLayout  
log4j.appender.RollingFile.layout.ConversionPattern=%d [%t] %-5p %-40.40c %X{traceId}-%m%n
log4j.appender.RollingFile.Threshold=DEBUG
#设置每天生成一个文件名后添加的名称,备份名称:sirius.log.年月日时分.log
log4j.appender.RollingFile.DatePattern='.'yyyy-MM-dd-HH-mm'.log'

此时:
DatePattern选项的有效值为:
'.'yyyy-MM,对应monthly(每月)
'.'yyyy-ww,对应weekly(每周)
'.'yyyy-MM-dd,对应daily(每天)
'.'yyyy-MM-dd-a,对应half-daily(每半天)
'.'yyyy-MM-dd-HH,对应hourly(每小时)
'.‘yyyy-MM-dd-HH-mm,对应minutely(每分钟)
DatePattern中不用处理的文字要放到单引号(’)中,如上面的(.)。

自定义properties的文件:

Log4j默认使用src根目录中名为log4j.properties的文件,实际开发中有可能需要使用特定目录中的特定名字的properties文件,如下工程:

在这里插入图片描述
其中,config包内log.properties文件保存了Log4j相关配置信息,那么此时如何使用该文件呢,如下代码:

import java.net.URL;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

public class Test {

	static {
		// 获取src目录config包中log.properties文件对应的URL对象
		URL url = Test.class.getResource("/config/log.properties");
		PropertyConfigurator.configure(url);
	}

	static Logger logger = Logger.getLogger(Test.class);

	public static void main(String[] args) {
		try {
			System.out.println(1 / 0);
		} catch (Exception e) {
			logger.debug(e.getMessage(), e);
		}
	}
}

开发中不止一个Java类需要将某些日志信息写入指定位置,此时每个类中都会重复性地写入如下代码:

static {
	// 获取src目录config包中log.properties文件对应的URL对象
	URL url = Test.class.getResource("/config/log.properties");
	PropertyConfigurator.configure(url);
}

为了尽可能减少重用代码,可以将该部分代码写入到一个Java类中(如BaseLog4j.java),需要输出日志的类只需继承该类即可,如下代码:

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值