Java中的异常问题详解
一、异常的概念与分类
1.异常概念
概念:Java异常是一个描述在代码段中发生异常的对象,当发生异常情况时,一个代表该异常的对象被创建并且在导致该异常的方法中被抛出,而该方法可以选择自己处理异常或者传递该异常。
异常机制:异常机制是指当程序出现错误后,程序如何处理。具体来说,异常机制提供了程序退出的安全通道。当出现错误后,程序执行的流程发生改变,程序的控制权转移到异常处理器。
2.关于异常的分类
(1)非受查异常(运行时异常):是指程序在执行时出现的异常
举例Demo:
int[] array = null;
System.out.println(array.length);
//执行结果:
Exception in thread "main" java.lang.NullPointerException
at TestDemo.main(TestDemo.java:160)
//必须对其进行捕获或声明以便抛出
(2)受查异常(编译时异常):是指程序在进行编译时出现的异常
(3)逻辑错误:是指因为程序没有按照预期的逻辑顺序执行。异常也就是指程序运行时发生错误,而异常处理就是对这些错误进行处理和控制
3.常见的异常
(1)算术异常
Demo:
int a = 10;
System.out.println(a/0);
//执行结果:
Exception in thread "main" java.lang.ArithmeticException: / by zero
//0不能放在分母
(2)数组越界异常
Demo:
int[] array = {1,2,3};
System.out.println(array[4]);
//执行结果:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 4 out of bounds for length 3
(3)空指针异常
Demo:
int[] array = null;
System.out.println(array.length);
//执行结果:
Exception in thread "main" java.lang.NullPointerException
二、异常的体系结构
在 Java 中,所有的异常都有一个共同的祖先 Throwable(可抛出)。Throwable 指定代码中可用异常传播机制通过 Java 应用程序传输的任何问题的共性。
在图中可以看出
- Throwable: 有两个重要的子类:Exception(异常)和 Error(错误),二者都是 Java 异常处理的重要子类,各自都包含大量子类。异常和错误的区别是:异常能被程序本身可以处理,错误是无法处理。
- Error:指的是Java虚拟机无法解决的严重问题,比如:JVM的内部错误、资源耗尽等,典型代表: StackOverflowError和OutOfMemoryError。
- Exception:是程序本身可以处理的异常。Exception 类有一个重要的子类 RuntimeException。RuntimeException 类及其子类表示“JVM 常用操作”引发的错误。
- Exception:分为运行时异常和非运行时异常。
三、异常的处理方式
1.防御式处理
防御式处理是指程序猿在写代码时就要有这种意识,写一步代码就会做一次检查。
如以下例子:
Demo:
boolean ret = false;
ret = 登陆游戏();
if (!ret) {
处理登陆游戏错误;
return;
}
ret = 开始匹配();
if (!ret) {
处理匹配错误;
return;
}
ret = 游戏确认();
if (!ret) {
处理游戏确认错误;
return;
}
ret = 选择英雄();
if (!ret) {
处理选择英雄错误;
return;
}
ret = 载入游戏画面();
if (!ret) {
处理载入游戏错误;
return;
}
2.事后认错型处理
事后认错型处理就是指先执行代码,如果遇到问题,再去处理问题。
(1).try···catch···异常捕获和处理
try {
登陆游戏();
开始匹配();
游戏确认();
选择英雄();
载入游戏画面();
...
} catch (登陆游戏异常) {
处理登陆游戏异常;
} catch (开始匹配异常) {
处理开始匹配异常;
} catch (游戏确认异常) {
处理游戏确认异常;
} catch (选择英雄异常) {
处理选择英雄异常;
} catch (载入游戏画面异常) {
处理载入游戏画面异常;
}
注:
- try当中的存放可能出现的异常代码
- catch当中捕获可能出现的异常
Demo:
try {
int a = 10;
System.out.println(a/0);
System.out.println("正常代码!");
}catch (ArithmeticException e) {
e.printStackTrace();//快速地定位异常出现的位置
System.out.println("你这里出现了算术异常!");
}
//执行结果:
java.lang.ArithmeticException: / by zero
at TestDemo.main(TestDemo.java:161)
你这里出现了算术异常!
从上面的结果可以看出,当代码运行到有错误的代码的时候,就会抛出异常,由catch去捕获异常,就不会继续执行后面正常的代码
关于try···catch···的使用细节
(1)如果try中出现了多个异常,当catch去捕捉时可用‘|’去分开各个异常.
catch (ArithmeticException | NullPointerException e)
(2)如果catch中没有写出对应的异常,这里就不会去捕获,最终这个异常就会交给JVM去处理,程序就会立即终止,正常的代码也不会执行.
(3)不会同时出现两个及以上异常
原因:因为当出现一个异常,就会直接被catch捕获,就不会继续执行try中的语句了.
(4)不建议这样写
catch(Exception e) {}
这样写说明你这人懒啊!!!
(5)try当中可能会同时抛出多个不同的异常对象,则必须用多个catch去捕获——多个异常,多次捕获.
(6)
catch(Exception e) {
}catch(ArithmeticException e) {
}
由于Exception是所有类的父类,那么后面的子类就没有存在的必要,所有这种写法不可行!!!
但是当父类Exception和子类交换位置时,这种写法是可行的.
(2)异常的声明
在方法声明时参数列表之后,当方法中抛出编译时异常,用户不想处理该异常,此时就可以借助throws将异常抛
给方法的调用者来处理。即当前方法不处理异常,提醒方法的调用者处理异常。
语法格式:
修饰符 返回值类型 方法名(参数列表) throws 异常类型1,异常类型2...{
}
具体代码举例:
Demo:
public class TestDemo {
public static void test(int a) throws CloneNotSupportedException {
if (a == 10) {
throw new CloneNotSupportedException();
}
System.out.println("异常后的代码不执行!");
}
public static void main(String[] args) {
try {
test(10);
System.out.println("正常代码!");
}catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
//执行结果:
java.lang.CloneNotSupportedException
注意事项:
- throw必须写在方法体内部
- 抛出的对象必须是Exception或者Exception子类的对象
- 如果抛出的是Runtime Exception或者Runtime Exception的子类,则可以不用处理,交给JVM就行
- 如果抛出的是编译异常,就必须处理,否则编译无法通过
- 异常一旦抛出,异常后面的代码就不会执行
(3)关于finally关键字
finally:一般用于资源释放,断开连接,关闭管道流等
一般搭配try – catch --finally 或者 try — finally,一般来说无论try中是否抛出异常,都会执行finally。
Demo:
public class TestDemo {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
try {
int num = scanner.nextInt();
System.out.println(num);
}catch (InputMismatchException e) {
e.printStackTrace();
System.out.println("输入的数据不匹配!");
}finally {
System.out.println("执行了finally部分,一般用来关闭资源!");
scanner.close();
}
}
}
这种就是正确的输入。
这种就是错误的输入,代码叫我们输入一个数字,但是这里我们输入了字符串,就会出现输入异常
但是finally部分的代码不管出现异常没有都会执行
(4)关于异常处理的流程
- 如果try中有异常,就会抛出异常,由catch捕获,然后匹配是否有配对的异常
- 如果有就执行catch中的语句
- 如果没有就会将异常上传给上层调用者
- 无论有没有都会执行finally中的语句
- 如果上层调用者也没有,就会继续上传
- 一直到main方法,如果main方法中也没有,就会将其交给JVM,此时程序机会异常终止
(5)finally的注意事项
建议不要在finally中return 数据!!!
因为finally 块中的 return 返回后方法结束执行,不会再执行 try 块中的 return 语句。也就是说try块中的return值会先保存起来,然后执行完finally中的代码后,才会把try块中的return值返回,所以finally中的代码逻辑是不会影响try块中的return值的。但如果在finally中使用return了就会导致try块中的代码得不到执行而无法返回正确的结果。
例子:
public class TestDemo {
public static int func() {
int num = 10;
try{
return num;
}catch (Exception e){
e.printStackTrace();
} finally {
num = 5;
return num;
}
}
public static void main(String[] args) {
int ret = func();
System.out.println(ret);
}
}
//执行结果:
5
四、自定义异常
Java 中虽然已经内置了丰富的异常类, 但是并不能完全表示实际开发中所遇到的一些异常,此时就需要维护符合我
们实际情况的异常结构。
具体方式:
格式:public class XXXException extends Exception 或者 RuntimeException{
添加一个空参数的构造方法
添加一个带异常信息的构造方法
}
Demo举例:
class UserNameErrorException extends RuntimeException {
public UserNameErrorException() {
super();
}
public UserNameErrorException(String message) {
super(message);
}
}
class PassWordErrorException extends RuntimeException {
public PassWordErrorException() {
super();
}
public PassWordErrorException(String message) {
super(message);
}
}
public class TestDemo {
private String userName = "admin";
private String passWord = "123456";
public void LoginInto(String userName,String passWord) {
try {
if(!this.userName.equals(userName)) {
throw new UserNameErrorException("用户名错误!");
}
if (!this.passWord.equals(passWord)){
throw new PassWordErrorException("密码错误!");
}
System.out.println("登陆成功!");
}catch (UserNameErrorException e) {
e.printStackTrace();
}catch (PassWordErrorException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
TestDemo test = new TestDemo();
test.LoginInto("admi","123456");
}
}
第一种运行结果:当userName和passWord输入正确的时候
第二种运行结构:当userName和passWord其中有一个或者两个都不对的时候
注意事项:
- 自定义异常通常会继承自 Exception 或者 RuntimeException
- 继承自 Exception 的异常默认是受查异常
- 继承自 RuntimeException 的异常默认是非受查异常
好啦!关于java中的异常就讲到这里,如果各位小伙伴有问题或者发现本博客有什么问题,可以私信哦!!!
以蝼蚁之行,展鸿鹄之志