基本概念
Java中的异常是指程序在运行时发生的不正常情况(开发过程中的语法错误和逻辑错误不是异常)。
异常类型
执行过程中所发生的异常可以分为两大类:
Error:
java虚拟机无法解决的严重问题,会导致程序直接崩溃
Exception:
因编程错误或偶然的外在因素导致的一般性问题,可以通过针对性的代码进行处理(如空指针访问,读取不存在的文件等)。同时Exception又可分为两大类:
[运行时异常]:
也称非检查型异常(Unchecked Exceptions)。是程序运行时发生的异常,特殊情况可不做处理(即交由系统默认处理方式处理)。例如空指针异常:(NullPointerException)当程序调用某对象并使用,但此时该对象为空时,系统就会抛出该异常:
java
public class Go {
public static void main(String[] args) {
String str1="这是一句话";
System.out.println(str1.length());
//正常执行
String str2=null;
System.out.println(str2.length());
//空指针异常
}
}
[编译时异常]:
也称检查型异常(Checked Exceptions)编译器检查出的异常,必须要处理。
关系表
java
Throwable
|
+-- Error
| |
| +--VirtualMachineError
| | |
| | +--OutOfMemoryError
| | |
| | +-- ... (其他虚拟机错误)
| |
| +-- ThreadDeath
| |
| +-- ... (其他错误)
|
+-- Exception
|
+-- RuntimeException
| |
| +-- ArithmeticException
| |
| +-- NullPointerException
| |
| +-- IndexOutOfBoundsException
| |
| +-- ... (其他运行时异常)
|
+-- IOException
| |
| +-- FileNotFoundException
| |
| +-- ... (其他I/O异常)
|
+-- SQLException
| |
| +-- ... (SQL异常)
|
+-- ... (其他检查型异常)
异常处理
try-catch-finally
程序在代码中捕获发生的异常,自行处理(选中代码,按ctrl+alt+t快捷键可快速输入)
java
try {
// 尝试执行的代码,可能会抛出异常
} catch (ExceptionType1 e) {
// 当try块中抛出ExceptionType1类型的异常时执行的代码
//封装为对象e
} catch (ExceptionType2 e) {
// 当try块中抛出ExceptionType2类型的异常时执行的代码
// 可以有多个catch块来处理不同类型的异常
} finally {
// 无论是否发生异常都会执行的代码
// 通常用于释放资源,如关闭文件、数据库连接等
}
- try块:包含可能抛出异常的代码。如果有异常,则执行相对应的catch块。
- catch块:用于捕获try块中抛出的异常,并将其封装的新对象中。
- finally块:无论是否发生异常,finally块中的代码都会被执行。
注意事项
1、如果try块中有异常发生,就会直接进入catch块,不会再继续向下执行try块中的其他语句;如果没有异常则不执行catch块。
java
public class Go {
public static void main(String[] args) {
String str1="这是句话";
String str2= null;
try {//第一个try块
System.out.println("str1长度:"str1.length());//正确,输出4
System.out.println("无异常");//继续执行
} catch (Exception e) {//因无异常,不再执行对应的catch块
System.out.println("有异常发生");
}
try {//第二个try块
System.out.println("str2长度:"str2.length());//错误,出现异常
System.out.println("无异常");//不再继续执行
} catch (Exception e) {//因有异常,直接执行对应的catch块
System.out.println("有异常发生");
}
}
}
执行结果
字符串str1长度:4
无异常
有异常发生
2、可以有多个catch块,每个catch块捕获不同类型的异常,要求父类异常在后,子类异常在前。如果发生异常,只会匹配一个catch块。
java
public class Go {
public static void main(String[] args) {
try {
int num1 = 10;
int num2 = 0;
//将0作为除数,会导致算术异常
System.out.println(num1 / num2);
//下例为空指针异常,在此仅作示例,不执行
// A a = new A();
// a = null;
// System.out.println(a.getClass());
} catch (NullPointerException e) {//第一个catch块
System.out.println("空指针异常:" + e.getMessage());
} catch (ArithmeticException e) {//第二个catch块
System.out.println("算术异常:" + e.getMessage());
} catch (Exception e) {//Exceptin为上两例异常的父类,因此放在后面
System.out.println(e.getMessage());
}
}
}
执行结果:
算术异常:/ by zero
因为在该例中未发生空指针异常,所以第一个catch块不会被执行
3、因为finally块总会被执行的特性,所以其通常用于释放资源,如关闭文件、数据库连接等。也可以仅使用try-finally,这样无论程序是否异常,都会执行finally内的语句,但这种用法相当于未捕获异常,程序有可能崩溃。
throws
当方法内部使用了可能抛出异常的代码,并且这些方法不想或不能处理这些异常时,它们可以使用 throws 关键字来声明这些异常。这样,调用这个方法的代码就需要负责处理这些异常,或者继续向上层抛出。
如果该异常一直未被处理,系统就会调用主方法默认的 throws 方法输出异常信息。
声明异常
在声明方法时使用 throws 关键字,后面跟着一个或多个异常类型(用逗号分隔)。
java
public void someMethod() throws SomeException, AnotherException {
// 方法体
}
注意事项
thrwos后面的异常类型可以是方法中产生的异常类型,也可以是它的父类(如NullPointerException可以被替换成其父类Exception)。但注意抛出的异常类型要么和父类一致,要么为父类抛出的异常类型的子类型。
java
class Father {//父类
//父类方法抛出的异常类型为RuntimeException
public void method()throws RuntimeException{}
}
class A extends Father{//子类A
//正确、子类方法抛出的异常类型为RuntimeException和父类一致
public void method() throws RuntimeException {
}
}
class B extends Father{//子类B
//错误、子类方法抛出的异常类型为RuntimeException的父类
public void method() throws Exception {
}
}
自定义异常
当程序中出现了某种异常,但该异常并未在系统所描述的异常类型中存在,这个时候我们就可以自己设计异常类,用于描述该异常信息。
声明异常
自定义异常类名继承自Exception或RuntimeException,并添加至少一个无参数的构造函数。如果继承自Exception则属于编译异常,如果继承自RuntimeException则属于运行异常(一般继承RuntimeException)。
java
public class myE extends Exception {
public E() {//添加构造函数
//该异常所需执行的操作
}
}
例:判断某一变量的值是否处于1---100之间,如果不是,则抛出异常
java
public class Go {
public static void main(String[] args) {
int num=101;
if(!(num>=1&&num<=100))//判断该变量是否符合要求
//抛出自定义异常MYE
throw new MYE("变量不在1-100之间");
System.out.println("变量符合要求");
}
}
//自定义一个异常
class MYE extends RuntimeException{//继承自RuntimeException,为运行异常
public MYE(String message) {
super(message);
}
}
执行结果:
Exception in thread "main" pack.chn.class1.MYE: 变量不在1-100之间
at pack.chn.class1.Go.main(Go.java:10)
throw和throws的区别
不难注意到,上文分别出现了throw和throws,他们之间存在一定区别:
1、意义不同:throws是异常处理的一种方式,throw为自定义异常的关键字
2、位置不同:throws写在声明方法的语句中,throw则在方法体中
2、后续代码不同:throws后写的是异常类型,throw是异常对象