文章目录
Java异常处理
- Error:Java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源耗尽等严重情况。比如:StackOverflowError 和 OOM(OutOfMemoryError)。一般不编写针对性的代码进行处理
- Exception:其他因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。
- 空指针访问
- 试图读取不存在的文件
- 网络连接中断
- 数组角标越界
java.lang.Throwable
java.lang.Error
:一般不编写针对性的代码进行处理java.lang.Exception
:可以进行异常的处理- 编译时异常(checked)
IOException
FileNotFoundException
ClassNotFoundException
- 运行时异常(unchecked)
NullPointerException
ArrayIndexOutOfBoundsException
ClassCastException
NumberFormatException
InputMismatchException
ArithmeticException
- 编译时异常(checked)
异常的处理:抓抛模型
-
过程一:“抛”:程序在正常执行的过程中,一旦出现异常,就会在异常代码处生成一个对应 异常类对象,并将此对象抛出一旦抛出对象以后,其后的代码就不再执行。
-
过程二:“抓”:可以理解为异常的处理方式:① try-catch-finally ② throws
1. 异常处理机制一:(try-catch-finally)
try {
// 可能出现异常的代码
} catch(异常类型1 变量名) {
// 处理异常的方式1
} catch(异常类型2 变量名) {
// 处理异常的方式2
}
...
finally {
// 一定会执行的代码
}
说明:
- 使用 try 将可能出现异常代码包装起来,在执行过程中,一旦出现异常,就会生成一个对应异常类的对象,根据此对象的类型,去 catch 中进行匹配。
- 一旦 try 中的异常对象匹配到某一个 catch 时,就进入 catch 中进行异常的处理,一旦处理完成就跳出当前 try-catch 结构(没有写 finally的情况)
-
- catch 中的异常类型如果没有子父类关系,则谁声明在上,谁声明在下无所谓。
- catch 中的异常类型如果满足子父类干洗,则要求子类一定声明在父类的上面。否则报错
- 常用的异常对象处理的方式:① String getMessage() ② printStackTrace()
- 在 try 结构中声明的变量,出了 try 结构以后,就不能再被调用。
- try-catch-finally 结构
finally:
- finally 是可选的。
- finally 中声明的是一定会被执行的代码,即使 catch 中又出现异常了,try 中有 return 语句,catch 中有 return 语句的情况。
- 像数据库连接、输入输出流、网络编程 Socket等资源,JVM 是不能自动的回收的,我们需要手动的进行资源释放,就需要声明在 finally 中。
(选中代码,快捷键:Alt+Shift+Z 或 右键 Surround With)
使用 try - catch - finally 处理编译时异常,使得程序在编译时就不再报错,但是运行时仍可能报错。相当于我们使用 try -catch -finally 将一个编译时可能出现的异常,延迟到运行时出现。
由于运行时异常比较常见,所以通常就不针对运行时异常编写 try - catch - finally了,针对编译时异常,一定要考虑异常的处理
2. 异常处理机制二:throws + 异常类型
- “throws + 异常类型” 写在方法的声明处。指明此方法执行时,可能会抛出的异常类型。 一旦当方法体执行时,出现异常,仍会在异常代码处生成一个异常类的对象,此对象满足 throws 后异常类型,就会被抛出。异常代码后序的代码 就不再执行。
-
- try - catch - finally:真正的将异常给处理掉了
- throws 的方式只是将异常抛给了方法的调用者,并没有真正将异常处理掉。
回顾:方法重写的规则之一
子类重写的方法抛出异常类型不大于父类被重写的方法抛出的异常类型
import java.io.FileNotFoundException;
import java.io.IOException;
public class OverrideTest {
public static void main(String[] args) {
OverrideTest test = new OverrideTest();
test.display(new SubClass());
}
public void display(SuperClass s) {
try {
s.method();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class SuperClass {
public void method() throws IOException {
}
}
class SubClass extends SuperClass {
public void method() throws FileNotFoundException {
}
}
如何选择使用 try - catch - finally
还是使用 throws
?
- 如果父类中被重写的方法没有 throws 方法处理异常,则之类重写的方法也不能使用 throws,意味着如果子类重写的方法中有异常,必须使用 try - catch - finally 方式处理。
- 执行的方法中,先后又调用了另外的几个方法,这几个方法是递进关系执行的。建议使用 throws 的方式进行处理。
3. 手动抛出异常 (throw)
public class ThrowTest {
public static void main(String[] args) {
Student s = new Student();
s.regist(-100);
s.toString();
}
}
class Student {
private int id;
public void regist(int id) {
if (id > 0) {
this.id = id;
} else {
// System.out.println("您输入的数据非法!");
// 手动抛出异常
throw new RuntimeException("您输入的数据非法!");
}
}
@Override
public String toString() {
return "Student [id=" + id + "]";
}
}
4. 自定义异常类
如何自定义异常类?
- 继承于现有的异常结构:
RuntimeException
、Exception
- 提供全局常量:
serialVersionUID
- 提供重载的构造器
class MyException extends RuntimeException{
static final long serialVersionUID = -7034897190745766939L;
public MyException() {
}
public MyException(String msg) {
super(msg);
}
}
5. 异常处理练习
public class ReturnExceptionDemo {
static void methodA();
try {
System.out.println("进入方法A");
throw new ReturnException("制造异常");
} finally {
System.out.println("用A方法的finally");
}
static void methodB(){
try {
System.out.println("进入方法B");
return;
} finally {
System.out.println("调用B方法的finally");
}
}
public static void main(String[] args) {
try {
methodA();
} catch(Exception e) {
System.out.println(e.getMessage());
}
methodB();
}
}
throw 和 throws区别:
- throw 表示抛出一个异常类的对象,生成异常对象的过程。声明在方法体内。
- throws 属于异常处理的一种方式,声明在方法的声明处。
世界上最遥远的距离,是我在 if 里你在 else 里,似乎一直相伴又永远分离;
世界上最痴心的等待,是我当 case 你是 switch,似乎永远都选不上自己;
世界上最真情的相依,是你在 try 我在 catch。无论你发神马脾气,我都默默承受,静静处理。到那时,再来期待我们的 finally。