异常
什么是异常?
异常:即不同寻常 。Java语言将程序运行过程中所发生的不正常严重错误称为异常,对异常的处理称为异常处理。
异常后果?
- 如果程序出现异常,则同级代码不再运行
public class Test {
public static void main(String[] args) {
System.out.println(121);
System.out.println(1/0);
System.out.println(121);
}
}
尽管两者都是有错误的,但是因为他们是同级,所以当程序进行到第一行有错误的代码时就返回程序出错,不在继续向下进行了。
public class Test {
public static void main(String[] args) {
String name =null;
System.out.println(name.length());
System.out.println(1/0);
}
}
- 并且它会中断正在运行的程序,正因为如此异常处理是程序设计中一个非常重要的方面,也是程序设计的一大难点。
异常的分类
如下图:
exception错误由编译者解决,而error错误,编译者则无需过问,那是JVM的事情。
检查时异常
必须显式对异常的处理,不然javac不会对程序进行编译
即,你在eclipse里面写代码时,如果写错了,程序会在代码下面显示出红色的波浪线,在这一行有一个红色的叉,提醒你这一行代码有问题。
运行时异常
可以不显式对异常的处理,javac依然可以编译程序
即:你的代码本身看上去没有任何的问题,但是事实上不符合数学等规则。
例如
System.out.println(1/0);
异常处理方式 try-catch-finally
try-catch:
将有错的代码包裹,并且给出几个关于什么错误的选项选择。
语法结构:
try{
//可能抛出异常的语句块
}catch(SomeException1 e){
// SomeException1特指某些异常
//当捕获到SomeException1类型的异常时执行的语句块
} catch( SomeException2 e){
//当捕获到SomeException2类型的异常时执行的语句块
}finally{
//无论是否发生异常都会执行的代码
}
例如:
public class Test {
public static void main(String[] args) {
System.out.println(121);
try {
System.out.println(1/0);
} catch (ArithmeticException e) {
e.printStackTrace();
}
System.out.println(121);
}
}
finally: 无论try中是否有异常发生,finlly中的代码总会执行,一般用于释放资源
例如:
public class Test {
public static void main(String[] args) {
try {
String name =null;
System.out.println(name.length());
System.out.println(1/0);
}catch (Exception e) {
System.out.println("other");
}finally {
System.out.println("z,jvhaahriFYEHDXLFG");
}
}
}
运行结果:
other
z,jvhaahriFYEHDXLFG
注:
一个try可以有多个catch,try不允许单独使用,像极了if else if else if … else
弊端:
如果错误很多,并且是死循环,那么控制台将会一直输出数据,由于内存是有限的,但数据却仍然输出,那么程序会将最先进入缓存的异常信息移除,我们就无法看到先前的异常信息,完整信息,为了解决这一点,我们引入了log4j 。
例:
import org.apache.log4j.Logger;
public class Test {
private static final Logger logger = Logger.getLogger(Test.class);
public static void main(String[] args) {
int i=1;
while (true) {
try {
System.out.println(1 /0);
} catch (Exception e) {
logger.debug(e.getMessage(), e);
}
i++;
}
}
}
log4j
引入
将异常信息打印控制台——>存入一段缓存,缓存有大小——>当缓存满了,但是异常信息源源不断,则会将最先进入缓存的异常信息移除——>意味着无法全面的发现程序运行期间出现的问题——>为了全面收集系统运行期间出现的所有异常信息,log4j诞生了——>将都有异常信息输出到一个文件中——因为文件在硬盘上——>可以认为无限大
概念:
Log4j是Apache的一个开源项目,通过使用Log4j,可以控制日志信息格式及其输送目的地(控制台、文件、数据库等),方便后期查找系统运行期间出现的问题,进而便于维护系统。
怎么用?
配置Log4j
步骤:
**第一步:**导入log4j-1.2.15.jar依赖包;
1.新建一个项目 (在此我的是work),在work下面新建一个 Folder (即文件夹)命名他为lib。然后将复制好的 log4j-1.2.15.jar 即jar包粘贴上去。
选中lib下面的log4j-1.2.15.jar—>BuildPath—>Add to Path
**第二步:**在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
Log4j配置文件详解:https://blog.youkuaiyun.com/gaohuanjie/article/details/44077551
第三步: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 级别的日志信息也会显示出来。
(我的在F盘)
间歇性产生新日志文件
引入:
思考:我们现在讲所有异常信息放在了一个文件中——>文件显得特别大——>分文件保存信息
上例配置文件是将所有的日志信息都收集到了一个文件中,那么随着时间的推移,该文件会越来越大,内容也会越来越多,这不利于后期对日志文件进行分析,为了解决该问题可以这样配置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中不用处理的文字要放到单引号(’)中,如上面的(.)。