Java程序的异常
一、异常概念
1、生活中的异常
在生活中,异常情况随时会发生。指的是在做某件事的时候,遇到某些不可控的现象,导致当前所做的事受到影响未能完成或者延时完成。
2、程序中的异常
程序中的异常就是在程序的运行过程
二、程序异常
1、分类
大致分为三种:
- 编译错误:不能运行,在编译阶段就报错
- 运行错误:能正常运行,但是运行时错误
- 逻辑错误:结果错误,能正常编译,能正常运行
细分为:
- Throwable类:所有异常类型都是Throwable类的子类,它派生两个子类,即Error和Exception。
- Error类:表示仅靠程序本身无法恢复的严重错误,如内存溢出动态链接失败、虚拟机错误。
- Exception类:由Java应用程序抛出和处理的非严重错误,如所需文件找不到、数组下标越界等等。
- 运行时异常:包括RuntimeException及其所有子类,不要求必须对它们做出处理。
- Checked异常(非运行时异常):除了运行时异常外的其他由Exception继承来的异常类。程序必须捕获或声明抛出这种异常,否则会出现编译错误,无法通过编译。
2、常见的异常类型
异常 | 说明 |
---|---|
Exception | 异常层次结构的根类 |
ArithmeticException | 算术错误情形,如以零做除数 |
ArrayIndexOutOfBoundsException | 数组下标越界 |
NullPointException | 尝试访问null对象成员 |
ClassNotFoundException | 不能加载所需的类 |
InputMismatchException | 欲得到的数据类型与实际输入的类型不匹配 |
IllegalArgumentException | 方法接收到非法参数 |
ClassCastException | 对象强制类型转换出错 |
NumberFormatException | 数字格式转换异常,如把“abc”转换为数字 |
3、处理异常手段
在程序执行代码的时候,万一发生了异常,程序会按照预定的处理办法对异常进行处理,异常处理完毕之后,程序继续运行
3.1、try…catch
try代码块里一般放置可能出现错误的代码,catch是程序出现异常会进入的代码块
- 如果try块中所有语句正常执行完毕,不会发生异常,那么catch块中的所有语句都将会被忽略。
- 如果try语句块在执行过程中遇到异常,并且这个异常与catch中声明的异常类型相匹配,那么try块中其余剩下的代码都将被忽略,而相应的catch块将会被执行。匹配是指catch所处理的异常类型与所生成的异常类型完全一致或是它的父类
- 如果try语句块在执行过程中遇到异常,而抛出的异常在catch块里面没有被声明,那么程序立刻退出
3.2、try…catch…finally
与try…catch对比多了一个finally关键字
finally:不论是执行try还是catch块都会执行到finally里面的代码
try-catch-finally结构中try块是必须的,catch和finally块为可选,但两者至少必须出现其中之一。
**注意:**即使在try块和catch块中存在return语句,finally块中语句也会被执行。发生异常时的执行顺序:执行try块或catch块中return之前的语句,执行finally块中的语句,执行try块或catch中的return语句退出。
try{
//代码1
}catch(Exception e){
//代码2
}finally{
//代码3 //一定会被执行
}
3.3、多重catch块
一段代码可能会引发多种类型的异常,这时,可以在一个try语句块后面跟多个catch块,分别处理不同的异常。但排序顺序必须是从子类到父类,最后一个一般都是Exception类。当运行时,系统从上到下分别对每个catch语句块处理的异常类型进行检测,并执行第一个与异常类型匹配的catch语句。执行其中的一条catch语句之后,其后的catch语句都将被忽略。
4、声明和抛出异常
4.1、声明异常:throws
Java语言中通过关键字throws声明某个方法可能抛出的各种异常。throws可以同时声明多个异常,之间用逗号隔开。
/*
*这个方法声明了异常
*/
public void test() throws Exception{
//代码块
}
4.2、抛出异常:throw
除了系统自动抛出异常外,在编程过程中,有些问题是系统无法自动发现并解决的,此时需要程序员而不是系统来自行抛出异常,把问题提交给调用者解决。
/*
*这个方法声明并抛出了异常
*/
public void test() throws Exception{
//代码块
throw new Exception(); //抛出异常
}
处理抛出异常的两种方式:
- 通过try-catch捕获并处理异常。
- 通过throws继续声明异常。如果调用者不打算处理该异常,则可以继续通过throws声明异常,让上一级调用者处理异常。main()方法声明的异常将由Java虚拟机来处理。
4.3、throws和throw的区别
- 作用不同:throw用于在程序中抛出异常;throws用于声明在该方法内抛出了异常。
- 使用的位置不同:throw位于方法体内部,可以作为单独语句使用;throws必须跟在方法参数列表的后面,不能单独使用。
- 内容不同:throw抛出一个异常对象,而且只能是一个;throws后面跟异常类,而且可以跟多个异常类。
三、开源日志记录工具log4j
软件的运行过程离不开日志,日志主要用来记录系统运行过程中的一些重要的操作信息,便于监视系统运行情况,帮助用户提前发现和避开可能出现的问题,或者出现问题后根据日志找到发生的原因。
log4j是一个非常优秀的日志(log)记录工具。通过使用log4j,可以控制日志的输出级别,以及日志信息输送的目的地(如控制台、文件等),还可以控制每一条日志的输出格式。
1、使用步骤
- 在项目中加入log4j所使用的JAR文件。
- 创建log4j.properties文件。
- 编写log4j.properties文件,配置日志信息。
- 在程序中使用log4j记录日志信息。
2、日志的分类
日志根据记录内容的不同,主要分成以下三类:
- SQL日志:记录系统执行的SQL语句。
- 异常日志:记录系统运行中发生的异常事件。
- 业务日志:记录系统运行过程,如用户登录、操作记录。
3、log4j配置文件
3.1、输出级别
log4j.rootLogger=debug, stdout,logfile
debug指的是日志记录器(Logger)的输出级别,主要输出级别及含义如下:
- fatal:指出严重的错误事件将会导致应用程序的退出。
- error:指出虽然发生错误事件,但仍然不影响系统的继续运行。
- warn:表明会出现潜在错误的情形。
- info:在粗粒度级别上指明消息,强调应用程序的运行过程。
- debug:指出细粒度信息事件,对调试应用程序非常有帮助。
各个输出级别优先级:
fatal > error > warn > info > debug
日志记录器(Logger)将只会输出那些级别高于或等于它的信息。
3.2、日志输出目的地Appender
log4j.rootLogger=debug, stdout,logfile
其中,stdout,logfile指的是日志输出目的地的名字。
log4j允许记录日志到多个输出目的地,一个输出目的地被称为一个Appender。log4j最常用的Appender有以下两种:
- ConsoleAppender:输出日志事件到控制台。通过Target属性配置输出到System.out或System.err,默认的目标是System.out。
- FileAppender:输出日志事件到一个文件。通过File属性配置文件的路径及名称。
3.3、日志布局类型Layout
Appender必须使用一个与之相关联的布局类型Layout,用来指定它的输出样式:
- HTMLLayout:格式化日志输出为HTML表格。
- SimpleLayout:以一种非常简单的方式格式化日志输出,它输出级别Level,然后跟着一个破折号“——”,最后是日志信息。
- PatternLayout:根据特定的转换模式格式化日志输出,从而支持丰富多样的输出格式。需要配置layout.ConversionPattern属性,若没有配置该属性,则使用默认的转换模式。
3.4、转换模式ConversionPattern
对于PatternLayout,需要配置layout.ConversionPattern属性,常用的配置参数及含义如下
- %d:设置输出日志的日期和时间,默认格式为ISO8601。
- %m:输出代码中指定的消息。
- %n:输出一个回车换行符。
- %l:输出日志事件的发生位置,包括类名、发生的线程,以及在代码中的行数。
- %p:输出优先级。
- %F:输出文件名
- %M:输出方法名。