JAVA 异常
Java中的异常(Exception)是程序运行时发生的不正常事件,分为检查异常(Checked Exception)和运行时异常(RuntimeException)。 异常处理机制包括捕获(try-catch)、声明(throws)和抛出(throw),确保程序在错误发生时仍能稳定运行或优雅终止。
原文链接:全网最完整Java学习笔记
基本介绍
什么是异常
Java中,异常(Exception)是指在程序执行过程中出现问题的一种情况,它可以中断程序的正常执行。异常通常是指由于错误、非法操作或意外情况导致的问题,比如文件未找到、数组越界、空指针引用等等。
异常机制:
当程序出现异常,程序安全的退出、处理完后继续执行的机制。Java是采用面向对象的方式来处理异常的。处理过程:
- 抛出异常:在执行一个方法时,如果发生异常,则这个方法生成代表该异常的一个对象,停止当前执行路径,并把异常对象提交给JRE。
 - 捕获异常:JRE得到该异常后,寻找相应的代码来处理该异常。JRE在方法的调用栈中查找,从生成异常的方法开始回溯,直到找到相应的异常处理代码为止
 
异常的分类
Error:错误类,无法通过代码解决,所以也不能处理。通常是由于系统资源不足或者JVM内部错误等导致的,需要通过修改环境或者配置等方式来解决。例如系统内存不够时抛出的内存溢出错误OutOfMemoryError,递归栈太深时抛出栈溢出错误StackOverflowError,这些通过代码没法解决,需要提升服务器配置,或者完全重构代码,换一种时间、空间复杂度更低的方案。Exception:异常类,程序可以处理的问题。它是一个类的实例,用于表示程序在运行过程中出现的意外情况。Java中所有的异常都是Throwable类的子类。Exception分为两种主要类型:运行时异常(RuntimeException及其子类)和非运行时异常。当一段代码有异常风险时应该通过try-catch或者throws进行处理,防止程序出现问题。例如往数据库插入记录时要捕获并打日志,从而对违反主键约束之类等问题进行排查。- **
RuntimeException**:运行时异常,编译不出错,运行出错,要try-catch处理。这类异常通常是由程序错误或者逻辑错误导致的,例如空指针引用、数组越界等。由于RuntimeException在编译时不受检查,所以需要在代码编写阶段考虑如何处理这类异常,以确保程序的健壮性。 - **非
RuntimeException**:编译时异常,编译时出错使程序不能运行,要try-catch处理或者throws抛出去。它是在编译时必须处理的异常类型,否则程序无法通过编译。这类异常常表示程序运行环境出现的异常情况,如IO异常IOException、数据库操作异常等。 
异常继承体系


详细介绍
Error类
Java中的Error类表示严重的错误情况,通常由虚拟机或其他底层自身的失效造成的,例如内存溢出、栈溢出,会导致应用程序终止。
通常程序不应该捕获Error,特定情境下可以捕获OutOfMemoryError处理内存溢出问题。使用try-catch-finally块捕获异常,并在finally块中进行资源清理、销毁、报告错误、终止应用程序等操作。
常见的错误Error包括:
- **
OutOfMemoryError**:内存溢出错误,通常是由于应用程序试图分配比可用内存更多的内存而导致。 - **
StackOverflowError**:堆栈溢出错误,发生在方法递归调用所需的堆栈空间已经用完的情况下。 - **
NoClassDefFoundError**:类未找到错误,通常是由于JVM无法找到应用程序尝试使用的某个类而导致。 - **
UnsatisfiedLinkError**:链接未满足错误,通常是由于调用本地方法时出现的链接问题而导致。 
Exception类
Exception的子类包括编译时异常和运行时异常:
编译时异常:在编译阶段就能检查出来的异常。例如FileNotFoundException、ClassNotFoundException、NoSuchFieldException、NoSuchMethodException、SQLException、ParseException(解析异常)等。如果程序要去处理这些异常,必须显式地使用try-catch语句块或者在方法定义中使用throws子句声明异常。
运行时异常:在运行时才会出现的异常。例如,NullPointerException、ArrayIndexOutOfBoundsException等。这些异常通常是由程序代码中的逻辑错误引起的,在编程时不会提示,运行时才报错。 因此,在编写程序时,通常无法处理这些异常,但是在程序开发完毕后,需要对这些异常进行一些处理,以防程序运行时崩溃。
常见的异常类
NullPointerException空指针异常;出现原因:访问未初始化的对象或不存在的对象。ClassNotFoundException类找不到异常;出现原因:类的名称和路径加载错误;NumberFormatException数字格式化异常;出现原因:转数字的字符型中包含非数字型字符。IndexOutOfBoundsException索引超出边界异常;出现原因:访问数组越界元素IllegalArgumentException不合法参数异常。出现原因:传递了不合法参数MethodArgumentNotValidException方法参数无效异常。出现原因:JSR303校验不通过ClassCastException类转换异常。出现原因:把对象强制转为没继承关系对象时报错。这个异常是在类加载过程的元数据验证阶段验证继承关系时报错。ArithmeticException算术异常。出现原因:除以0时。FileNotFoundException文件未找到异常NoSuchMethodException方法不存在异常IOException IO异常SocketExceptionSocket 异常
异常的两种处理方式
抛出异常
throws:- 位置:在方法签名中使用,其后跟着异常类名。
 - 特点:它表示方法可能会抛出异常,但并不保证一定会发生这个异常。
 - 数量:可以声明抛出多个异常,多个一场之间用逗号隔开
 - 处理异常:异常会传递给该方法的调用者来处理。
 
throw:- 位置:在方法体内使用,其后跟着异常对象名。
 - 特点:它表示方法内部一定已经发生了某种异常情况,并将这个异常抛出。
 - 数量:throw语句抛出的是一个异常实例,不是一个异常类,而且每次只能抛出一个异常实例
 - 处理异常:执行该关键字必定会抛出异常。异常由方法体内的语句来处理。
 
1  | public class Demo {  | 
throw 和 throws 的区别
throw:是真实抛出一个异常。
throws:是声明可能会抛出一个异常。
捕获异常(推荐)
使用 try 和 catch 关键字可以捕获异常,需要将try/catch 包围在异常可能发生的地方。
1  | // 2. try/catch语法:  | 
final、finally、finalize 的区别
final:是修饰符,如果修饰类,此类不能被继承;如果修饰方法和变量,此方法和此变量不能再被改变,只能使用。
finally:是 try{} catch{} finally{} 最后一部分,表示不论发生任何情况都会执行,finally 部分可以省略,但若 finally 部分存在,则一定会执行 finally 里面的代码。
finalize:是 Object 类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法。
try-catch-finally 中哪部分可省
try-catch-finally 其中 catch 和 finally 都可以被省略,但不能同时省略,也就是说有 try 时,必须后面跟一个 catch 或 finally。
try-catch-finally 在 catch 中 return 了,finally 是否还会执行
finally 一定会执行,即使是 catch 中 return 了,catch 中的 return 会等 finally 中的代码执行完之后,才会执行。
finally块最终执行:
- 只要程序不崩溃,finally块的代码都最终执行:即使try块、catch块中有return或throw语句,程序也会在执行finally块的代码后再return或throw。这里需要注意,禁止在finally块中使用return或throw。因为若finally块里也使用了return或throw等语句,finally块会终止方法,系统将不会跳回去执行try块、catch块里的任何代码。这将会导致try块、catch块中的return、throw语句失效
 - 如果程序终止,finally代码块不执行:
- 线程终止:如果一个线程在执行 try 语句块或者catch语句块时被打断interrupted,或者被终止killed,与其相对应的 finally 语句块可能不会执行。
 - 退出虚拟机:如果在try块或catch块中使用 
System.exit(1);来退出虚拟机,则finally块将失去执行的机会。 
 
自定义异常:继承异常类
有时候预定义的异常类不能完全满足业务需求,这时就需要自定义异常,以便于在程序出现问题时,可以及时抛出或处理
例如电商项目的库存不足异常、商品找不到异常,论坛项目中的“帖子找不到异常”、“无效评论异常”等等。
自定义异常的方法: 可以通过继承异常根类,或者它们的子类,重写父类的方法,以达到自定义异常的效果:
- 编译时异常类:需要继承 Exception 类。
 - 运行时异常类:需要继承 RuntimeException 类。
 





