目录
1.概念
2.异常的体系结构
3.异常的分类
3.1编译时异常
3.2运行时异常
4.异常的处理
4.1防御式编程
5.异常的抛出
6.异常的捕获
1.异常声明throw
2.try-catch捕获处理
7.finally
8.异常处理的流程
9.自定义异常类
在JAVA中,将程序执行过程中发生的不正常的行为称为‘异常’。
而关于异常,也有多种多样的。像是,算术异常,数组越界异常,空指针异常。
因为异常的种类繁多,为了对于不同的异常或者错误进行了很好的分类。
他们直接是父类与子类,继承的关系。
可以看到Thorwable是异常体系的顶端,派生出了Errow和Exception两个子类
Errow,指的是Java虚拟机无法解决的严重问题,比如:JVM的内部错误、资源耗尽等。
Exception,异常产生后程序员可以通过代码进行处理,使程序继续执行。
而在这两个子类下又还有许多的子类。
异常可能会在编译的时候发生错误,也可能是在运行时发生错误。根据这一情况,异常可以分为‘编译时异常’和‘运行时异常’。
在程序编译期间发生的异常,称为编译时异常,也称为受检查异常(Checked Exception)
在程序执行期间发生的异常,称为运行时异常,也称为非受检查异常(Unchecked Exception)
RunTimeException以及其子类对应的异常,都称为运行时异常。比如:NullPointerException、
ArrayIndexOutOfBoundsException、ArithmeticException
LBYL:Look Before You Leap.(事前防御型)
即在每一次的操作之后都对其检查,查看是否发生异常。
EAFP:It's Easier to Ask Forgiveness than Permission.(事后认错型)
即是先把代码运行,当在运行过程种发生错误再捕获异常。
在java中,可以通过throw关键字,抛出一个指定的异常对象,将错误信息更直白的告知
throw new 异常对象("异常的原因")
public class Test {
public static void Printf(int[] arr){
if(arr == null){
throw new NullPointerException("传递的数组为空");
}
for (int a:arr
) {
System.out.print(a + " ");
}
}
public static void main(String[] args) {
int[] arr = {1,2,3,4,5,6,7};
Printf(null);
}
}
异常的捕获就是异常的助理方式:
在方法的声明中使用throws关键字抛出,标明此方法有这个异常,但并没有处理此异常,让方法的调用者负责处理。在遇到异常后的代码不会运行
当方法的实现者没能力或不想解决的时候,可以使用throws抛出此异常给调用者解决。
public static void main(String[] args) throws IOException
当方法调用者遇到这种情况,可以选择处理或继续throws抛出异常
语法格式:
try{
//可能会有异常的代码
//遇到异常后的代码不会执行
}catch(要捕获的异常类型 e){
//如果try的类型与此处的catch匹配
//则会执行此catch下的代码
}catch (){
//catch可以有多个
}
//如果catch成功捕获try处的异常,try-catch体系后的代码可以继续正常执行
如果try中出现了异常,且被catch捕获了,则try-catch的后续代码可以继续运行。如果try中出现了异常且没有被catch捕获,则编译器会报错,且后续的代码不会运行。
如果要捕获的异常之间存在子类与父类的关系,那么子类异常的catch一定要写在父类catch的前面。不然会捕获不到,子类的异常。
在写程序时,有些特定的代码,不论程序是否发生异常,都需要执行,比如程序中打开的资源:网络连接、数据库连接、IO流等,在程序正常或者异常退出时,必须要对资源进进行回收。另外,因为异常会引发程序的跳转,可能导致有些语句执行不到,finally就是用来解决这个问题的。
语法格式:
try{
// 可能会发生异常的代码
}catch(异常类型 e){
// 对捕获到的异常进行处理
}finally{
// 此处的语句无论是否发生异常,都会被执行到
}
//后续的代码看try处的异常是否被catch捕获来决定是否执行
示例:
继承RuntimeException表示为运行时异常
如果继承了Exception,默认为受查异常,则要在编译时进行处理,可以在方法中通过关键字throws抛出
import java.security.PrivateKey;
import java.util.Scanner;
class UserNameException extends RuntimeException{//自定义一个类,继承RuntimeException
public UserNameException(String message) {//带参数的构造方法,
super(message);
}
}
class PasswordException extends RuntimeException{//自定义一个类,继承RuntimeException
public PasswordException(String message) {
super(message);
}
}
public class Test {
public static void Login() {
String userName = "helloworld";
String userPassword = "123456789";
Scanner scanner = new Scanner(System.in);
System.out.println("请输入用户名:");
String name = scanner.nextLine();
System.out.println("请输入密码:");
String password = scanner.nextLine();
if(!name.equals(userName)){
throw new UserNameException("用户名错误");
}
if(!password.equals(userPassword)){
throw new PasswordException("密码错误");
}
System.out.println("登录成功");
}
public static void main(String[] args){
try{
Login();
}catch (UserNameException e){
e.printStackTrace();//printStackTrace()方法的意思是:在命令行打印异常信息在程序中出错的位置及原因
}catch (PasswordException e){
e.printStackTrace();
}
}
}
printStackTrace()方法的意思是:在命令行打印异常信息在程序中出错的位置及原因