Java 语言中,将程序执行中发生的不正常情况称为“异常”。
Java 虚拟机无法解决的严重问题,如:JVM 系统内部错误、资源耗尽等严重情况。比如:StackOverflowError[栈溢出]和OOM(out of memory),Error 是严重错误,程序会崩溃。
其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如空指针访问,试图读取不存在的文件,网络连接中断等待,Exception 分为两大类:运行时异常[程序运行时,发生的异常]和编译时异常[编译时,编译器检查出的异常]。
运行时异常,编译器检查不出来。一般是指编程时的逻辑错误,是程序员应该避免其出现的异常。java.lang.RuntimeException类及它的子类都是运行时异常。对于运行时异常,可以不做处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响。编译时异常,时编译器要求必须处理的异常。
在 Java 中,把异常信息封装成了一个类。当出现了问题时,就会创建异常类对象并抛出异常相关的信息(如异常出现的位置、原因等)。
1)手动去修改有问题的代码
2)使用debug
去调试代码
3)使用判断选择结构去修改代码:if...else
1)手动改代码,不靠谱,你怎么知道哪里会发生异常?
2)使用选择结构,太繁琐,不好维护
使用 java 提供的异常处理机制,来处理和捕获异常,保证程序的正常运行,提高程序的健壮性和可维护性。
Throwable类: Throwable
类是Java语言中所有错误和异常的超
类。
|--- 子类error : 一个 Error
是的子类Throwable
表示严重的问
题。该问题程序员是无法处理的,没有办法解决,一般不处理该问题。
|--- 子类 `Exception` : `异常` 及其子类是 `Throwable` 的形式,表示合理应用程序可能想要捕获的条件。该问题,程序员可以进行处理,捕获异常。 | --- checked异常/检查异常/编译期异常:程序员可以在写代
码的时候,可以发现的异常,代码有红色波浪线
|---RuntimeException: 运行期异常/非检查异常:该异常在编
译期不报错的,只有在程序运行的时候,才会出现异常,该异常要捕获!
使用 tay - catch 来捕获异常,来对异常进行处理
语法
try{ //可能会发生异常的代码 }catch(异常类型 变量名){ //对异常进行处理 }
快捷键:先写代码,然后选中代码,按 ctrl+alt+T,再选 try...catch
通过多重 catch,可以捕获具体的异常。
注意问题:
1)使用多个 catch 来捕获异常
2)catch 执行是有顺序的,一般范围小的异常,放在最前,最后写Exception
3)异常捕获成功之后,只会捕获一次异常,会结束 try...catch,继续执行后面的程序
4)catch 中的异常的变量名,可以重复,没有影响
finally:可以写,也可以不写;如果写了,那么finally中的代码,会执行。
一般应用于:I/O流,jdbc操作,关闭流,关闭连接
语法:
try{ //可能会发生异常的代码 }catch(异常类型 变量名){ //对异常进行处理 }finally{ //默认自动执行 }
细节问题:
System.exit(0)
:强制退出案例
package com.xunfang.homework.topic03; import java.util.InputMismatchException; import java.util.Scanner; public class NewDivide { public static void main(String[] args) { Scanner input = new Scanner(System.in); try { System.out.print("请输入被除数:"); int num1 = input.nextInt(); System.out.print("请输入除数:"); int num2 = input.nextInt(); System.out.println("num1 / num2 = " + num1/num2); // System.exit(0); // return; } catch (InputMismatchException e){ e.printStackTrace(); System.err.println("被除数和除数必须是整数"); }catch (ArithmeticException e){ e.printStackTrace(); System.err.println("除数不能为零"); } catch (Exception e) { //打印异常的堆栈信息- 什么异常,异常发生的位置 e.printStackTrace(); //err:打印的颜色会变成红色 System.err.println("程序发生了异常"); }finally { System.out.println("感谢使用本程序!"); } System.out.println("程序继续运行..."); } }
throws:抛出异常,表示该位置可能发生异常,但是不具体处理,让后面的程序去处理异常。
语法:
//表示当前的方法,抛出了什么异常! ...方法名() throws 异常类型1,异常类型2,...{ }
异常抛出的处理方式:
//1.main方法捕获异常 - 这种方式 //2.main也不想捕获,摆烂,抛出异常。(JVM的默认方式)
运行时异常:
RuntimeException - 父类
常见的运行时异常:
异常 | 解释 |
---|---|
NullPointerException | 空指针异常 |
ArithmeticException | 算术异常 |
ClassCastException | 类型强制转换异常 |
ArrayIndexOutOfBoundsException | 数组下标越界异常 |
StringIndexOutOfBoundsException | 字符串索引越界异常 |
InputMismatchException | 控制台输入类型错误异常 |
编译时异常:
写代码的时候,红色波浪线。
常见的编译时异常:
异常 | 解释 |
---|---|
FileNotFoundException | 文件未找到异常 |
ClassNotFoundException | 无法找到指定的类异常 |
SQLException | 操作数据库异常 |
IOException | 输入输出异常 |
NumberFormatException | 字符串转换为数字异常 |
NoSuchMethodException | 方法未找到异常 |
细节问题:
1、在代码的运行过程中,发生的异常,需要捕获
2、在代码的编写过程中,发生的异常,一般表现为红色波浪线
表示 程序员 认为该位置 肯定会有异常,进行手动抛出异常。
语法:
throw new 异常类型("xxx")
package com.xunfang.demo.demo2; public class Person { private String name; private int age; private char sex; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) throws Exception { if (age >= 16 && age <= 32){ this.age = age; }else { throw new Exception("年龄不合法!!!"); } } public char getSex() { return sex; } public void setSex(char sex) throws Exception { if (sex == '男' || sex == '女') { this.sex = sex; } else { throw new Exception("性别不合法!!!"); } } } package com.xunfang.demo.demo2; import java.util.Scanner; public class PersonTest { public static void main(String[] args) { Scanner input = new Scanner(System.in); Person person = new Person(); System.out.print("请输入姓名:"); person.setName(input.next()); try { System.out.print("请输入年龄:"); person.setAge(input.nextInt()); System.out.print("请输入性别:"); person.setSex(input.next().charAt(0)); } catch (Exception e) { e.printStackTrace(); } System.out.println("程序继续执行"); } }
System.exit(0)
程序强制退出:结束程序
return:方法返回
子类关系中,使用异常
1)如果父类方法抛出异常,子类可以不抛出异常
2)子类不能比父类抛出的异常范围大
3)子类可以比父类抛出的异常类型多
public abstract class Father { public abstract void show() throws NullPointerException, Exception; } public class Son extends Father{ @Override public void show() throws Exception,ArithmeticException,RuntimeException,NullPointerException{ System.out.println("重写"); } }
自定义异常类,要继承Exception类,并重写构造方法
public class AgeException extends Exception{ public AgeException(){} public AgeException(String message){ super(message); System.out.println("这是一个自定义的异常类"); } } public class Person { private int age; public int getAge() { return age; } public void setAge(int age) throws Exception { if (age >= 16 && age <= 60){ this.age = age; }else { throw new AgeException("年龄不合法!!!"); } } } public class PersonTest { public static void main(String[] args) { Scanner input = new Scanner(System.in); Person person = new Person(); try { System.out.print("请输入年龄:"); person.setAge(input.nextInt()); } catch (AgeException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } System.out.println("程序继续执行"); } }
日志:记录代码操作
Log4j:是一个日志的框架,可以在控制台和日志文件中,体现出后端的代码输出信息,方便我们去查找代码的信息和错误,和日志分析
使用步骤:
1)导入第三方的 jar 包
2)在src
目录下,去引入日志的配置文件log4j.properties
;
配置文件:便是可以实现一些项目的配置信息
配置文件的分类:xx.xml xx.properties xx.yaml xx.yml properties
配置文件的规则:属性1.属性2.xx.xx = 值
3)使用日志的类的对象,来使用日志的操作。
#根logger设置 log4j.rootLogger = INFO,console,file ### 输出信息到控制台### log4j.appender.console = org.apache.log4j.ConsoleAppender log4j.appender.console.Target = System.out log4j.appender.console.layout = org.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern = [%p] %d{yyyy-MM-dd HH:mm:ss} method: %l----%m%n ###输出INFO 级别以上的日志文件设置### log4j.appender.file = org.apache.log4j.DailyRollingFileAppender log4j.appender.file.File = D:/2022.7.22_test.log log4j.appender.file.Append = true log4j.appender.file.layout = org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss} method: %l - [ %p ]----%m%n
用法:
导包:import org.apache.log4j.Logger; 创建日志对象 public Logger logger = Logger.getLogger(Person.class); 打印日志消息... logger.info("年龄合法~"); public static Logger logger = Logger.getLogger(Person.class); //注意此处为static 再调用方法:报程序错误,和错误内容 logger.error("程序错误",e);