在 Java 语言中,将程序执行中发生的不正常情况称为 “异常”。
注:开发过程中的语法错误和逻辑错误不是异常。
在编写程序时,经常要在可能出现错误的地方加上检测的代码,如进行 x/y 运算时,要检测分母为 0 ,数据为空,输入的不是数据而是字符等。过多的 if-else 分支会导致程序的代码加长、臃肿,可读性差。因此采用异常处理机制。
目录
异常事件的分类
常见异常的举例
异常处理:抓抛模型
try-catch-finally的使用
throws方式
如何选择使用哪种方式处理异常
throw 手动抛出异常对象
1. Error:Java 虚拟机无法解决的严重问题,一般我们不编写针对性代码进行处理
2. Exception:其他因编程错误或偶然外在因素导致的一般性问题,我们编写针对性代码进行处理
java . lang . Throwable
java . lang . Error
java . lang . Exception
编译时异常(checked)
IOException
FileNotFoundException
ClassNotFoundException
运行时异常(unchecked)
NullPointerException
ArrayIndexOutOfBoundException
ClassCastException
NumberFormatException
InputMismatchException
ArithmeticException
抛:程序在正常执行的过程中,一旦出现异常,就会在异常代码处生成一个对应异常类的对象,并将此对象抛出,一旦抛出对象后,其后的代码就不再执行
抓:可以理解为异常处理方式:try-catch-finally 和 throws
使用 try-catch-finally 处理编译时异常,使得程序在编译时就不再报错,但是运行时仍可能报错。相当于我们使用 try-catch-finally 将一个编译时可能出现出现的异常,延迟到运行时出现
1. finally 是可选的,可以不出现,一旦出现,则一定会被执行
2. 使用 try 将可能出现异常的代码包装起来,在执行过程中,一旦出现异常,就会生成一个对应异常类的对象,根据此对象的类型,去 catch 中进行匹配
3. 一旦 try 中的异常对象匹配到某一个 catch 时,就进入 catch 中进行异常的处理。一旦处理完成,就跳出当前的 try-catch 结构(在没有写 finally 的情况下),继续执行其后的代码
4. catch 中的异常类型如果没有子父类关系,则谁声明在上,谁声明在下无所谓
catch 中的异常类型如果满足子父类关系,则要求子类一定声明在父类的上面,否则报错
5. 常用的异常对象处理的方式:String getMessage() printStackTrace()
6. 在 try 结构中声明的变量,在出了 try 结构以后,就不能再被调用
7. 像数据库连接、输入输出流、网络编程 Socket 等资源。JVM 是不能自动的回收的,我们需要自己动手进行资源的释放。此时的资源释放,就需要声明在 finally 中
import org.junit.Test;
public class ExceptionTest {
@Test
public void test() {
String str = "123";
str = "abc";
try {
int num = Integer.parseInt(str);
System.out.println("hello");
}catch(NumberFormatException e) {
System.out.println("出现了数据格式错误");
System.out.println(e.getMessage());
// e.printStackTrace();
}catch(NullPointerException e) {
System.out.println("出现了空指针错误");
e.printStackTrace();
}catch(Exception e) {
System.out.println("出现了异常");
}finally {
System.out.println("出现异常不要着急");
}
}
}
>>> 出现了数据格式错误
For input string: "abc"
出现异常不要着急
throws + 异常类型
1. throws + 异常类型,写在方法的声明处。指明此方法执行时,可能会抛出的异常类型。一旦当方法执行时,出现异常,仍会在异常代码处生成一个异常类的对象,此对象满足 throws 后异常类型时,就会被抛出。异常代码后续的代码,就不再执行
2. throws 方式只是将异常抛给了方法的调用者,并没有真正将异常处理掉
import org.junit.Test;
public class ExceptionTest {
@Test
public void test() throws NumberFormatException,NullPointerException{
String str = "123";
str = "abc";
int num = Integer.parseInt(str);
System.out.println("hello");
}
}
开发中如何选择使用 try-catch-finally 还是 throws ?
1. 如果父类中被重写的方法没有 throws 方式处理异常,则子类重写的方法也不能使用 throws ,意味着如果子类重写的方法中有异常,必须使用 try-catch-finally 方式处理
2. 执行的方法 a 中,先后又调用了另外的几个方法,这几个方法是递进关系执行。我们建议这几个方法使用 throws 的方法进行处理。而执行的方法 a 可以考虑使用 try-catch-finally 方式进行处理
1. 继承于现有的异常结构:RuntimeException 、Exception
2. 提供全局常量:serialVersionUID
3. 提供重载的构造器
public class ExceptionTest1 extends RuntimeException {
public static void main(String[] args) {
Student s = new Student();
s.regist(-1001);
System.out.println(s);
}
}
class ExceptionTest extends RuntimeException { // 手动抛出异常对象
static final long serialVersionUID = -579445735779656467L;
public ExceptionTest() {
}
public ExceptionTest(String msg) {
super(msg);
}
}
class Student{
private int id;
public void regist(int id) throws ExceptionTest{ // 手动抛出异常
if(id > 0) {
this.id = id;
}else {
throw new ExceptionTest("您输入的数据非法!");
}
}
}
>>> Exception in thread "main" tryCatchThrows.ExceptionTest: 您输入的数据非法!
at tryCatchThrows.Student.regist(ExceptionTest1.java:24)
at tryCatchThrows.ExceptionTest1.main(ExceptionTest1.java:6)