目录
3. Java中一切都是类,异常其实也是类,因此Catch代码块只能捕获相应的异常"类型"
5. 关于finally代码块:无论是否有异常产生,最终都会执行finally代码块中的代码
a. RuntimeException(运行时异常,编译阶段不报错,运行时出错)。
引言
异常:程序没按照预计的结果运行,在运行的过程中发生了"错误"。
//除0异常 System.out.println(10 / 0); //运行错误 Exception in thread "main" java.lang.ArithmeticException: / by zero at ExceptionTest.main(ExceptionTest.java:9)
// 数组越界异常 int[] data = new int[]{1, 3, 5}; System.out.println(data[10]); //运行错误 Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 10 at ExceptionTest.main(ExceptionTest.java:14)
基本语法
异常的基本语法:
try{ //可能会产生异常的代码,除0,数组越界,空指针等 }[catch 可能出现异常的类型异常对象引用] { //出现异常以后如何处理 }[finally] { //异常的出口,最终会执行的代码块 //无论是否有异常产生都会执行的代码块,资源类的释放,文件的关闭等 }
1. 程序中不处理异常的情况
int[] date = {1,2,3}; System.out.println("before..."); System.out.println(date[100]); //发生异常之后的代码就不再执行 System.out.println("after..."); //输出结果 before... Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 100 at ExceptionTest.main(ExceptionTest.java:18)
发生异常之后的代码就不再执行
2. 使用try ..catch ..处理异常
int[] date = {1,2,3}; System.out.println("before..."); try { //可能会产生异常的代码 System.out.println(date[100]); System.out.println("try中的其他代码块"); } catch (ArrayIndexOutOfBoundsException e) { System.out.println("异常产生了"); } System.out.println("after..."); //输出结果 before... 异常产生了 after...
一旦try中出现异常,那么try 代码块中的程序就不会继续执行,而是交给catch中的代码来执行。catch执行完毕会继续往下执行。
3. Java中一切都是类,异常其实也是类,因此Catch代码块只能捕获相应的异常"类型"
数组越界异常
此时代码出错的原因在于空指针异常,不属于数组越界异常,因此catch代码块无法处理,所以需要多个catch代码块。
空指针异常被捕获。
有一个异常类是所有异常类的父类——Exception类
我们如果catch块中捕获的是Exception这个类型,就可以接收到所有异常类型。(不推荐)public static void main(String[] args) { int[] date = {1, 2, 3}; date = null; System.out.println("before..."); try { //可能会产生异常的代码 System.out.println(date[1]); System.out.println("try中的其他代码块"); } catch (Exception e) { System.out.println("异常产生了"); } System.out.println("after..."); } //输出结果 before... 异常产生了 after...
若此时明确知道try中可能产生的异常类型,如:数组越界,空指针,catch捕获明确的相关类型。
若此时不太清楚可能产生哪些异常,就使用Exception共同的父类。所有异常的子类都会向上转型变为Exception的引用。
4. 关于错误"堆栈"信息
在Java中其实出现问题是很好解决,异常的错误信息非常完善,到底在哪一行出了怎样的错误,说的非常清楚。
输出程序出现异常的位置以及原因,就调用异常对象的printStackTrace()方法
5. 关于finally代码块:无论是否有异常产生,最终都会执行finally代码块中的代码
5.1 有异常
public static void main(String[] args) { int[] date = {1, 2, 3}; try { System.out.println(date[100]); } catch (ArrayIndexOutOfBoundsException e) { e.printStackTrace(); } finally { System.out.println("finally代码块"); } System.out.println("异常体系之后的代码"); } //输出结果 java.lang.ArrayIndexOutOfBoundsException: 100 at exception_test.FinallyTest.main(FinallyTest.java:13) finally代码块 异常体系之后的代码
5.2 无异常
public static void main(String[] args) { int[] date = {1, 2, 3}; try { System.out.println(date[1]); } catch (ArrayIndexOutOfBoundsException e) { e.printStackTrace(); } finally { System.out.println("finally代码块"); } System.out.println("异常体系之后的代码"); } //输出结果 2 finally代码块 异常体系之后的代码
一般来说资源的释放,方法的关闭操作都在finally代码块中。
比如关闭数据库的连接,关闭文件的操作都在finally代码块中,无论是否有异常产生,都能保证资源会正确释放。
不要在finally代码块中写返回值。
问题:求返回值?
public static void main(String[] args) { int ret = test(); System.out.println(ret); } private static int test() { try { int[] date = {1, 2, 3}; date[100] = 10; return 10; } catch (ArrayIndexOutOfBoundsException e) { e.printStackTrace(); return 20; } finally { System.out.println("finally代码块"); return 30; } }
答:finally是最终都会执行的代码块,若finally中存在返回值,会覆盖掉try或者catch的返回值。
去掉finally的return语句
6. 异常的处理流程
异常处理流程
1. 程序先执行try中的代码
2. 如果try中的代码出现异常,就会结束try 中的代码,看和catch 中的异常类型是否匹配。a. 如果找到匹配的异常类型,就会执行catch中的代码。
b. 如果没有找到匹配的异常类型,就会将异常向上传递到上层调用者。
3. 无论是否找到匹配的异常类型。 finally 中的代码都会被执行到(在该方法结束之前执行)。如果上层调用者也没有处理的了异常,就继续向上传递。
4. 一直到 main方法也没有合适的代码处理异常,就会交给JVM来进行处理,此时程序就会异常终止。
7. throws和throw关键字——人为抛出异常
throws:用在方法声明上,表示该方法可能会产生的异常类型,但是本方法中不处理该异常。若异常产生抛回给调用者。
throw:用在方法内部,表示人为产生异常对象并抛出。
异常对象的产生都是发生异常后由JVM产生的,若需要人为产生异常对象,就使用throw关键字。
7.1 throws的使用
7.2 throw的使用
关于这两个关键字的使用,需要结合自定义的异常类来使用。
异常体系:JDK内部异常的继承关系
Java中的异常分为两大类,一类称之为"受查异常",另—类称为"非受查异常"。
1. 非受查异常
上图中蓝色部分的类——非受查异常
RuntimeException以及其子类包括Error及其子类称之为非受查异常,编译阶段可以不显示进行异常处理(try...catch/throws抛出)。
a. RuntimeException(运行时异常,编译阶段不报错,运行时出错)。
其子类有:
ArrayIndexOfBoundsException——数组越界异常;
NullPointerException——空指针异常;
ClassCastException——类型转换异常。
b. Error——程序内部错误。
一般来说,出现这种错误,程序没法再正常执行下去的,只能退出程序。
OutofMemoryError——堆内存溢出错误、StackOverflowError——栈溢出错误。
2. 受查异常
除了这些非受查异常以外的其他异常类属于受查异常,必须在编译阶段显示进行异常的处理,否则编译就会出错。上图中红色部分的类,受查异常。
受查异常,调用者就必须显示进行异常的处理。
显示处理:1. 进行try..catch..捕获这个异常
2. 调用者也使用throws向上抛出异常
3. 自定义异常
JDK内部已经帮我们提前定义好了很多的异常类,但是在某些业务场景下,出现的错误需要我们自定义异常类(用户登录的时候,用户名不对,密码不对,这种错误就需要我们来自定义异常类)。
自定义异常类操作简单,只需要继承相关的两个父类就可以。
若希望这个异常必须显示处理——继承Exception父类。
若这个异常不需要显示处理——继承RunTimeException父类。package exception_test; import java.util.Scanner; public class MyExceptionTest { private static String USER_NAME = "小明"; private static String PASSWORD = "123"; public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.println("请输入用户名:"); String userName = scanner.nextLine(); System.out.println("请输入密码:"); String pass = scanner.nextLine(); if (!userName.equals(USER_NAME)) { //用户名错误,抛出异常 throw new UserNameException("用户名错误"); } if (!pass.equals(PASSWORD)) { //密码错误,抛出异常 throw new PassWordException("密码错误"); } } } class UserNameException extends RuntimeException { public UserNameException(String msg) { super(msg); } } class PassWordException extends RuntimeException { public PassWordException(String msg) { super(msg); } }
异常体系:
1. try...catch...finally的使用流程
2. 受查和非受查异常的关系以及常见异常
运行时异常就是非受查异常的一种,空指针、数组越界、类型转换。IOException就是受查异常的一种。
3. throws和throw关键字的使用以及自定义异常类