1.问题引出:
public class Exception01 { public static void main(string[l args){ int num1 = 10; int num2 = 0; int res = num1 / num2; System.out.println("程序继续运行...."); } }(1)num1/num2 => 10 / 0
(2)当执行到 num1 / num2 因为 num2 = 0,程序就会出现(抛出)异常 ArithmeticException
(3)当抛出异常后,程序就退出,崩溃了,下面的代码就不在执行
(4)大家想想这样的程序好吗?
不好,不应该出现了一个不算致命的问题,就导致整个系统崩溃
(5)java 设计者,提供了一个叫 异常处理机制来解汇该问题
int res = num1 / num2;
如果程序员,认为一段代码可能出现异常/问题,可以使用try-catch异常处理机制来解决,从而保证程序的健壮性。
方式:将该代码块 -> 选中 ->快捷键ctrl + alt + t-> 选中 try-catch
(6)如果进行异常处理,那么即使出现了异常,程序可以继续执行
public class Exception01 { public static void main(string[l args){ int num1 = 10; int num2 = 0; try { int res = num1/num2, } catch(Exception e){ e.printStackTrace(); } //int res = num1 / num2; System.out.println("程序继续运行...."); } }2.什么是异常?
在 Java 中,异常是程序运行过程中出现的错误或不正常情况(开发过程中的语法
错误和逻辑错误不是异常)。Java 的异常处理机制允许我们捕获、处理异常,使程序能够在遇到问题时优雅地应对,而不是直接崩溃。异常通常表示程序中某些不正常的情况,例如,文件找不到、数据库连接失败、数组越界等。
执行过程中所发生的异常事件可分为两类:
(1)Error(错误):Java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源耗尽等严重情况。比如:StackOverflowError[栈溢出]和OOM(out ofmemory),Error 是严重错误,程序会崩溃。
(2)Exception:其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如空指针访问,试图读取不存在的文件,网络连接中断等等。
Exception 分为两大类:运行时异常(程序运行时,发生的异常) 和编译时异常(编程时,编译器检查出的异常)。
小结:
运行时异常,编译器检查不出来。一般是指编程时的逻辑错误,是程序员应该避免其出现的异常。
对于运行时异常,可以不作处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响
编译时异常,是编译要求必须处置的异常
3.异常体系图
1.Java 异常体系的基本结构
Java 中的异常类体系主要由两个顶级类组成:
Throwable:所有错误和异常的父类。Error:表示严重的系统错误,通常是 JVM 无法处理的问题,如内存不足等。Exception:表示程序可以处理的异常。
2.异常体系的详细层次结构
在上面的图中:
Throwable是所有异常和错误的根类,所有的异常(Exception)和错误(Error)都继承自它。Error用于表示严重的错误,通常程序不能处理这类错误。例如,OutOfMemoryError和StackOverflowError,这些错误通常是由 JVM 引发的,表示系统出现了严重问题,程序无法恢复。Exception用于表示程序可以捕获并处理的异常。Exception又分为两种类型:Checked Exception(检查时异常):这种异常必须显式地处理,编译器会要求你处理它们。常见的例子有IOException、SQLException等。Unchecked Exception(运行时异常):这种异常是运行时发生的,编译器不会强制要求处理。常见的例子有NullPointerException、ArrayIndexOutOfBoundsException等。
3.Error 类
Error类表示程序运行时遇到的系统级错误,通常这些错误无法通过程序代码捕获和恢复。常见的Error类型包括:
OutOfMemoryError:表示 JVM 无法分配足够的内存。StackOverflowError:表示栈内存溢出,通常是递归调用过深导致的。VirtualMachineError:表示 JVM 无法正常运行的错误。
这些Error是 JVM 内部引发的,程序一般无法处理,程序出现此类错误时,通常会终止执行。
4.Exception 类
Exception类表示程序运行过程中出现的异常情况。这些异常可以被程序捕获并处理。Exception类有两个重要的子类:
1.Checked Exception(检查时异常)
这类异常是程序可以预料的,并且必须显式处理。编译器要求你在代码中处理这些异常,要么用try-catch捕获它们,要么在方法签名中使用throws声明抛出异常。常见的Checked Exception包括:
IOException:文件或网络操作时可能发生的异常。SQLException:数据库操作时可能发生的异常。ClassNotFoundException:加载类时发生的异常。
2.Unchecked Exception(运行时异常)
这类异常通常是由程序错误引起的,编译器不要求你处理它们。这些异常通常是由逻辑错误引起的,比如访问一个空对象引用或数组越界。常见的Unchecked Exception包括:
NullPointerException(空指针异常):当应用程序试图在需要对象的地方使用 null 时,抛出该异常。ArrayIndexOutOfBoundsException(数组下标越界异常):访问数组时使用了无效索引。ArithmeticException(数学运算异常):数学运算错误(如除以零)。ClassCastException:类型转换错误。- NumberFormatException(数字格式不正确异常):当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常 =>使用异常我们可以确保输入是满足条件数字,
Unchecked Exception继承自RuntimeException,程序可以选择性地捕获这些异常。
4.异常处理
异常处理就是当异常发生时,对异常处理的方式。
方式:
(1)try-catch-finally
程序员在代码中捕获发生的异常,自行处理
处理机制:
try{ //可能有异常的代码 //如果异常没有发生,则顺序执行try的代码块,不会进入到catch. //如果没有发生异常catch代码块不执行 //如果异常发生了,则try块中异常发生后面的代码不会执行,将执行catch块中的语句,如果有finally,最后还需要执行finally里面的语句。 // }catch(Exception e){ //捕获到异常时,系统将异常封装成Exception 对象e,传递给catch //得到异常对象后,程序员自己处理 }finally{ //finally部分可写可不写 //不管try代码块是否有异常发生,始终要执行finally //所以,通常将释放资源的代码放在finally //可以进行 try-finally 配合使用, 这种用法相当于没有捕获异常,因此程序会直接崩掉。应用场景:就是执行一段代码,不管是否发生异常,都必须执行某个业务逻辑 }
(2)throws
1. 将发生的异常抛出,交给调用者(方法)来处理,最顶级的处理者就是JVM
2.try-catch-finally方式 与 throws方式只能二选一
3.如果程序没有使用try-catch-finally方式处理,程序默认是throws方式,这就是程序运行出错给出报错信息的原因
4.在方法声明中用throws语句可以声明抛出异常的列表(多个异常),throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。
public void f2() throws FileNotFoundException,NullPointerException,ArithmeticException { //创建了一个文件流对象 //解读: //1.这里的异常是一个FileNotFoundException 编译异常 //2.可以使用前面讲过的 try-catch-finally //3.可以使用throws抛出异常,让调用f2方法的调用者(方法)处理 //4.throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类,FileNotFoundException的父类是 Exception //5.throws 关键字后也可以是异常列表,即可以抛出多个异常 FileNotFoundException, NullPointerException, ArithmeticException FileInputStream fis = new FileInputstream("d://aa.txt"); }处理机制:
调用 调用 调用
JVM ——> main方法 ——> f1方法 ——> f2方法(抛出异常)
JVM <—— main方法 <—— f1方法 <—— f2方法
f2方法 可以抛出异常给 f1方法,f1方法此时有两个选择:1,使用try-catch-finally方式处理;2,把异常抛给调用f1方法的方法(main方法)。
main方法此时也是这两个选择,1,使用try-catch-finally方式处理;2,把异常抛给调用main方法的方法(JVM)。
异常到达JVM,处理:1,输出异常信息;2,退出程序
5.自定义异常
当程序中出现了某些“错误”,但该错误信息并没有在Throwable子类中描述处理,这个时候可以自己设计异常类,用于描述该错误信息。
(1)自定义异常步骤:
1.定义类:自定义异常类名 (程序员自己写) 继承 Exception 或 RuntimeException
如果继承Exception,属于编译异常
如果继承RuntimeException,属于运行异常
一般来说,自定义异常继承RuntimeException,即把自定义异常做成运行时异常,好处是我们可以使用默认的处理机制
eg:
public class CustomException { public static void main(string[] args)/*throws AgeException*/{ //要求范围在18-120 之间,否则抛出一个自定义异常 int age = 180; if(!(age >= 18 && age <= 120)){ //这里我们可以通过构造器,设置信息 throw new AgeException("年龄需要在 18~120之间"); } System.out.println("你的年龄范围正确。"); } } //自定义一个异常 class AgeException extends RuntimeException { public AgeException(string message){//构造器 super(message); } } //当前程序报错,控制台输出年龄需要在 18~120之间