
异常
- 异常:将程序执行过程中发生的不正常行为,异常也是一个类
- 程序出现异常后将不会继续执行
- 异常的分类:算术异常,空指针异常,数组越界异常
算术异常
空指针异常
数组越界异常
异常和错误
- 异常到底有多少个?它们之间的关系是什么?
异常分为运行时异常和编译时异常
运行时异常(非受查异常):运行时才能检测出来
编译时异常(受查异常):没进行运行前就能检测出来,比如clone(深浅拷贝)
2. RunTimeException以及其子类对应的异常都是运行时异常
异常的处理
- Java中用的是try catch来捕获异常
2. 如何让程序抛出异常?
抛出异常的方式有很多种:
某段程序触发(JVM抛出)
通过关键字throw抛出异常(手动抛出)
throw
throws,异常的声明,后面可以跟多个异常,用逗号隔开
如果在方法内出现了编译时异常,在方法的声明后面声明这个异常就不会报错,最后这个异常是交给JVM处理的
3. throws的处理逻辑:
4. 调用抛出异常的方法时,调用者必须对该异常进行处理,或者继续使用throws抛出,下图中这种异常是交给JVM处理的
5. 程序员自己处理的异常
JVM处理异常和自己处理异常
一旦交给JVM处理,程序就会到对应的异常处终止异常
自己用try catch捕获异常,并且捕获多个异常
捕获多个异常,虽然可以捕获多个异常,但是同一时刻只能抛出一个异常
多个异常的处理方式完全相同可以使用以下方式捕获
5. 父类的异常和子类的异常同时存在,可以用一个Exception捕获所有的异常(但是不推荐这样做)
- 此时是可以的子类捕获不到的异常,用父类来捕获
- 未正确捕获异常,直接报错
8. 正确捕获异常后不会影响后续代码的执行
finally
- 无论是否发生异常,finally都将被执行
public class test {
public static void main(String[] args) {
try{
int[] array = {1,2,3};
System.out.println(array[3]);
}catch(ArrayIndexOutOfBoundsException e){
e.printStackTrace();// 打印栈的痕迹
}finally{
System.out.println("111");
}
System.out.println("后续代码");
}
}
- finally一定会被执行,finally中的代码会在return之前执行
- finally用来释放资源,Scanner也是一种资源,使用完之后需要close该资源,放在try括号中就不需要手动关闭了,可以把需要关闭的资源写在try的括号中
- 为什么一定要使用finally,在finally内部进行释放资源呢?
如果是try中有return的话,不使用finally就会造成资源泄露,关闭资源写在finally之外
面试题
- throw和throws有什么区别?
throw是用来抛出异常的,throws是用来声明异常的,出现编译时异常,用throws来声明就不会报错了,但是是没有处理这个异常的
- finally中的语句一定会被执行吗?
是的,一定会被执行
异常的处理流程
- 异常会沿着调用栈向上传递,比如func方法中出现了异常,那么调用它的main方法中可以写处理异常的逻辑,也可以在func方法中处理异常,如果没有处理就在func方法后面声明这个异常
2. 总结
自定义异常类
如果要写一个自定义异常,一定要继承一个异常,并且自定义异常都是继承Exception或者是RunTimeException的
extends Exception 编译时异常(受查异常)
extends RuntimeException 运行时异常(非受查异常)例子:用户名和密码的登录
public class Test {
private String userId = "一";
private String password = "010101";
public void login(String userId,String password) {
if(!this.userId.equals(userId)){
System.out.println("用户名错误");
}
if(!this.password.equals(password)){
System.out.println("密码错误");
}
System.out.println("登录成功");
}
public static void main(String[] args) {
Test test = new Test();
test.login("一","010101");
}
}
上面密码和用户名都是正确的,不会抛出异常
用户名或者密码错误会抛出异常,需要写自定义异常,继承自Exception或者是RunTimeException
自定义异常类
//继承基类异常
//用户名异常
//这里继承的是受查异常
// 用户名异常
class UserIdException extends Exception{
public UserIdException(String message){
super(message);
}
}
//密码异常
class PasswordException extends Exception{
public PasswordException(String message){
super(message);
}
}
如果用户名或者密码不正确就会报出异常,在main方法中或者是login方法中捕获异常
class UserIdException extends Exception{
public UserIdException(String message){
super(message);
}
}
class PasswordException extends Exception{
public PasswordException(String message){
super(message);
}
}
public class Test {
private String userId = "三三";
private String password = "060610";
public void login(String userId,String password) {
// 捕获异常
try {
if(!this.userId.equals(userId)){
throw new UserIdException("用户名错误"+userId);
}
if(!this.password.equals(password)){
throw new PasswordException("密码错误"+password);
}
//如果没有异常就会登录成功
System.out.println("登录成功");
}catch (UserIdException e){
e.printStackTrace();
}catch (PasswordException e){
e.printStackTrace();
}
}
public static void main(String[] args) {
Test test = new Test();
test.login("三三","060610");
}
}