Java初学之中的异常处理

 

什么是异常

异常,顾名思义——不同寻常。

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

异常的后果

我们看如下代码

public class Test {
	public static void main(String[] args) {
        System.out.println(10);
        System.out.println(1/0);
        System.out.println(12);
    }
}

最后控制台上如下所示

显然,只输出了10,第四行代码因为数学上的错误,即除数为零,导致程序运行出错,而第五行的12则完全没有执行。

由此可见,如果程序出现异常,则同级代码不再运行。

异常的分类

Error错误说明JVM错误,我们编程的时候暂时无需考虑。

Theowable中有两个常用方法所有的Exception类之中都有

public String getMessage():获取异常信息;

public void printStackTrace():输出异常堆栈中的异常信息

Exception类的构造方法

public Exception():无参构造方法;

public Exception(String message):可以指定详细异常信息的有参构造方法;

检查时异常和运行时异常

Exception:异常可分为运行时异常(RuntimeException)和检查时异常(CheckedException)两种:

System.out.println(1/0);//运行时异常:可以不显式对异常的处理,javac依然可以编译程序

RuntimeException:运行时异常,即程序运行时抛出的异常。这种异常在写代码时不进行处理,Java源文件也能编译通过。 RuntimeException异常类及其下面的子类均为运行时异常。 

Class.forName("某个无法找到的类名");//检查时异常:必须显式对异常的处理,不然javac不会对程序进行编译

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

可以类比多态之中的编译时类型和运行时类型。

 

捕获异常的结构

首先,最常见的是try catch语法结构。

捕获异常语法结构:

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

try…catch…finally异常处理结构中,try语句块是必须的,  catchfinally语句块至少出现一个。

注意如果try语句块包含的是检查时异常,则在没有通过throws抛出该异常类的情况下,try必须和catch一起使用,当该行代码去掉或注销掉时,catch相应的异常语句块必须去掉,如下代码:

由于上图被圈出代码抛出检查时异常,所以该行代码去掉或注销掉时,catch相应的异常语句块必须去掉。

try语句块中的代码可能会引发多种类型的异常,当引发异常时,会按顺序查看每个 catch 语句,并执行第一个与异常类型匹配的catch语句,其后 catch 语句被忽略。

在捕获异常的时候,应按照“从小到大”的顺序捕获异常,即先子类后父类。

先子类异常,后父类异常:ArrayIndexOutOfBoundsException异常类是RuntimeException的子类,而RuntimeException异常类是Exception的子类,他们的先后顺序不能颠倒。

Java中对异常的处理有如下两种方式:

通过trycatchfinally关键字捕获异常;

通过throwthrows关键字抛出异常;

finally关键字

Java异常在try/catch块后加入finally块,可以确保无论是否发生异常 finally块中的代码总能被执行。

其中getMessage()获取异常信息的方法来自最原始的父类Throwable。

Java中对异常的处理有如下两种方式:

通过trycatchfinally关键字捕获异常;

通过throwthrows关键字抛出异常;

普通的异常处理有什么弊端

显然对于一个极大规模循环的异常抛出流程(数十万次),已经远远超出控制台所所拥有的缓存空间,而超出缓存区域则会导致异常数据数据丢失,因此,我们选择使用log4j来弥补。

主要流程如此——

将异常信息打印控制台——>存入一段缓存,缓存有大小——>当缓存满了,但是异常信息源源不断,则会将最先进入缓存的异常信息移除——>意味着无法全面的发现程序运行期间出现的问题——>为了全面收集系统运行期间出现的所有异常信息,log4j诞生了——>将都有异常信息输出到一个文件中——因为文件在硬盘上——>可以认为无限大

配置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
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常用日志级别从高到低依次为:ERRORWARNINFODEBUG,由于上例所设置的Log4j日志级别为DEBUG,所以ERRORWARNINFO 级别的日志信息也会显示出来。


间歇性产生新日志文件

上例配置文件是将所有的日志信息都收集到了一个文件中,那么随着时间的推移,该文件会越来越大,内容也会越来越多,这不利于后期对日志文件进行分析,为了解决该问题可以这样配置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中不用处理的文字要放到单引号(')中,如上面的(.)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值