异常 笔记分享

异常

异常Exception:

  • ArrayIndexOutOfBoundsException 数组下标越界异常

  • NullPointerException(NPE) 空指针异常

    当引用数据类型没有引用某个内存空间时,它的值就是null,那么如果null值去使用方法、属性则会报出此异常

  • ClassCastException 类型转换异常

    使用多态时尤其可能出现,不确定多态的具体类型时,转换可能会出现问题。

  • ClassNotFoundException 类找不到的异常

  • ArithmeticException 算数异常 (除数为0)

  • InputMismatchException 输入不匹配异常

1.了解异常的概念

1.1生活中的异常

异常: 在执行某件事的过程中,出现了不符合预期的情况

电梯异常、地铁异常、电路异常……

1.2程序中的异常

在程序运行过程中出现的问题,会导致程序中断(结束),后续代码不会再执行。

// 示例代码
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("程序结束!");

2.理解Java异常处理机制

Java提供了一套异常处理机制来解决我们使用过多的 if 判断问题(补不全、代码维护性变差、阅读困难)

由下方关键词可以让我们的程序遇到异常时更加健壮

try: 尝试

catch: 抓住

finally: 最终的

throw:

throws:

3.会捕捉异常

3.1 try-catch组合

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("程序结束!");

3.2 多重catch块

类似于多重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.根据逻辑进行合理值更改

3.3 try-catch-finally/try-finally

try{
    // 可能出现异常的代码段
}catch(异常类型 e){
    // 处理异常的代码段
}finally{
    // 最终执行的代码段:无论是否出现异常 此处代码段都会执行
    // 一般的应用在资源释放
}
try{
    // 可能出现异常的代码
}finally{
    // 最终执行的代码段:无论是否出现异常 此处代码段都会执行
    // 一般的应用在资源释放
}

如果finally和return同时出现,那么如何执行?【面试题】

会执行finally中的内容,然后再执行return。

final、finally、finalize的区别【面试题】

  • final的作用

    • 修饰变量 则此变量变为常量,常量只允许赋值一次
    • 修饰类 则此类将无法被继承
    • 修饰方法 则此方法无法被重写
  • finally的作用

    • 是异常处理中的一个概念,表示无论是否出现异常finally中的内容都会执行
  • finalize的作用

    • 它是Object类中的一个方法,是Java的GC(垃圾回收站)自动会调用的一个方法

      protected void finalize() throws Throwable {}
      

4.会抛出异常

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; 

5.了解Java异常体系结构

异常 笔记分享_第1张图片

Throwable顶级接口

  • Exception异常的顶级父类(异常指的是可以经过处理而修复的问题 )

    表示代码编写出来后必须要求提前处理的异常

    例如:FileNotFoundException

    Checked异常(受检异常)

  • Error错误的顶级父类:OutOfMemory StackOverFlow(Error是必须通过更改代码才能修复的问题)

表示代码编写后非必须要求处理的异常

例如:InputMismatchException NumberFormatException

UnChecked异常(不受检异常)/RuntimeException运行时异常

6.会编写自定义异常

如果觉得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;
        }
	} 
}

7.会使用日志记录异常情况(log4j(log for java)、log4j2、logback)

try{

}catch(Exception e){
	// 处理
}

它用来记录系统运行中的一些重要操作信息,便于监视系统运行情况,也便于出现问题后快速找到原因的文件。

.log格式的文件

我们要记录日志,如果自己来实现这种红能非常繁琐,所以有很多组织或者个人开发了相关的工具开源出来供我们使用,那么在Java项目中如何去引用他们编写的这些工具呢?

步骤:

1.下载相应的工具包(SDK):他们一般帮助我们将其打成了jar包(压缩包 字节码文件的集合)

2.将jar包引入到项目的类库中(像引入jre一样)

3.引入之后,根据工具的说明书(API文档)进行使用即可

我们记录日志可以采用的工具包:log4j、log4j2、logback…(slfj日志门面)

  • 在Java项目中创建一个文件夹(lib)存放jar包
    异常 笔记分享_第2张图片

  • 将jar包引入为类库

    在jar包上右键 → build path → add to build path
    异常 笔记分享_第3张图片

  • 根据要求和使用说明进行使用

    • 准备一个日志配置文件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(字节码对象);

        • info() 记录普通信息
        • debug() 记录方便我们调试的信息
        • error() 记录错误信息
      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(">>>>>>程序结束>>>>>>>");
      	}
      
      }
      

注:笔记思路来自查老师!!

你可能感兴趣的:(异常,笔记)