异常Exception:
ArrayIndexOutOfBoundsException 数组下标越界异常
NullPointerException(NPE) 空指针异常
当引用数据类型没有引用某个内存空间时,它的值就是null,那么如果null值去使用方法、属性则会报出此异常
ClassCastException 类型转换异常
使用多态时尤其可能出现,不确定多态的具体类型时,转换可能会出现问题。
ClassNotFoundException 类找不到的异常
ArithmeticException 算数异常 (除数为0)
InputMismatchException 输入不匹配异常
异常: 在执行某件事的过程中,出现了不符合预期的情况
电梯异常、地铁异常、电路异常……
在程序运行过程中出现的问题,会导致程序中断(结束),后续代码不会再执行。
// 示例代码
Scanner input = new Scanner(System.in);
System.out.print("请输入第一个整数:");
int num1 = input.nextInt();
System.out.print("请输入第二个整数:");
int num2 = input.nextInt();
// 计算除法
int num3 = num1 / num2;
System.out.println(num1+"/"+num2+"="+num3);
System.out.println("程序结束!");
利用前期学习的技术:
Scanner input = new Scanner(System.in);
System.out.print("请输入第一个整数:");
// 判断输入的是否是整数 判断语句要放在前面 否则没有意义
if(input.hasNextInt()){
int num1 = input.nextInt();
System.out.print("请输入第二个整数:");
if(input.hasNextInt()){
int num2 = input.nextInt();
if(num2 != 0){
// 计算除法
int num3 = num1 / num2;
System.out.println(num1+"/"+num2+"="+num3);
}else{
sout("除数不能为0!");
}
}else{
sout("对不起!除数必须为整数");
}
}else{
sout("对不起!被除数必须为整数");
}
System.out.println("程序结束!");
Java提供了一套异常处理机制来解决我们使用过多的 if 判断问题(补不全、代码维护性变差、阅读困难)
由下方关键词可以让我们的程序遇到异常时更加健壮
try: 尝试
catch: 抓住
finally: 最终的
throw: 扔
throws: 扔
try{
// 在try代码块中执行有可能出现异常的代码段
}catch(异常类型 e){ // 当出现了异常的情况下,catch标注的异常会捕获合适的异常
// 捕获到合适的异常之后,对异常采取修复/处理
}
执行流程:
在执行try块代码时
当出现:InputMismatchException
情况时,会立刻结束try块代码,JVM会帮你构建一个异常对象(nextInt()
代码中有此源码)new InputMismatchException(nfe.getMessage());
然后我们的catch块就可以捕获到此异常,形参会接收此对象引用,进行正常处理,处理完继续正常运行。
当出现:ArithmeticException
情况时,会立刻结束try块代码,JVM帮你创建的异常对象无法被catch块所接受,相当于方法的形参和实参不一致,所以catch不会捕获异常,JVM会将你的异常直接以堆栈跟踪的形式打印出来,并且会结束我们的程序。
Scanner input = new Scanner(System.in);
try{
// 可能出现问题的代码
System.out.print("请输入第一个整数:");
int num1 = input.nextInt();
System.out.print("请输入第二个整数:");
int num2 = input.nextInt();
// 计算除法
int num3 = num1 / num2;
System.out.println(num1+"/"+num2+"="+num3);
}catch(InputMismatchException e){ // 能捕获的异常类型
// 对应的异常处理
sout("对不起!请输入整数!");
}
System.out.println("程序结束!");
类似于多重if一样,出现的异常会挨个进行尝试调用catch,只要有一个匹配,则执行处理,后面的catch不会处理了
异常类型范围大的记得放在后面
try{
// 可能出现的异常代码
}catch(异常类型1 e){
// 对应的异常处理
}catch(异常类型2 e){
// 对应的异常处理
}....
catch(Exception e){ // Ecxeption是异常的顶级父类,它可以接受任何异常类型的对象(多态)
// 最终默认的处理
}
Scanner input = new Scanner(System.in);
try{
// 可能出现问题的代码
System.out.print("请输入第一个整数:");
int num1 = input.nextInt();
System.out.print("请输入第二个整数:");
int num2 = input.nextInt();
// 计算除法
int num3 = num1 / num2;
System.out.println(num1+"/"+num2+"="+num3);
}catch(InputMismatchException e){ // 能捕获的异常类型1
sout("对不起!请输入整数!");
}catch(ArithmeticException e){ // 能捕获的异常类型2
sout("对不起!除数不能为0!");
}catch(Exception e){
sout("服务器繁忙!");
}
System.out.println("程序结束!");
处理手段一致的情况下会采用:
Scanner input = new Scanner(System.in);
try{
System.out.print("请输入第一个整数:");
int num1 = input.nextInt();
System.out.print("请输入第二个整数:");
int num2 = input.nextInt();
// 计算除法
int num3 = num1 / num2;
System.out.println(num1+"/"+num2+"="+num3);
}catch(InputMismatchException | ArithmeticException e){
e.getMessage(); // 打印异常的堆栈跟踪
// 或 打印红色字 + 堆栈信息追踪
// System.err.println("异常出现了!"+e.getMessage());
}
System.out.println("程序结束!");
catch代码块中,处理异常的情况一般有以下几种:
1.已友好的形式提示异常信息 System.out.println();
或System.err.println();
2.使用异常的堆栈跟踪来打印异常信息(这个和JVM处理不一样,JVM会中断程序)
3.使用日志记录异常信息
4.根据逻辑进行合理值更改
try{
// 可能出现异常的代码段
}catch(异常类型 e){
// 处理异常的代码段
}finally{
// 最终执行的代码段:无论是否出现异常 此处代码段都会执行
// 一般的应用在资源释放
}
try{
// 可能出现异常的代码
}finally{
// 最终执行的代码段:无论是否出现异常 此处代码段都会执行
// 一般的应用在资源释放
}
如果finally和return同时出现,那么如何执行?【面试题】
会执行finally中的内容,然后再执行return。
final、finally、finalize的区别【面试题】
final的作用
finally的作用
finalize的作用
它是Object类中的一个方法,是Java的GC(垃圾回收站)自动会调用的一个方法
protected void finalize() throws Throwable {}
throw和throws的区别【面试题】
throw表示抛出异常,抛出异常后面要跟随异常的对象,用于告知调用者异常的信息(异常对象),后期常用来抛出自定义异常。
// 摘自:java.util.Scanner.nextInt()方法
try {
String s = next(integerPattern());
if (matcher.group(SIMPLE_GROUP_INDEX) == null)
s = processIntegerToken(s);
return Integer.parseInt(s, radix);
} catch (NumberFormatException nfe) {
position = matcher.start(); // don't skip bad token
throw new InputMismatchException(nfe.getMessage());
}
throws表示声明异常,它是在方法声明中进行指定的,一般表示此方法不处理异常而是向上甩锅。
public FileInputStream(File file) throws FileNotFoundException;
Throwable顶级接口
Exception异常的顶级父类(异常指的是可以经过处理而修复的问题 )
表示代码编写出来后必须要求提前处理的异常
例如:FileNotFoundException
Checked异常(受检异常)
Error错误的顶级父类:OutOfMemory StackOverFlow(Error是必须通过更改代码才能修复的问题)
表示代码编写后非必须要求处理的异常
例如:InputMismatchException NumberFormatException
UnChecked异常(不受检异常)/RuntimeException运行时异常
如果觉得Java的异常体系不够丰富,可以自行创建异常类。
//public class IllegalAgeException extends Exception{
public class IllegalAgeException extends RuntimeException{
public IllegalAgeException() {
super();
}
public IllegalAgeException(String message) {
super(message);
}
}
// ----------------------------------------------------
public class Student{
private String name;
private int age;
public void setAge(int age) throws Exception {
if(age < 0 || age > 100) {
// System.out.println("对不起!年龄非法!");
// throw new Exception("年龄非法!");
throw new IllegalAgeException("年龄非法!");
}else {
this.age = age;
}
}
}
try{
}catch(Exception e){
// 处理
}
它用来记录系统运行中的一些重要操作信息,便于监视系统运行情况,也便于出现问题后快速找到原因的文件。
.log
格式的文件
我们要记录日志,如果自己来实现这种红能非常繁琐,所以有很多组织或者个人开发了相关的工具开源出来供我们使用,那么在Java项目中如何去引用他们编写的这些工具呢?
步骤:
1.下载相应的工具包(SDK):他们一般帮助我们将其打成了jar包(压缩包 字节码文件的集合)
2.将jar包引入到项目的类库中(像引入jre一样)
3.引入之后,根据工具的说明书(API文档)进行使用即可
我们记录日志可以采用的工具包:log4j、log4j2、logback…(slfj日志门面)
将jar包引入为类库
根据要求和使用说明进行使用
log4j.properties
配置日志运行的规则### 设置Logger输出级别和输出目的地(可以指定多个目的地) ###
### 一般在开发的时候使用debug,开发完成后使用error ###
### 他们对应的是输出信息的级别,级别越低信息输出越详细,使用debug级别的时候,info中的信息也能输出,使用info的时候,debug对应的信息显示不出来 ###
### 日志记录器输出级别:fatal>error>warn>info>debug ###
### 后面的两个对应下方的两处 一处打印在控制台 另一处打印在日志文件里
log4j.rootLogger=debug,console,logFile
##################################################################################
### 把日志信息输出到控制台 ###
log4j.appender.console=org.apache.log4j.ConsoleAppender
### 信息打印到System.err上,红色 ###
log4j.appender.console.Target=System.out
### 指定日志在控制台上输出的布局类型 采用指定格式的类型 ###
log4j.appender.console.layout=org.apache.log4j.PatternLayout
### %r:输出自应用启动到输出该 log信息耗费的毫秒数 %x表示信息输出时左对齐
### %5p:%p表示输出日志信息优先级,即 DEBUG, INFO, WARN, ERROR, FATAL 中间的5控制最小的宽度为5
### %F:%L %F:输出日志消息产生时所在的文件名称 %L:输出代码中的行号
### %l:输出日志事件的发生位置,相当于%C.%M(%F:%L)的组合,包括类目名、发生的线程,以及行数
### %m:输出代码中指定的消息,产生的日志具体信息 %n:输出一个回车换行符, Windows 平台为"\r\n", Unix 平台为"\n"输出日志信息换行
log4j.appender.console.layout.ConversionPattern= (%r ms) - %d{yyyy-M-d HH:mm:ss}%x[%5p](%F:%L) %m%n
##################################################################################
#################################################################################
### 把日志信息输出到文件:jbit.log 注意:如果有路径\符号一定要写成\\ 否则会被转义 ###
log4j.appender.logFile=org.apache.log4j.FileAppender
### 指定日志输出的文件名 ###
log4j.appender.logFile.File=test.log
### 指定转换模式 ###
log4j.appender.logFile.layout=org.apache.log4j.PatternLayout
### 指定日志布局类型 ###
###log4j.appender.logFile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss}%l %F %p %m%n
###log4j.appender.logFile.layout.ConversionPattern= -> (%r ms) - %d{yyyy-M-d HH:mm:ss}%x[%5p](%F:%L) %m%n
log4j.appender.logFile.layout.ConversionPattern= (%r ms) - %d{yyyy-MM-dd HH:mm:ss}%x[%5p]%l %m%n
#################################################################################
使用API来进行日志记录
Logger类
Logger getLogger(字节码对象);
public class Demo1 {
// 类名.class
static Logger logger = Logger.getLogger(Demo1.class);
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
try {
logger.info(">>>>>>程序启动>>>>>>>");
// 可能出现问题的代码
System.out.print("请输入第一个整数:");
int num1 = input.nextInt();
logger.info(">>>>>用户正在输入第一个整数,输入的数值为:"+num1+">>>>>>>>");
System.out.print("请输入第二个整数:");
int num2 = input.nextInt();
logger.info(">>>>>用户正在输入第二个整数,输入的数值为:"+num2+">>>>>>>>");
// 计算除法
int num3 = num1 / num2;
logger.info(">>>>>用户正在进行结果计算,结果为:"+num3+">>>>>>>>");
System.out.println(num1+"/"+num2+"="+num3);
}catch(InputMismatchException e) { // 能捕获的异常类型
logger.error(">>>>>>>程序出现输入不匹配异常>>>>>>",e);
}catch (ArithmeticException e) {
logger.error(">>>>>>>程序出现算术异常>>>>>>",e);
}catch (Exception e) {
logger.error(">>>>>>>程序出现未知异常>>>>>>",e);
}
System.out.println("程序结束!");
logger.info(">>>>>>程序结束>>>>>>>");
}
}
注:笔记思路来自查老师!!