目录
- 1- 什么是异常概述(What、Why)
- 1-1 什么是异常(What)
- 1-2 为什么要有异常处理机制(Why)
- 2- ⭐异常体系结构图-总览
- 2-1 分类
- 2-2 异常体系结构小结
- 3- 五大运行时异常
- 3-1 NullPointerException 空指针异常
- 3-2 ArithmeticException 算数异常
- 3-3 ArrayIndexOutOfBoundsException 数组下标越界异常
- 3-4 ClassCastException 异常
- 3-5 NumberFormatException 数字格式不正确异常
- 4- 编译异常
- 5- 异常处理机制
- 5-1 try-catch-finally 的处理机制
- try-catch 细节
- 5-2 throws 异常处理机制
- thorws 基本介绍
- throws 细节
- 5-3 throw 和 throws 的区别
- 6- 自定义异常
- 6-1 自定义异常步骤
- 小结
- 1- 什么是异常?Java 中的异常是如何分类的?
- 2- 常见的 Exception 有哪些?
- 3- throw 和 throws 有什么区别?
- 4- Error 和 Exception 有什么区别?
- 5- try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?
- 6- finally 一定会被执行吗?
- 7- 什么是受检异常(Checked Exception)和非受检异常(Unchecked Exception)?
- 8- 解释 try-catch-finally 语句的工作原理。
- 9- 三道异常处理经典题目,如果 try 中带有 return,finally 怎么执行?
1- 什么是异常概述(What、Why)
1-1 什么是异常(What)
基本概念
- 在 Java 语言中,将程序执行中发生的不正常的情况称为 “异常”。(开发过程中的语法错误和逻辑错误不是异常)
执行过程中的异常可以分为两类
- Error(错误):Java 虚拟机无法解决的严重问题。比如 JVM 系统内部错误、资源耗尽等情况。比如:StackOverflowError(栈溢出)和 OOM(out of memory),Error 是严重的错误,程序会崩溃。
- Exception:其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如空指针访问,试图读取不存在的文件,网络连接中断等等。
- Exception分为两大类:运行时异常(程序运行时,发生的异常)和 编译时异常(编译时,编译器检查出来的异常)。
通过一个例子,引出异常
public class Exception1 {
public static void main(String[] args) {
int num1 = 10;
int num2 = 0;
// 执行到这部分的时候,程序会不出现(抛出异常) ArithmeticException
// 当抛出异常之后,程序就退出崩溃了,下面的代码就不再执行
int res = num1/num2;
System.out.println("程序继续运行...");
}
}
- 针对上述问题,执行到
int res = num1/num2;
代码的时候,会出现异常。 - 问题在于出现了一个不算致命的问题,但会导致整个系统崩溃。因此 Java 设计者提供了 异常处理机制来解决这个问题。
1-2 为什么要有异常处理机制(Why)
- 如果程序员任务一段代码可能出现异常/问题,可以使用 try-catch 异常处理机制来解决。从而保证代码的健壮性。如果进行了异常处理,即使出现了异常,程序可以继续执行。
- 常见的异常处理机制如下:
public class Exception1 {
public static void main(String[] args) {
int num1 = 10;
int num2 = 0;
try{
int res = num1/num2;
}catch (Exception e){
// e.printStackTrace();
System.out.println(e.getMessage()); // 输出异常信息
}
System.out.println("程序继续运行...");
}
}
2- ⭐异常体系结构图-总览
2-1 分类
- 下图的内容需要记忆
- 编译异常(Checked 受检异常):是在 Java源程序 经过
javac.exe
转为字节码文件阶段遇到的异常。 - 运行异常(Unchecked 非受检异常):是在字节码文件在内存中加载、运行时类的时候出现的异常。
2-2 异常体系结构小结
异常分为两大类,运行时异常和编译时异常:
- 运行时异常(Unchecked 非受检异常):编译器不要求强制处置的异常。一般是指编程时的逻辑错误,是程序员应该避免其出现的异常。java.lang.RuntimeException类及它的子类都是运行时异常对于运行时异常,可以不作处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响。
- 举例:(比如除法操作,
nums1 = 10
、nums2 = 0
则nums1/nums2
可得到运行时异常)
- 举例:(比如除法操作,
- 编译时异常(Checked 受检异常):是在 Java源程序 经过
javac.exe
转为字节码文件阶段遇到的异常。
// 编译时异常举例
public class Exception02 {
public static void main(String[] args) {
// Throwable
FileInputStream fis;
try {
fis = new FileInputStream("d:\\aa.jpg");
int len;
while ((len = fis.read()) != -1) {
System.out.println(len);
}
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 在上述代码中,
FileInputStream
会报编译时异常,也就是 IDEA 工具会报错,必须立即处理的异常。
3- 五大运行时异常
常见的运行时异常包括
- ①
NullPointerException
:空指针异常 - ②
ArithmeticException
:数学运算异常 - ③
ArrayIndexOutOfBoundsException
:数组下标越界异常 - ④
ClassCastException
:类型转换异常 - ⑤
NumberFormatException
:数字格式不正确异常
3-1 NullPointerException 空指针异常
NullPointerException
空指针异常
- 当应用程序试图在需要对象的地方使用 null 时,抛出该异常,看案例演示。
public class NullPointerException_ {
public static void main(String[] args) {
String name = null;
// 在输出的时候会报空指针异常
System.out.println(name.length());
}
}
3-2 ArithmeticException 算数异常
- 比如出现 除以 0 的操作的时候就会出现算数异常
public class Exception1 {
public static void main(String[] args) {
int num1 = 10;
int num2 = 0;
// 执行到这部分的时候,程序会不出现(抛出异常) ArithmeticException
// 当抛出异常之后,程序就退出崩溃了,下面的代码就不再执行
int res = num1/num2;
System.out.println("程序继续运行...");
}
}
3-3 ArrayIndexOutOfBoundsException 数组下标越界异常
- 用非法的索引访问数组时候抛出的异常。如果索引为负数或者大于等于数组大小,则该索引非法。
public class Exception1 {
public static void main(String[] args) {
int[] nums = new int[4];
System.out.println(nums[4]);
}
}
3-4 ClassCastException 异常
- 当试图将对象强制转换为不是实例的子类时,抛出该异常。例如,以下代码将生成一个
ClassCastException
public class ClassCastException_ {
public static void main(String[] args) {
A b = new B(); // 向上转型
B b2 = (B)b; // 向下转型,这里是OK
C c2 = (C)b; // 这里抛出ClassCastException
}
}
class A {}
class B extends A {}
class C extends A {}
3-5 NumberFormatException 数字格式不正确异常
- 当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常 => 使用异常我们可以确保输入是满足条件数字。
- 例如在使用
Integer.parseInt("你好")
的时候,本来是想将字符串中的数字转为整型,但这个时候就会出现数字格式不正确的异常。
public class NumberFormatException_ {
public static void main(String[] args) {
String name = "你好呀";
// 将String 转成 int
int num = Integer.parseInt(name); // 抛出NumberFormatException
System.out.println(num); //
}
}
4- 编译异常
- 编译异常是指,在编译期间就必须处理的异常,否则代码不能通过编译。编译异常常常发生在操作网络、文件、数据库的时候。
常见的编译时异常
SQLException
:操作数据库时候,查询表可能发生的异常IOException
:操作文件时候发生的异常FileNotFoundException
:当操作一个不存在的文件时,发生异常ClassNotFoundException
:加载类,而文件不存在时,异常EOFException
:操作文件,到文件末尾发生异常IllegalArgumentException
:参数异常
5- 异常处理机制
异常处理机制就是在发生异常时,对异常处理的方式,主要有两种:
- ①
try-catch-finally
- 程序员在代码中捕获发生的异常,自行处理
- ②
throws
- 将发生的异常抛出,交给调用者(方法)来处理,最顶级的处理者就是 JVM
5-1 try-catch-finally 的处理机制
try-catch-finally 机制:
- try 中锁放的代码是有可能出现异常的代码,catch 主要是负责捕获异常。
- 当异常发生的时候,系统将异常封装给 Exception 的对象 e,传递给 catch,当 catch 得到异常对象之后,我们需要自己处理,如果没有发生异常的话 catch 中的代码是不会执行的。
- finally中的代码部分,无论是否有异常发生,始终是要执行 finally 代码快的(例如对资源释放的代码一般是放在 finally中)
- 如果没有 finally 也是允许的
try{
// 有可能有异常的代码
}catch(Exception e){
// 捕获到异常
// 1. 当异常发生时
// 2. 系统将异常封装给 Exception 的对象 e,传递给 catch
// 3. 得到异常对象之后,程序员自己处理
// 4. 注意,如果没有发生异常 catch 中的代码块不执行
}finally{
// 不管 try 中的代码块是否有异常发生,始终要执行 finally 代码块
// 通常将资源释放的代码,放在 finally 中
}
try-catch 细节
:::info
- 1) 如果异常发生了,则异常后面的代码不会执行,直接进入到 catch 块
- 2) 如果异常没有发生,则顺序执行 try 中代码,不会进入到 catch 中
- 3) 如果希望不管是否发生异常,都执行某段代码(比如关闭连接,释放资源等)则使用 -finally
- 4) 可以有多个 catch 语句,捕获不同的异常(进行不同的业务处理),要求父类异常在后,子类异常在前,比如(
Exception
在后,NullPointerException
在前),如果发生异常,只会匹配一个catch,案例演示 - 5) 可以进行 try-finally 配合使用,这种方法相当于没有捕获异常,因此程序会直接崩掉。应用场景,就是执行一段代码,不管是否发生异常,都必须执行某个业务逻辑
- 6) 如果在 catch 代码块中有一个临时变量 i,进行了 ++ 操作之后直接 return,此时不会直接返回会等到 finally 的代码执行完成之后才会返回。且 返回的 catch中临时变量结果。
:::
1) 如果异常发生了,则异常后面的代码不会执行,直接进入到 catch 块
- 以下代码块中
System.out.println("数字: " + a);
部分的内容是不会输出的
public class TryCatchDetail {
public static void main(String[] args) {
try {
String str = "你好";
int a = Integer.parseInt(str);
System.out.println("数字: " + a);
} catch (NumberFormatException e) {
System.out.println("异常信息=" + e.getMessage());
}
}
}
2) 如果异常没有发生,则顺序执行 try 中代码,不会进入到 catch 中
3) 如果希望不管是否发生异常,都执行某段代码(比如关闭连接,释放资源等)则使用 -finally
4) 可以有多个 catch 语句,捕获不同的异常(进行不同的业务处理),要求父类异常在后,子类异常在前,比如(**Exception**
** 在后,**NullPointerException**
在前),如果发生异常,只会匹配一个catch,案例演示**
- 如以下代码,其中 Person 对象有一个空指针异常,和一个算数异常。此时异常的排序需将子类排在前,父类排在后面。
public class TryCatchDetail02 {
public static void main(String[] args) {
try {
Person person = new Person();
person = null;
System.out.println(person.toString()); // NullPointerException
int n1 = 10;
int n2 = 0;
int res = n1 / n2; // ArithmeticException
} catch (NullPointerException e) {
System.out.println("空指针异常=" + e.getMessage());
} catch (ArithmeticException e) {
System.out.println("算术异常=" + e.getMessage());
} catch (Exception e) {
System.out.println(e.getMessage());
} finally {
System.out.println("finally代码块被执行");
}
}
}
class Person {
private String name = "jack";
public String getName(){
return name;
}
}
5) 可以进行 try-finally 配合使用,这种方法相当于没有捕获异常,因此程序会直接崩掉。应用场景,就是执行一段代码,不管是否发生异常,都必须执行某个业务逻辑
5-2 throws 异常处理机制
JVM 处理异常的机制是,直接输出异常信息 ——> 中断(退出)这个程序
- 在 Java 中如果对于非受检异常,也就是运行时异常,如果没有显示使用
try-catch
进行异常捕获,此时默认方法会带一个throws Exception
thorws 基本介绍
- 1)如果一个方法(中的语句执行时)可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应显示地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理。
- 2)在方法声明中用 throws 语句可以声明抛出异常的列表,throws 后面常类型可以是方法中产生的异常类型,也可以是它的父类。
public class Throws01 {
public static void main(String[] args) {
}
public void f2() throws FileNotFoundException {
// 创建了一个文件流对象
// 老韩解读:
// 1. 这里的异常是一个FileNotFoundException 编译异常
// 2. 使用前面讲过的 try-catch-finally
// 3. 使用throws,抛出异常,让调用f2方法的调用者(方法)处理
FileInputStream fis = new FileInputStream("d:/aa.txt");
}
}
throws 细节
:::info
throws 抛出异常介绍
- 1) 对于编译异常,程序必须处理,比如 try-catch 或者 throws
- 2) 对于运行时异常,程序如果没有处理,则默认的就是 throws 方式处理
- 3) 子类重写父类的方法时,对抛出异常的规定:子类重写的方法,所抛出的异常类型要么和父类抛出的异常一致,要么为父类抛出的异常的类型的子类型
- 4) 在throws过程中,如果有方法try-catch,就相当于处理异常,就可以不必 throws
:::
1) 对于编译异常,程序必须处理,比如 try-catch 或者 throws
2) 对于运行时异常,程序如果没有处理,则默认的就是 throws 方式处理
3) 子类重写父类的方法时,对抛出异常的规定:子类重写的方法,所抛出的异常类型要么和父类抛出的异常一致,要么为父类抛出的异常的类型的子类型
class Father { // 父类
public void method() throws RuntimeException {
}
}
class Son extends Father { // 子类
// 3. 子类重写父类的方法时,对抛出异常的规定:子类重写的方法,
// 所抛出的异常类型要么和父类抛出的异常一致,要么为父类抛出的异常类型的子类型
@Override
public void method() throws NullPointerException {
}
}
5-3 throw 和 throws 的区别
thorws
后面跟的是一个具体的异常类型throw
后面跟的是一个具体的异常对象
6- 自定义异常
基本概念
- 当程序中出现了某些“错误”,但该错误信息并没有在 Throwable 子类中描述处理,这个时候可以自己设计异常类,用于描述该错误信息。
6-1 自定义异常步骤
- 1)定义类:自定义异常类名(程序员自己写)继承 Exception 或 RuntimeException
- 2)如果继承 Exception ,属于编译异常
- 3)如果继承 RuntimeException ,属于运行异常(一般来说,继承 RuntimeException)
举例
- 当我们接收 Person 对象年龄时,要求范围在 18-120 之间,否则抛出一个自定义异常(要求继承RuntimeException),并给出提示信息。
:::info
自定义异常
- 一般是继承
**RuntimeException**
类,之后通过构造器方法实现自定义异常的信息
:::
public class CustomException {
public static void main(String[] args) {
int age = 80;
// 要求范围在 18 - 120 之间,否则抛出一个自定义异常
if (!(age >= 18 && age <= 120)) {
// 通过构造器设置自定义异常信息
throw new AgeException("年龄需要在 18~120之间");
}
System.out.println("你的年龄范围正确。");
}
}
// 自定义一个异常
class AgeException extends RuntimeException {
public AgeException(String message) { // 构造器
super(message);
}
}
小结
1- 什么是异常?Java 中的异常是如何分类的?
Java基础异常
分析
- Java异常
- 思路:Throwable接口有两个子类,分别是 Error 和 Exception。
- 关键字:Throwable
知识点详解
- Java中的异常都来自一个接口 Throwable,其中有两个主要的子类。
1- 谈论 Throwable、Exception、Error 三者的关系
- 一个是 Exception、一个是 Error
Error
一般是虚拟机异常,是程序无法干预的一种错误,这些异常发生时,Java 虚拟机(JVM)一般会选择线程终止。常见的有StackOverFlow
、OutOfMemory
Exception
是 Java 的一个异常类,Exception
下的异常主要分为两类,运行时异常和编译时异常。
2- 谈论 Exception 下的分类
Exception类下的异常主要分为两类
- 运行时异常(Unchecked 非受检异常):编译器不要求强制处置的异常。一般是指编程时的逻辑错误,是程序员应该避免其出现的异常。java.lang.RuntimeException 类及它的子类都是运行时异常对于运行时异常,可以不作处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响。
- 举例:(比如除法操作,
nums1 = 10
、nums2 = 0
则nums1/nums2
可得到运行时异常)
- 举例:(比如除法操作,
- 编译时异常(Checked 受检异常):是在 Java源程序 经过
javac.exe
转为字节码文件阶段遇到的异常。
回答
:::info
Java中的异常主要都来自于一个 Throwable 接口
- ①介绍 Error 和 Exception:Throwable 接口下主要有两个类,分别是 Error 和 Exception
**Error**
指的是虚拟机异常,是程序无法干预的一种错误。这些异常发生时,Java 虚拟机(JVM)一般会选择线程终止。常见的有StackOverFlow
、OutOfMemory
。**Exception**
异常是程序本身可以捕获并处理的异常。
- ② Exception 异常分类,主要分为两种
- 运行时异常(Unchecked 非受检异常):运行时异常,一般是在 Java 运行的过程中由于编程的逻辑错误而导致的异常,是可以手动处理避免的。
java.lang.RuntimeException
类及它的子类都是运行时异常对于运行时异常,可以不作处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响。 - 编译时异常(Checked 受检异常):是在 Java源程序 经过
javac.exe
转为字节码文件阶段遇到的异常。这类异常常见的就是在我们写代码过程中 IDEA 会给出的提示,也就是 Java 程序在运行前需要解决的异常,不然 Java 程序不能编译执行。
- 运行时异常(Unchecked 非受检异常):运行时异常,一般是在 Java 运行的过程中由于编程的逻辑错误而导致的异常,是可以手动处理避免的。
常见的运行时异常
- ①
NullPointerException
:空指针异常 - ②
ArithmeticException
:数学运算异常 - ③
ArrayIndexOutOfBoundsException
:数组下标越界异常 - ④
ClassCastException
:类型转换异常 - ⑤
NumberFormatException
:数字格式不正确异常
常见的编译时异常
SQLException
:操作数据库时候,查询表可能发生的异常IOException
:操作文件时候发生的异常FileNotFoundException
:当操作一个不存在的文件时,发生异常ClassNotFoundException
:加载类,而文件不存在时,异常EOFException
:操作文件,到文件末尾发生异常IllegalArgumentException
:参数异常
:::
2- 常见的 Exception 有哪些?
Java基础异常
分析
- Java异常
知识点详解
程序本事可以捕获并且处理的异常就是 Exception
异常,Exception 又分为两类,一种是运行时异常一种是编译时异常
运行时异常
- 都是
RuntimeException
类及其子类异常,如NullPointerException
(空指针异常)、IndexOutBoundsException
(下标越界异常)等,这些异常不是受检异常,程序可以选择捕获处理也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。 - 运行时异常的特点是 Java 编译器不回去检查它,也就是说,当程序中出现这类异常,即使没有用
try-catch
捕获,也没有使用throws
语句抛出它,也会编译通过。
非运行时异常(编译异常)
- 是
RuntimeException
以外的异常,类型上都属于 Exception 类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如 IOException、SQLException 等以及用户自定义的Exception异常,一般情况下不自定义检查异常。
回答
:::info
其中 **Exception**
异常又划分为 编译时异常和运行时异常两种
- 运行时异常:也就是
**RutimeException**
下的异常,这种异常可以通过 throws 或者 try-catch 的方式手动处理,这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。常见的异常有NullPointerException
(空指针异常)、IndexOutBoundsException
(下标越界异常)等。 - **非运行时异常(编译异常):**也就是
**RutimeException**
以外的异常,类型上都属于 Exception 类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如**IOException**
、**SQLException**
等以及用户自定义的**Exception**
异常,一般情况下不自定义检查异常。
常见的运行时异常
- ①
NullPointerException
:空指针异常 - ②
ArithmeticException
:数学运算异常 - ③
ArrayIndexOutOfBoundsException
:数组下标越界异常 - ④
ClassCastException
:类型转换异常 - ⑤
NumberFormatException
:数字格式不正确异常
常见的编译时异常
SQLException
:操作数据库时候,查询表可能发生的异常IOException
:操作文件时候发生的异常FileNotFoundException
:当操作一个不存在的文件时,发生异常ClassNotFoundException
:加载类,而文件不存在时,异常EOFException
:操作文件,到文件末尾发生异常IllegalArgumentException
:参数异常
:::
3- throw 和 throws 有什么区别?
Java基础异常
分析
- Java异常
知识点详解
thorws
后面跟的是一个具体的异常类型throw
后面跟的是一个具体的异常对象
回答
:::info
- throw:用于抛出一个具体的异常对象。
- throws:后面跟的是一个具体的异常类型,用于声明该方法可能抛出的异常。子类方法抛出的异常范围更小,或者根本不抛出异常。
:::
4- Error 和 Exception 有什么区别?
Java基础异常
分析
- Java异常
知识点详解
**Error**
:JVM 无法解决的严重问题,如栈溢出 StackOverflowError、内存溢出 OOM 等。程序无法处理的错误。**Exception**
:其他因为编程错误或偶然的外在因素导致的一般性问题,可以在代码中进行处理。如:空指针异常、数组下标越界等。
回答
:::info
**Error**
:JVM 无法解决的严重问题,如栈溢出 StackOverflowError、内存溢出 OOM 等。程序无法处理的错误。**Exception**
:其他因为编程错误或偶然的外在因素导致的一般性问题,可以在代码中进行处理。如:空指针异常、数组下标越界等。
:::
5- try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?
Java基础异常
分析
- Java异常
知识点详解
- 会,当 try 和 catch 中有 return 时,finally 仍然会执行。
回答
:::info
- 会,当 try 和 catch 中有 return 时,finally 仍然会执行。
:::
6- finally 一定会被执行吗?
Java基础异常
**分析 **
- Java异常
知识点详解
不一定,有以下两种情况 finally 不会被执行:
- ① 程序未执行到 try 代码块,(比如在执行 finally 之前程序就 exit 退出了)
try {
System.out.println("Try to do something");
throw new RuntimeException("RuntimeException");
} catch (Exception e) {
System.out.println("Catch Exception -> " + e.getMessage());
// 终止当前正在运行的Java虚拟机
System.exit(1);
} finally {
System.out.println("Finally");
}
- ② 当一个线程在执行 try 语句块或者 catch 语句块时被打断(Interrupted)或者被终止(Killed),与其相对应的 finally 语句块可能不会执行。还有更极端的情况,就是在线程运行 try 语句块或者 catch 语句块时,突然死机或者断电,finally 语句块肯定不会执行了。
回答
:::info
不一定,有以下两种情况 finally 不会被执行:
- ① 程序未执行到 try 代码块,(比如在执行 finally 之前程序就 exit 退出了)
- ② 当一个线程在执行 try 语句块或者 catch 语句块时被打断(Interrupted)或者被终止(Killed),与其相对应的 finally 语句块可能不会执行。还有更极端的情况,就是在线程运行 try 语句块或者 catch 语句块时,突然死机或者断电,finally 语句块肯定不会执行了。
:::
7- 什么是受检异常(Checked Exception)和非受检异常(Unchecked Exception)?
Java基础异常
**分析 **
- Java异常
知识点详解
其中 **Exception**
异常又划分为 编译时异常和运行时异常两种
- 运行时异常(非受检异常):也就是
**RutimeException**
下的异常,这种异常可以通过 throws 或者 try-catch 的方式手动处理,这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。常见的异常有NullPointerException
(空指针异常)、IndexOutBoundsException
(下标越界异常)等。 - **非运行时异常(受检异常):**也就是
**RutimeException**
以外的异常,类型上都属于 Exception 类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如**IOException**
、**SQLException**
等以及用户自定义的**Exception**
异常,一般情况下不自定义检查异常。
回答
:::info
其中 **Exception**
异常又划分为 编译时异常和运行时异常两种
- 运行时异常(非受检异常):也就是
**RutimeException**
下的异常,这种异常可以通过 throws 或者 try-catch 的方式手动处理,这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。常见的异常有NullPointerException
(空指针异常)、IndexOutBoundsException
(下标越界异常)等。 - **非运行时异常(受检异常):**也就是
**RutimeException**
以外的异常,类型上都属于 Exception 类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如**IOException**
、**SQLException**
等以及用户自定义的**Exception**
异常,一般情况下不自定义检查异常。
:::
8- 解释 try-catch-finally 语句的工作原理。
Java基础异常
**分析 **
- Java异常
知识点详解
try 部分的代码
- 其中 try 中放的代码是可能出现异常的代码块。catch 主要是负责捕获异常。
catch部分
- 如果 try 部分的代码发生了异常,catch 就负责捕获信息,将异常封装为 Exception 对象。当 catch 得到异常对象之后,我们需要自己处理,如果没有发生异常的话 catch 中的代码是不会执行的。
finally部分
- finally中的代码部分,无论是否有异常发生,始终是要执行 finally 代码快的(例如对资源释放的代码一般是放在 finally中)如果没有 finally 也是允许的。
try-cath细节
- 1) 如果异常发生了,则异常后面的代码不会执行,直接进入到 catch 块
- 2) 如果异常没有发生,则顺序执行 try 中代码,不会进入到 catch 中
- 3) 如果希望不管是否发生异常,都执行某段代码(比如关闭连接,释放资源等)则使用 -finally
- 4) 可以有多个 catch 语句,捕获不同的异常(进行不同的业务处理),要求父类异常在后,子类异常在前,比如(
Exception
在后,NullPointerException
在前),如果发生异常,只会匹配一个catch,案例演示 - 5) 可以进行 try-finally 配合使用,这种方法相当于没有捕获异常,因此程序会直接崩掉。应用场景,就是执行一段代码,不管是否发生异常,都必须执行某个业务逻辑
- 6) 如果在 catch 代码块中有一个临时变量 i,进行了 ++ 操作之后直接 return,此时不会直接返回会等到 finally 的代码执行完成之后才会返回。且 返回的 catch中临时变量结果。
回答
:::info
try 部分的代码
- 其中 try 中放的代码是可能出现异常的代码块。catch 主要是负责捕获异常。
catch部分
- 如果 try 部分的代码发生了异常,catch 就负责捕获信息,将异常封装为 Exception 对象。当 catch 得到异常对象之后,我们需要自己处理,如果没有发生异常的话 catch 中的代码是不会执行的。
finally部分
- finally中的代码部分,无论是否有异常发生,始终是要执行 finally 代码快的(例如对资源释放的代码一般是放在 finally中)如果没有 finally 也是允许的。
try-cath细节
- 1) 如果异常发生了,则异常后面的代码不会执行,直接进入到 catch 块
- 2) 如果异常没有发生,则顺序执行 try 中代码,不会进入到 catch 中
- 3) 如果希望不管是否发生异常,都执行某段代码(比如关闭连接,释放资源等)则使用 -finally
- 4) 可以有多个 catch 语句,捕获不同的异常(进行不同的业务处理),要求父类异常在后,子类异常在前,比如(
Exception
在后,NullPointerException
在前),如果发生异常,只会匹配一个catch,案例演示 - 5) 可以进行 try-finally 配合使用,这种方法相当于没有捕获异常,因此程序会直接崩掉。应用场景,就是执行一段代码,不管是否发生异常,都必须执行某个业务逻辑
- 6) 如果在 catch 代码块中有一个临时变量 i,进行了 ++ 操作之后直接 return,此时不会直接返回会等到 finally 的代码执行完成之后才会返回。且 返回的 catch中临时变量结果。
:::
9- 三道异常处理经典题目,如果 try 中带有 return,finally 怎么执行?
Java基础异常
**分析 **
- Java异常
知识点详解
public class TryDemo {
public static void main(String[] args) {
System.out.println(test());
}
public static int test() {
try {
return 1;
} catch (Exception e) {
return 2;
} finally {
System.out.print("3");
}
}
}
- 执行结果:
31
- 解析:
try
、catch
、finally
的基础用法,在return
前会先执行finally
的语句块,所以是先输出finally
里面的 3,再输出1。
public class TryDemo {
public static void main(String[] args) {
System.out.println(test1());
}
public static int test1() {
try {
return 2;
} finally {
return 3;
}
}
}
- 执行结果:
3
- 解析:try 返回前先执行 finally,如果 finally 里面不按套路出牌,直接 return 了,自然也就不会走到 try 里面的 return了。
public class TryDemo {
public static void main(String[] args) {
System.out.println(test1());
}
public static int test1() {
int i = 0;
try {
i = 2;
return i;
} finally {
i = 3;
}
}
}
- 执行结果:
2
- 解析:这段不应该返回 3 吗,其实在实际执行 finally 之前, JVM 会先将 i 的结果暂存起来,然后 finally 执行完成之后,会返回之前存储的结果,而不是返回 i ,所以 i 已经被修改为 3,最终返回的还是之前暂存的结果 2。
回答
:::info
- 解析:
try
、catch
、finally
的基础用法,在return
前会先执行finally
的语句块,所以是先输出finally
里面的 3,再输出1。
:::