异常
1.1有关异常
- 异常的概念:指的是程序在执行过程中,出现的非正常的情况,最终会导致JVM的非正常停止。
- 在java等面向对象编程中,异常本身是一个类,产生异常就是创建异常并抛出一个异常对象。java处理异常的方式是中断处理。
- 异常指的并不是语法错误,语法错了,编译不通过,不会产生字节码文件,根本不能运行。
1.2异常体系
异常的根类是java.lang.Throwable,其下有两个子类java.lang.Error 与 java.lang.Exception,平常所说的异常指java.lang.Exception。
Throwable中的常用方法:
- public void printStackTrace():打印异常的详细信息。
包含了异常的类型,异常的原因,还包括异常出现的位置,在开发和调试阶段,都得使用printStackTrace。 - public String getMessage():获取发生异常的原因。
提示给用户的时候,就提示错误原因。
异常分为编译期异常和运行期异常两种。(编译期的异常必须处理)
在代码执行过程中出现异常时,异常后的代码将不再执行,而是将程序执行流交给JVM,由JVM抛出异常并强行终止程序
1.3异常处理机制
Java异常处理的五个关键字:try、catch、finally、throw、throws
- try(引发异常)
- 是用于引发异常或监控可能出现异常的代码,将可能出现异常的代码放到try块中,当其中的代码一旦出现异常,则**try块就可以检测到并交给catch进行捕获及处理*
- try{}不能单独使用,必须和catch或finally一起使用
try{
编写可能会出现异常的代码
}catch(异常类型 e){
处理异常的代码
//记录日志/打印异常信息/继续抛出异常
}
- catch(处理):用于捕获并处理异常。
注意:Exception可以捕获到所有异常;如果需要捕获多个异常的情况将Exception放到最后一个catch处理
- finally(最终):最终会被执行的,在finally代码块中的代码无论是否出现异常都会被执行到。
注意:finally不能单独使用。
- throws(声明异常)
(1)关键字throws运用于方法声明之上,用于表示当前方法不处理异常,而是提醒该方法的调用者来处理异常(抛出异常).
(2)声明异常格式:有多个异常,用逗号隔开
修饰符 返回值类型 方法名(参数) throws 异常类名1,异常类名2…{ }
- throw(引发新异常)
(1)在方法体内部使用,用于抛出新异常(引发新异常)
(2)通过throw关键字来引发新异常,引发的新异常需要直接使用try-catch 处理或使用throws抛出
使用格式
throw new 异常类名(参数);
例如
throw new NullPointerException("要访问的arr数组不存在");
throw new ArrayIndexOutOfBoundsException("该索引在数组中不存在,已超出范围");
1.4异常注意事项
- 多个异常使用捕获该怎么处理
(1)多个异常分别处理
(2)多个异常一次捕获,多次处理
(3)多个异常一次捕获,一次处理
一般我们使用的是一次捕获多次处理方式。格式如下:
try{
编写可能会出现异常的代码
}catch(异常类型A e){ 当try中出现A类型异常,就用该catch来捕获.
处理异常的代码
//记录日志/打印异常信息/继续抛出异常
}catch(异常类型B e){ 当try中出现B类型异常,就用该catch来捕获.
处理异常的代码
//记录日志/打印异常信息/继续抛出异常
}
注意:要求这些catch中的异常类型不能相同,如果有子类与父类之间的关系,那么子类异常要求在上边的catch中处理,父类异常在下边的catch中处理。
- 运行时异常被抛出可以不处理。即不捕获也不声明抛出
- 如果finally中有return语句,则永远返回finally中的结果。
- 如果父类抛出了多个异常,子类重写父类的方法时,抛出和父类相同的异常或抛出父类异常的子类或不抛出异常。
- 父类方法没有抛出异常,子类也不能抛出异常。此时子类产生的异常只能捕获处理,不能声明抛出。
1.5自定义异常
当系统提供的异常类无法满足我们的异常需求,此时我们就要自定义异常。
自定义的异常需要继承Exception类或者Exception类的子类
编译期异常继承Exception
运行期异常继承RuntimeException
练习
要求:我们模拟注册操作,如果用户名已存在,则抛出异常并提示:亲,该用户名已经被注册。
首先自定义一个注册异常类:
public class RegisterException extends Exception{
//空参数的构造器
public RegisterException() {
}
//提示错误信息的构造器
public RegisterException(String message) {
super(message);
}
}
实现如下:
package com.study.test.Demo08Exception;
import java.util.Scanner;
/*要求:模拟进行用户注册
* 如果已经注册,则抛出异常提示用户:用户名已经存在
* 分析:1.使用数组存储已经注册过的用户名
* 2.使用Scanner接收用户输入的注册名
* 3.定义一个方法,判断用户输入的用户名是否已经存在
* 循环遍历存放的数组,一一与输入的用户名进行比较
* true:用户名已经存在,抛出异常
* false:继续遍历
* 如果循环结束,还没有找到重复的用户名,提醒:恭喜您注册成功
*
* */
public class RegisterException01 {
static String[] userName={"张三","李四","王五"};
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
System.out.print("请输入您要注册用户名:");
String username=sc.next();
checkName(username);
}
public static void checkName(String username) {
//遍历数组
for (String name : userName) {
//使用遍历得到的这个用户名和用户输入的进行比较
if(name.equals(username)){
//true
try {
throw new RegisterException("该用户已经被注册");
} catch (RegisterException e) {
e.printStackTrace();
return;//结束方法
}
}
}
//循环结束没有找到重复的用户名
System.out.println("恭喜您!注册成功");
}
}