异常处理就是当异常发生时,对异常处理的方式。
(1) try-catch-finally 处理机制
try {
代码/可能有异常
} catch(Exception e) {
捕获到异常
1、当异常发生时
2、系统将异常封装成 Exception 对象e,传递给catch
3、得到异常对象后,程序员自己处理
4、注意,如果没有发生异常,catch代码块不执行
} finally {
1、不管try代码块是否有异常发生,都要执行finally
2、所以,通常将释放资源的代码放在finally
}
(2)throws 处理机制图
JVM 调用main方法,main调用 f1,f1 中 调用 f2,f2 抛出(发生)异常。
f2 抛出异常可以使用 ① try-catch-finally ② throws 机制,扔出去,f2 说它不管,抛给 f1(因为是 f1 调用它的),
f1也有两种选择,它也可以继续丢出去 throws。
扔给JVM,处理异常非常暴力,直接①输出异常信息 ②退出程序。
(1)try-catch-finally 和 throws 二选一
(2)如果程序员,没有显式处理异常,默认throws
try {
可疑代码
将异常生成对应的异常对象,传递给catch块
} catch(异常){
对异常的处理
}
没有finally也是可以滴
CTRL + ALT + T
【举例A】
public static void main(String[] args) {
try {
String str = "XXXXXXX";
System.out.println("=========");
int a = Integer.parseInt(str);
System.out.println("+++++++++");
System.out.println("数字:" + a);
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
int a = Integer.parseInt(str);这句话会报错,直接跳到 catch块
【举例B】
public class TryCatchDetail02 {
public static void main(String[] args) {
try {
Person person = new Person();
person = null;
System.out.println(person.getName());//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) {
//Exception是 NullPointerException 和ArithmeticException的父类
System.out.println(e.getMessage());
} finally {
}
}
}
class Person {
private String name = "jack";
public String getName() {
return name;
}
}
public class Throws01 {
public static void main(String[] args) {
}
public void f2() throws FileNotFoundException {
// 创建了一个文件对象
FileInputstream fis = new FileInputStream("d ://aa.txt");
}
}
说明:
① 这里的异常:编译异常 FileNotFoundException(后面学到 IO)
② 使用throws,【throws FileNotFoundException】 抛出异常,让调用f2()的方法处理。
③ throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。解释: FileNotFoundException的父类是Exception,也可以写 【throws Exception】
④ 在方法声明中用throws语句可以声明抛出异常的列表
【throws FileNotFoundException,NullPointerException, ArithmeticException】
【案例A】
子类重写的方法,所抛出的异常类型和父类抛出的异常一致
class Father {
public void method() throws RuntimeException {
}
}
class Son extends Father {
@Override
public void method() throws RuntimeException {
}
}
这样也可以,子类重写的方法,所抛出的异常类型为父类抛出的异常的类型的子类型
class Father {
public void method() throws Exception {
}
}
class Son extends Father {
@Override
public void method() throws RuntimeException {
}
}
【案例B】
f1 和 f3 都在相同的类里,且都是静态方法,按理来说可以直接调用。怎么在 f1 中调用 f3 报错??
分析:
FileNotFoundException是编译异常,f3 会抛出异常给调用它的 f1,但是在 f1 中没有处理。
因为f3()方法抛出的是一个编译异常。即这时,就要求 f1()必须处理这个编译异常。
解决方法 ① 让 f1 方法 throws ② try-catch
【案例C】
public static void f4() {
f5();
}
public static void f5() throws ArithmeticException {
}
分析:
① 在 f4() 中调用方法 f5() 是OK
② 原因是 f5() 抛出的是运行异常
③ 而java中,并不要求程序员显示处理,因为有默认处理机制
当程序中出现了某些“错误”,但该错误信息并没有在Throwable子类中描述处理,这个时候可以自己设计异常类,用于描述该错误信息。
当我们接收Person对象年龄时,要求范围在18-120之间,否则抛出一个自定义异常(要求继承 RuntimeException),并给出提示信息。
CustomException.java
public class CustomException {
public static void main(String[] args) {
int age = 80;
if(!(age >= 18 && age <=120)) {
throw new AgeException("年龄要在 18-120之间。");
}
System.out.println("你的年龄输入正确。");
}
}
class AgeException extends RuntimeException {
public AgeException(String message) {
super(message);
}
}
① 一般情况下,我们自定义异常是继承RuntimeException
② 即把自定义异常做成运行时异常,好处时,我们可以使用默认的处理机制
【例题】
public class ThrowException {
public static void main(String[] args) {
try {
ReturnExceptionDemo.methodA();
} catch (Exception e) {
System.out.println(e.getMessage());
}
ReturnExceptionDemo.methodB();
}
}
class ReturnExceptionDemo {
static void methodA() {
try {
System.out.println("进入方法A");
throw new RuntimeException("制造异常");
} finally {
System.out.println("用A方法的finally");
}
}
static void methodB() {
try {
System.out.println("进入方法B");
return;
} finally {
System.out.println("调用B方法的finally");
}
}
}
程序从main函数开始
【执行】ReturnExceptionDemo.methodA();
------------------------ReturnExceptionDemo类------------------------------------
进入ReturnExceptionDemo类寻找静态方法methodA
【执行】System.out.println("进入方法A");
【输出1】进入方法A
【执行】throw new RuntimeException("制造异常");
抛出异常: new RuntimeException("制造异常") 进入类RuntimeException的构造方法,并且传递参数
进入源代码查看,发现RuntimeException是Exception的子类,Exception是Throwable的子类。
Throwable源码:
{
private String detailMessage;
public Throwable(String message) {
fillInStackTrace();
detailMessage = message;
}
}
此时 属性detailMessage = "制造异常";
【执行】finally中的内容
【输出2】用A方法的finally
【返回main函数】
------------------------------main函数------------------------------------------
main捕捉到了异常,进入catch
【执行】System.out.println(e.getMessage());
Throwable类中的源码为 :
public String getMessage() {
return detailMessage;
}
【输出3】制造异常
【执行】ReturnExceptionDemo.methodB();
------------------------ReturnExceptionDemo类------------------------------------
【输出4】进入方法B
【输出5】调用B方法的finally