异常概述
异常可以看作是程序运行时,在运行时可能会出现的一些错误称为异常。
通常使用Exception以及它的子类来封装程序产生的错误。
异常一般可以分为两类。
- RuntimeException:运行时才会出现的异常,一般是代码运行时,逻辑错误而产生的。可以正常编译运行。
- 编译时出现的异常,一般是在代码在编译阶段,编译器会自动检测语法规范而产生的。如果没修改异常,那么将无法编译运行。
这段代码就是一个在编译阶段就出现的异常,在编写完这段代码后,编译器就会自动提示错误,编写者必须需要修改报错行的代码,才能运行程序。
Random r=new Random();
int a="123"; // 编译阶段就会被检测出来的异常
而下面这段代码就是一个只有运行时才可能产生异常的代码,如果随机值是负数或小于10,将会产生一个异常。
int[] arr=new int[r.nextInt()]; // 只有运行后,才能确定是否会产出异常
arr[10]=100;
异常的处理
程序在产生后异常后,如果我们不对该异常进行处理,那么Java虚拟机会采取默认处理方式,程序会在异常产生行处停止,并将异常信息打印在控制台,以便编写者进行代码的修改。
异常出现后,第11行的代码并没有执行,说明异常出现后,程序会在异常行停止运行。
那该如何对异常进行处理呢?
Java提供了一种机制,异常捕捉进制,简述就是当异常产生后被抛出后,可以使用特定的语句将被抛出的异常进行捕获,并进行处理。
异常的捕捉
Java的异常捕获结构由try、catch和finally3部分组成。
语法使用:
try{
// 可能产生异常的代码快
}catch(可能产生的异常类型 变量名){
// 对异常的处理
}
finally{
// 无论以上代码是否执行,本语句都会执行
}
使用try、catch语句对上述代码进行改写后。
try{
Random r=new Random();
int[] arr=new int[r.nextInt()];
arr[10]=100;
System.out.println("代码标记位");
}
catch (NullPointerException e){
System.out.println("空指针引用,出现异常");
}
catch(NegativeArraySizeException e){
System.out.println("数组大小为负数,出现异常");
}
finally{
System.out.println("异常处理结束");
}
System.out.println("程序结束");
运行结果
try语句有下列几个特点。
- 如果在try语句内的代码块产生了异常,那么将会被下面的catch语句进行捕获,会和catch语句进行异常类型匹配,如果匹配成功则,进入该catch语句,不在进行后面的catch语句匹配。这点与if else语句类似。
- 在异常产生并被捕获后,并在执行完catch语句后,程序不会停止,会继续往下执行。
- 如果在try语句内产生异常,但是在catch语句内没有与之匹配的异常类型,那么该异常会交给JVM进行默认处理。
- 在try内某行代码产生异常后,在try语句该行以下的程序不会被执行了,将会跳转catch语句进行异常匹配处理。
- 如果在try内的代码块,没有出现异常,那么依次将try内的语句执行完毕,不会执行catch语句。
一般的,在try、catch语句中,try语句中不会只产生一种异常,那么对异常类型的匹配catch语句就不会只有一条,那么如果在catch语句内的异常类型有父子关系,那么父类异常的catch语句必须放置在子类异常的catch语句下面。
因为父类异常是可以接收子类异常的,可以形成多态的关系,那么拿子类异常进行匹配时,父类异常也是可以接收的。那么如果子类异常放置在父类异常下面,那么子类异常catch将永远不会被执行。
例如在以下代码中,Exception是父类异常,而NullPointerException等是Exception异常的子类,那么两个子类异常匹配将永远不会执行,所以编译器给出了警告。
finally语句
一个完整的异常处理语句一定要包含finally语句,无论程序中是否有异常产生,并且无论之前的try-catch语句块是否顺序执行完毕,都会执行finally语句。
但是有以下四种特殊情况,finally不会执行。
- 在finally语句内出现异常
- 在finally语句之前使用了System.exit()退出了程序。
- 程序所在的线程死亡
- 关闭了CPU
finally只能与try-catch语句配合中,并不能让其单独存在。
Java常见的异常类
Java提供了多种类型的异常类,我们可以选择对应的产生的异常类,使用catch语句进行捕捉,对其进行对应的处理。当然如何看到被JVM默认处理的异常要能大概了解是那种异常,然后对其进行对应的修改。
常见的异常类
自定义异常类
虽然Java提供了很多的异常类供我们使用,但是如果有一个user的类,类中有一个属性是name,要求这个name需要用户自己输入,并且name的长度需要大于2-小于10,否则抛出一个异常进行处理。那么这个异常该使用那个异常类呢?好像在Java提供的异常类中,没有对应的异常类能够很好的表示出来。
这个时候就需要编写者自己定义一个异常类来使用了。
异常类的定义
public class NameLengthException extends Exception{
public NameLengthException (){
}
//创建一个有参构造,使用父类的构造方法
public NameLengthException(String message){
super(message);
}
}
自定义异常要遵守以下两个规范
- 异常类的定义与普通类的定义几乎相同,但是,异常类要直接或间接的继承Throwable类,Exception就是Throwable的子类。
- 在异常类中一般没有属性与方法,而且其两个构造方法也是调用父类的构造方法。
例如上述的需求,在user中,用户名长度需要遵守大于2小于10的规定,那么我们就可以自定义一个异常类来提醒用户的错误输入。
//定义一个异常类
class NameLengthExcepiton extends Exception{
public NameLengthExcepiton() {
}
public NameLengthExcepiton(String message) {
super(message);
}
}
class user{
private String name;
public user(String name) throws NameLengthExcepiton {
int len=name.length();
// 对于出现的错误,将异常抛出
if(len < 2 || len > 10){
throw new NameLengthExcepiton(name+"的长度不符合规定");
}
this.name = name;
}
}
自异常一般分为以下几个步骤
- 创建异常类。
- 在方法中通过throw关键字抛出异常对象。
- 如果在当前抛出异常的方法进行处理,那么使用try-catch语句进行处理,否则需要在方法的声明处通过throws关键字指明要抛出给方法调用者的异常,进行下一步操作。
- 在出现异常的方法的调用者中捕获并处理异常。
End
本文如有错误,欢迎指正。