目录
一、Java异常体系结构
Error
Exception
受检查异常
未受检查异常
二、异常处理的方式
1.try-catch块异常处理
注意
2.Throws异常处理
使用场景
注意
三、异常产生的方式
引言
Java异常处理是Java语言用于处理程序在执行过程中出现的错误或者异常的机制。通过异常处理,程序可以更加健壮,能够在遇到问题时进行适当处理,而不是直接崩溃。Java异常处理主要依赖于try、catch、finally和 throw/throws 关键字。
一、Java异常体系结构
Thorwable类是所有异常和错误的父类(超类),有两个字类Error和Exception,分别表示错误和异常(错误一般是程序员无法解决的问题)。
其中,异常类Exception又分为运行时异常(RuntimeException)和非运行时异常。(也可以分类为不检查异常Unchecked Exception 和检查异常Checked Exception)。
Error
Error表示严重的问题,通常是程序无法恢复的问题。
这些问题通常是虚拟机自身的问题或者其他系统问题,如内存不足,类加载,OutOfMemoryError,ThreadDeath等问题。这些异常发生时,Java虚拟机一般会选择线程终止。
Exception
Exception是程序中可能会遇到的可捕获和处理的非致命性问题。Exception分为受检查异常(Checked Exception)和未受检查异常(Unchecked Exception)。
受检查异常
需要在代码中明确声明和处理,如IOException、FileNotFoundException等。编译器会强制要求程序员处理这类异常,要么使用try-catch块捕获,要么在方法签名中使用throws关键字声明抛出。
未受检查异常
通常是运行时异常,继承自RuntimeException类,如NullPointerException、IndexOutOfBoundsException等。这类异常不需要显式捕获和处理,因为它们通常表示程序逻辑错误,应该通过改进程序逻辑来避免。
二、异常处理的方式
Java异常处理涉及到五个关键字,分别是:try、catch、finally、throw、throws。
try:用于包裹可能会抛出异常的代码块。
catch:用于捕获try代码块中抛出的异常,并进行处理。
finally:无论是否发生异常,finally代码块中的代码都会被执行。通常用于释放资源,如关闭文件,数据库连接等等。
throw:用于显示的抛出一个异常。
throws:在方法签名中使用,声明该方法可能会抛出的异常。
1.try-catch块异常处理
示例:
java">import java.util.InputMismatchException;
import java.util.Scanner;public class ExceptionTest {public static void main(String[] args) {Scanner scanner=new Scanner(System.in);try {int a=scanner.nextInt();//输入!发生异常,异常后代码不执行,跳转到catch块。System.out.println(a);}catch (InputMismatchException i){//如果没有异常发生,则顺序执行try块,不会进入catch。System.out.println("异常:"+i.getMessage());}finally {//如果希望不管是否发生异常,都执行某段代码。System.out.println("finally 代码块执行");}}
}
运行结果:
java">!
异常:null
finally 代码块执行
注意
1.当有多个catch块用于捕获不同的异常(进行不同的业务),要求父类在后,子类在前,同级别随意。
java">import java.util.InputMismatchException;
import java.util.Scanner;public class ExceptionTest {public static void main(String[] args) {Scanner scanner=new Scanner(System.in);try {int[] array={1,2,3,4};for (int i = 0; i <=array.length ; i++) {System.out.println(array[i]);}}catch (ArrayIndexOutOfBoundsException a){System.out.println("ArrayIndexOutOfBoundsException:"+a.getMessage());}catch (NullPointerException n){System.out.println("NullPointerException:"+n.getMessage());}catch (Exception e){System.out.println("Exception:"+e.getMessage());}finally {System.out.println("finally 代码块执行");}}
}
运行结果:
2.如果catch块没有捕获到异常,如果这些异常没有被捕获,它们将会一直传递到程序的顶层,并且通常会导致程序终止,同时在控制台输出异常的堆栈跟踪信息。
java">public class ExceptionTest {public static void main(String[] args) {try {int[] array={1,2,3,4};for (int i = 0; i <=array.length ; i++) {System.out.println(array[i]);}}catch (NullPointerException a){System.out.println("ArrayIndexOutOfBoundsException:"+a.getMessage());}finally {System.out.println("finally 代码块执行");}}
}
运行结果:
3.try - finally 可以配合使用,这种用法相当于没有捕获异常。应用场景:执行一段代码,不管是否发生异常,都必须执行某个业务逻辑。
4.如果catch块中和finally中都有return代码,该返回那个呢?
在Java中,如果catch
块和finally
块中都有return
语句,那么finally
块中的return
语句将会被执行,并且它的返回值将会覆盖catch
块中的返回值。
这意味着,即使catch
块中有一个return
语句,如果在finally
块中也存在一个return
语句,那么最终返回给调用者的值将是finally
块中return
语句所指定的值。
java">public class ReturnInCatchFinally {public static void main(String[] args) {System.out.println(testMethod());}public static int testMethod() {try {throw new Exception("Test Exception");} catch (Exception e) {System.out.println("Caught an exception");return 1; // 这个return值会被finally块中的return覆盖} finally {System.out.println("Inside finally");return 2; // 这个return值会最终被返回}}
}
2.Throws异常处理
如果一个方法中的语句执行时,可能会产生某种异常,但是不能确定如何处理这种异常,则此方法应该显示地声明抛出异常,该方法不对其进行处理,而由该方法的调用者负责处理。如果所有方法都层层上抛获取的代码,最终JVM会进行处理,处理也很简单,就是打印异常消息和堆栈消息。
使用场景
1.方法内可能抛出的受检异常(在编译时就需要处理的异常)。如果方法内部可能会抛出受检异常,但该方法又不希望或无法自行处理这些异常,那么可以在方法签名中使用throws
关键字声明这些异常。
2.自定义异常。当用户自定义了自己的异常,如果某个方法可能会抛出这些自定义异常(throw),也可以使用throws关键字在方法中签名。
java">import java.util.InputMismatchException;
import java.util.Scanner;public class ExceptionTest {public static void main(String[] args){try {a();}catch (Exception e){e.printStackTrace();}System.out.println(111);}public static void a()throws RuntimeException,Exception{Scanner scanner=new Scanner(System.in);int a=scanner.nextInt();}
}
运行结果:
注意
子类重写的方法抛出的异常类型不大于(<=)父类被重写方法抛出的异常类型 。
子类重写的方法不能:
- 声明抛出新的、与父类方法抛出异常无关的异常类型。
- 声明抛出比父类方法更宽泛的异常类型(即父类异常类型的超类)。
三、异常产生的方式
1.系统自动生成的异常对象
2.手动生成异常对象并抛出(throw)
java">class StudentTest {public static void main(String[] args) {try {Student s = new Student();//数据非法,需要处理异常对象//调用此方法进入到catch代码块中s.regist(-1001);} catch (Exception e) {//控制台输出:您输入的数据非法System.out.println(e.getMessage());}}
}class Student{private int id;public void regist(int id) throws Exception {if (id > 0){this.id = id;}else {//手动抛出异常对象throw new Exception("您输入的数据非法!");}}
}
面试题:throw和throws区别?
throw表示抛出一个异常对象,生成异常对象的过程。声明在方法体内
throws属于异常处理的一种方式,声明在方法的声明处
一个是生成异常,一个是处理异常。