使用if-else处理异常的缺点
1.无法穷举所有的异常情况
2.影响程序可读性,维护难度高
使用Java异常处理机制自动处理异常
Java针对异常的处理提供了 try、catchfinally、throwsthrow 五个核心关键字,其中前三个关键字就可以组成常用的异常处理结构,语法如下所示
try{ //可能出现异常的语句 }catch(异常类型 异常对象){ //异常处理语句 }finally{ // 一定会运行到的语句 }
其中,ty 语句用于监听,将可能抛出异常的代码放在 ty 语句块内,当ty 语句块内发生异常时,异常就被抛出;catch 语句用于捕获异常,catch 语句用来捕获 ty 语句块中抛出的异常fially 语句块总会被执行,主要用于回收ty 语句块内打开的资源
eg:
try {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入1-3的课程编号");
int num=scanner.nextInt();
switch (num){
case 1:
System.out.println("Java");
break;
case 2:
System.out.println("html");
break;
case 3:
System.out.println("c#");
break;
default:
System.out.println("请输入1~3数字");
break;
}
} catch (Exception e) {
System.out.println("你的输入不匹配,请输入数字");
} finally {
System.out.println("欢迎提出意见");
}
以上格式中的 catch 语句、finally 语句都可选。实际上,这并不是表示catch 语句、finally语句可以同时消失。异常格式的常见组合有try-catch、try-catch-finally、try-finally三种
finally 语句
增加了 finally 语句,这样在异常处理过程中,无论是否出现异常,最终都会执行finally语句块中的代码。finally 语句往往会在开发中进行一些资源释放操作,无论代码是否正常执行都必须完成这些操作。 需要注意的是,即使在try 语句块或catch 语句块中添加了retum语句finally语句块也会被正常执行。
多重catch 语句进行异常处理
程序出现的全部异常有统一的处理方式。但在实际开发中,有时会希望针对不同的异常类型采取不同的处理方式,这样就需要使用多重 catch 语句进行异常处理。语法如下:
如果需要针对可能发生的异常类型采取不同的处理方式,则需要使用多个 catch 语句块分别捕获不同的异常类型,输出不同的提示信息,
try{ //有可能出现异常的语句 }catch(异常类型1 异常对象){ //异常处理语句 }catch(异常类型2 异常对象){ //异常处理语句 }finallyt{ //一定会运行到的语句 }
注意:
(1)当ty 语句块中发生异常时,系统将会按照从上到下的顺序依次检测每个 catch 语句,当匹配到某条catch 语句后,后续其他 catch 语句块将不再被执行。 (2)以 Exception 作为参数的 catch 语句必须放在最后的位置,否则所有的异常都会被其捕获后面以其子类异常作为参数的 catch 语句将得不到被执行的机会
异常分类
下面分别介绍Error类和Exception类 1,Error类 Java.lang.Error类包含仅靠程序本身无法恢复的严重错误,(一般指与JVM相关的问题是Java运行环境的内部错误或硬件问题,如内存资源不足、JVM错误等。应用程序不应抛出这种类型的对象一由JVM抛出)。假如出现这种错误,除尽力使程序安全退出外,其他方法是无能为力的。因此在进行序设计时,应该更关注Exception 类。
2.Exception类 Javalang.Exception类是程序本身可以处理的异常,可分为运行时(RunTimeException)异常与检(Checked)异常。
(1).运行时异常:可以在程序中避免的异常。这类异常在编译代码时不会被编译器检测出来,可正常编译运行,但当程序进行时发生异常,会输出异常堆栈信息并中止程序运行,程序员可根据需要使用ty-catch语句捕获这类异常,如空指针异常、类型转换异常、数组越界异常等这些异常包括javalongRuntimeException类及其子类,通过这些具体的异常类型,能够判断序的问题所在。Java程序中常见的运行时异常
(2).Checked 异常,除运行时异常外的异常,是由用户错误或问题引起的异常,这是程序员无法预见的。在编译时,编译器会提示这类异常需要捕获。如果不进行捕获,则会出现编译错误。常见的编译异常有FileNotFoundException异常、SQLException异常等
Java程序中常见的运行时异常
异常 说明 | |
---|---|
ArithmeticException 当出现算术错误时,抛出此异常。例如,在一个整数“除以0”时,抛出此异常 | |
ArrayIndexOutOfBoundsException 当非法索引访问数组时,抛出此异常。例如,索引为负或大于等于数组长度 | |
ClassCastException 当试图将对象强制转换为非本对象类型的子类时,抛出此异常 | |
IllegalArgumentException 当向方法传递了一个不合法或不正确的参数时,抛出此异常 | |
InputMismatchException 当欲得到的数据类型与实际输入的类型不匹配时,抛出此异常 | |
NullPointerException 当应用程序试图在需要对象的地方使用mull时,抛出此异常 | |
NumberFormatException 当试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出此异常。 | |
Java中异常处理的完整流程进行总结
(1) 生成异常对象。如果程序在运行过程中出现异常,则JVM 自动根据异常的类型实例化一个与之类型匹配的异常对象。如果发生异常的语句存在于ty 语句块中,则去匹配对应的 catch 语句;否则IVM进行默认处理,输出异常信息后中断执行。
(2)执行 catch 语句块。将所生成的异常对象与ty 后每一条 catch 语块进行比较。如果 catch语句块的异常参数能够与当前产生的异常对象匹配,则执行该 catch 语句块进行异常处理,否则,继续向下匹配其他catch 语句块。如果无匹配的 catch 语句块,则此异常对象交由JVM进行默认处理,输出常信息。
(3)执行 finally语句块。无论最终是否有匹配的catch语句块,都会执行finally 语句块如果没finally语句块,则忽略。
声明异常-throws 关键字
如果根据程序的设计,不适合立即去处理异常,而应声明可能发生的异常,交由上一级处理,此时就需要使用throws关键字
throws关键字是方法可能抛出异常的声明,用在所声明的方法时,表示该方法可能会抛出此类异常
public void方法名() throws 异常类型{ //方法体 }
throws 关键字可以在一个方法定义处声明一类或多类异常,多类异常间使用逗号分隔
抛出异常-throw 关键字
使用ty-catch-finally 语句进行异常处理,在这个异常处理结构中,由JVM进行判断并抛出异常信息,也就是程序遇到异常时会自动处理。但是有时可能会出现以下状况。 需要根据程序逻辑自定义异常类,这些异常类在 Java 异常体系中并未提供,不能抛出。例如 当程序中的注册流程执行时发生错误,需要抛出自定义的注册异常精确定位问题所在,但是注册异常在Java 异常体系中不存在,就不能被自动捕获 ,根据业务需要自行选择异常抛出时机或自定义异常处理逻辑。例如,根据不同的逻辑判断条件而抛出异常。 在以上情况中,就需要使用 throw 关键字自行手动抛出异常,由调用者处理抛出异常的时机和异常处理逻辑。由于使用 throw 关键字抛出的异常是异常类的对象,所以可以使用new 关键字创建异常类的对象,通过throw关键字抛出
日志
日志的主要用途如下
问题追踪:辅助排查和定位问题,优化程序运行性能
状态监控:通过日志分析,可以监控系统的运行状态
安全审计:主要体现在安全上,可以发现非授权操作
日志记录器的日志级别共有八级,从低到高依次如下
all<trace<debug<info<warn<error<fatal<OFF
all:最低等级,用于打开所有日志记录
trace:用于程序追踪输出。
debug:指出细粒度信息事件,对调试应用程序是非常有帮助的
info:在粗粒度级别上指明消息,强调应用程序的运行过程。
warn :表示警告信息,即可能出现的潜在错误。
errOr:指出错误事件,但仍然不影响系统的继续运行 fatal :指出严重的错误事件,将会导致应用程序退出
OFF:最高等级,用于关闭所有日志记录
程序会输出高于或等于所设置级别的日志,设置的日志等级越高,输出的日志就越少.
常用的占位符及其含义如下
控制日志输出格式的常用占位符,通过设置日志输出格式,可以输出丰富多样化的日志。
%d:用来设置输出日志的日期和时间,默认格式为 ISO8601。也可以在其后指定格式如%d{yyyy-MM- ddHH:mm:ss},输出的格式类似于2021-03-10 16:43:08
%m:输出代码中指定的消息。
%5level:输出日志级别,-5表示左对齐并固定输出5个字符,如果不足,则在右边补0.
%1:用来输出日志事件的发生位置,包括类名、发生的线程,以及在代码中的行数。例如,如果输出为cnjava.log.Test.main(Test.java:25),则说明日志事件发生在 cnjavalog 包下的Test类的main 线程中,在代码中的行数为第25行。
%t:用来输出当前线程的名称 %logger:输出logger 名称。
%msg:日志文本
%n:换行。