这里写目录标题
异常机制
1. 之前常见的运行时异常
1 空指针异常
2 下标越界
3 类型转换
4 栈内存移出
异常概述
异常是Java中提供的一种识别及响应错误情况的一致性机制。有效地异常处理能使程序更加健壮、易于调试。
异常发生的原因有很多,比如:
1)用户输入了非法数据
2)要打开的文件不存在
3)网络通信时连接中断
4)JVM内存溢出
5)这些异常有的是因为用户错误引起,有的是程序错误引起的,还有其它一些是因为物理错误引起的。
- 如果程序报错,会终止程序生命周期执行(错误代码之后的代码都不会执行了)
- 1 异常机制
-
异常就是错误的另一种说法
-
在java中有一个专门模拟所有异常和错误的类(Throwable),所有的异常类都必须继承这个类
- 异常是我们程序员在写程序的时候,对某些高风险代码的操作规定了一个提醒机制,对于系统来说 就是处理异常的触发机制
- 2 异常机制的处理形式
-
try...catch... : 解决异常,一般用在客户端
-
throws : 抛出异常,一般用在类库端(服务端)
-
throw : 制造异常,异常源点,创建一个异常对象
- 用if…else…进行判断,也可以把大多数错误屏蔽掉,但是 只能处理我们预知的情况,对于无法预知的情况,就需要使用try…catch…解决了
- 3 不同异常机制的选择
-
有些错误我们不想处理,或者没有办法处理,或者不知道应该怎么处理(通常是类库端),一般使用throws把问题抛给调用处
-
在一个就是知道怎么处理,直接使用try...catch...处理问题即可,一般是main方法
- 4 finally语句块
-
必须执行的语句块
- 5 异常机制的继承体系
-
最大的异常类是 Throwable
-
直接两个子类 : Error(我们解决不了,比如栈溢出)和 Exception(所有的子类除了一个RunTimeException之外,其他全是编译时异常)
- 6 语法 :
-
try{
-
高风险代码;
-
}catch(异常类 变量){
-
处理措施;
-
}
目的 : 增强程序的鲁棒性,健壮性
异常继承体系
4. Error
- 概念
系统内部错误,这类错误由系统进行处理,程序本身无需捕获处理。
比如:OOM(内存溢出错误)、VirtualMachineError(虚拟机错误)、StackOverflowError(堆栈溢出错误)等,一般发生这种情况,JVM会选择终止程序。 - 示例
//堆栈溢出错误
public class TestError {
public static void recursionMethod() {
recursionMethod();// 无限递归下去
}
public static void main(String[] args) {
recursionMethod();
}
}
报错信息:
Exception in thread “main” java.lang.StackOverflowError
at com.TestError.recursionMethod(TestError.java:5)
at com.TestError.recursionMethod(TestError.java:5)
at com.TestError.recursionMethod(TestError.java:5)
at com.TestError.recursionMethod(TestError.java:5)
at com.TestError.recursionMethod(TestError.java:5)
at com.TestError.recursionMethod(TestError.java:5)
5. Exception
5.1概述
Exception是所有异常类的父类。分为非RuntimeException和RuntimeException 。
非RuntimeException
指程序编译时需要捕获或处理的异常,如IOException、自定义异常等。属于checked异常。
RuntimeException
指程序编译时不需要捕获或处理的异常,如:NullPointerException等。属于unchecked异常。一般是由程序员粗心导致的。如空指针异常、数组越界、类型转换异常等。
如果程序报错,会终止程序生命周期执行(错误代码之后的代码都不会执行了)
1 异常机制
异常就是错误的另一种说法
在java中有一个专门模拟所有异常和错误的类(Throwable),所有的异常类都必须继承这个类
异常是我们程序员在写程序的时候,对某些高风险代码的操作规定了一个提醒机制,对于系统来说 就是处理异常的触发机制
2 异常机制的处理形式
try…catch… : 解决异常,一般用在客户端
throws : 抛出异常,一般用在类库端(服务端)
throw : 制造异常,异常源点,创建一个异常对象
用if…else…进行判断,也可以把大多数错误屏蔽掉,但是 只能处理我们预知的情况,
对于无法预知的情况,就需要使用try…catch…解决了
3 不同异常机制的选择
有些错误我们不想处理,或者没有办法处理,或者不知道应该怎么处理(通常是类库端),一般使用throws把问题在一个就是知道怎么处理,直接使用try…catch…处理问题即可,一般是main方法
4 finally语句块
必须执行的语句块
5 异常机制的继承体系
最大的异常类是 Throwable
直接两个子类 : Error(我们解决不了,比如栈溢出)和 Exception(所有的子类除了一个RunTimeException之外,其他全是编译时异常)
- 6 语法 :
- try{
-
高风险代码;
-
}catch(异常类 变量){
-
处理措施;
-
}
5.2 常用方法
5.3 TryCatch
5.3.1 第一种
这种就是编译时异常,如果不出来,压根不能运行,这时候 我们要么抛出,要么处理
5.3.2 第二种
- try{
-
高风险代码;
- }catch(异常类 变量){
-
异常操作
- }catch(异常类 变量){
-
异常操作
- }
- 1 catch语句可以根据代码返回的异常编写多个
- 2 但是从上往下,必须是子类到父类,要不然会因为多态的原因,父类会把子类对象捕捉
- 3 从上往下可以是没有继承关系的,那样就不需要考虑顺序问题
- 4 多个异常,只会有一个执行,因为最先出错的语句之后,try中的代码就不再执行了
- 如果 多个异常中,我们的处理措施是一样的,可以直接写exception 没问题
- 但是 如果操作不同,就不能使用exception捕捉
-
比如 用户登陆,如果使用exception捕捉,你是不知道是用户名不对还是密码不对的,那么就只能提醒 "用户名或密码不对"
-
如果想分开提醒 到底是用户名错了还是密码错了 就只能分开捕捉
5.3.3 第三种
- java1.7开始,出现了一个新的写法,可以一次catch捕捉多个异常,
- 但是异常之间不能有继承关系,如果有继承关系,之间写父类
- 多个异常使用 | 隔开
- 异常类型 | 异常类型 | …
5.3.4 第四种
- java1.7 异常有两个改进
-
1 多个异常可以在一个catch中同时捕捉, 需要使用 | 隔开
-
2 自动关闭资源
-
try(开启资源语句){
-
高风险代码;
-
}catch(异常类 变量){
-
处理语句;
-
}
5.4 Throws
5.4.1 第一种
- throws 并不会把异常处理,而是一种提醒,告诉调用人员,这里有个异常/可能有个异常没有解决,你注意一下
- 如果你调用的方法 通过 throws 提醒了你,要么你也提醒调用你的地方,或者你 try 处理掉
5.4.2 第二种
- throws 也可以同时抛出多个异常,使用 逗号 隔开
- 因为 throws 只是一个提醒,所以无所谓顺序和继承关系
5.4.3 注意-覆写不能有更宽泛的异常
- 子类中重写的方法,不能比父类有更宽泛的异常
- 也就是说,子类方法中抛出的异常,必须是父类方法抛出的异常类,或者是其子类
- 子类覆写后 异常 <= 父类 方法的异常
5.5 Finally
5.5.1 基本使用
finally : 必须执行的语句块
我们在编程当中,会碰到程序出错的情况,但是某些情况下,尽管出错了,某些代码也仍然需要让他执行
比如关闭资源语句
1 finally 可以直接和 try… finally{} 一起使用
2 finally 不能单独使用
3 也可以和try…catch…finally… 一起使用
4 只有一种不执行 的情况
System.exit() : 关闭虚拟机
5.5.2 注意事项(return)
5.5.3 面试题
谈谈你对final的理解
1 final是什么,怎么用
2 finally是什么,怎么用
3 finalize是什么,怎么用
5.5.4 Finally一个应用场景
5.6 Throw
异常源点,创建一个异常
throw new 异常类( 错误信息 );
详细用法参考 自定义异常
异常源点,创建一个异常
throw new 异常类( 错误信息 );
详细用法参考 自定义异常
6. 自定义异常类
6.1 定义异常类
1 继承一个 已有的异常类,基本上就继承Exception即可,如果是运行时异常 就继承RuntimeException
2 无参构造
3 有参构造,传入错误信息,并把信息传递给父类 super(xxx)
6.2 应用场景
需求 : 完成用户登陆
1 如果用户名不是 admin 则 提示 用户名不存在
2 如果密码不是 root 则 提示 密码不正确
使用自定义异常类 做提示
/**
- 自定义异常类
- 1 继承一个 已有的异常类,基本上就继承Exception即可,如果是运行时异常 就继承RuntimeException
- 2 无参构造
- 3 有参构造,传入错误信息,并把信息传递给父类 super(xxx)
*/
public class UserException extends Exception {
public UserException() {
}
public UserException(String msg) {
super(msg);
}
}
6.2.1 用户类
public class User {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public User(String username, String password) {
super();
this.username = username;
this.password = password;
}
public User() {
super();
}
6.2.2 业务类
package ThrowExample;
/**
- 需求 : 完成用户登陆
- 1 如果用户名不是 admin 则 提示 用户名不存在 2 如果密码不是 root 则 提示 密码不正确
- 使用自定义异常类 做提示
*/
public class UserService {
public void login(User user) throws UserException {
if (“admin”.equals(user.getUsername())) {
// 如果用户名是admin 就比较密码
if (“root”.equals(user.getPassword())) {
System.out.println(“登陆成功”);
} else {
// 如果密码不正确 就抛异常 提示密码不正确
throw new UserException(“密码不正确”);
}
} else {
// 如果用户名不存在 就抛异常 提示用户名不存在
throw new UserException(“用户名不存在”);
}
}
}
6.2.3 客户端类
package ThrowExample;
import java.util.Scanner;
/**
- 客户端
*/
public class Client {
public static void main(String[] args) {
System.out.println("请输入用户名和密码 : ");
Scanner scanner = new Scanner(System.in);
// 获取用户输入
String username = scanner.next();
String password = scanner.next();
// 封装为用户类对象
User user = new User(username, password);
// 创建业务类对象
UserService userService = new UserService();
// 登陆
try {
userService.login(user);
System.out.println("跳转到主页");
} catch (UserException e) {
// 打印追踪栈帧,没有必要了,只需要把错误提醒的信息 展示给页面即可
// 因为这里 有错 才是对的,所以这个追踪栈帧对程序员来说 没有任何价值
e.printStackTrace();
// 获取错误信息
String msg = e.getMessage();
// 传递到页面
System.out.println(msg);
}
}
}