异常类学习
概念:异常是在程序执行过程中,出现的非正常的情况,最终会导致JVM的非正常停止。
在JAVA等面向对象的编程语言中,异常本身是一个类,产生异常就是创建异常对象并抛出一个异常对象,JAVA处理异常的方式是中断处理。
ps:并不是语法错误,编译不通过不会产生字节码文件,不能运行。
Exception:编译期异常。
RuntimeException:运行期异常。异常就相当于程序得了一个小感冒,只要吃点药(处理掉异常)就可以继续运行。
Error:错误
相当于程序得了一个无法治愈的毛病,必须修改源码才能继续执行。
解决方案
- 第一种处理方式:JVM处理,中断程序,错误信息打印在控制台
- 第二种处理方式:try/catch处理。
异常的举例
java.lang.ArrayIndexOutOfBoundException:数组索引越界异常
java.text.ParseException:解析异常
ERROR举例
OutOfMemoryError:创建的数组太大了,超出了JVM分配的内存。
JVM对异常的处理
1.JVM会根据异常产生的原因创建一个异常对象,这个异常对象包含了异常产生的(内容,原因,位置)
2.在方法中没有处理逻辑(try/catch)那么JVM就会把异常对象抛出方法的使用者,main来处理这个异常。
3.main方法接收到了这个异常,main方法也没有异常的处理逻辑继续把对象抛出给mian方法的调用者JVM处理
4.JVM接收到了这个对象,把异常对象(内容,原因,位置)以红色的字体打印在控制台并且中断当前正在执行的java程序—>中断处理
Object非空判断
Objects.requireNonNUll(“对象”);
Objects.requireNonNUll(“对象”,“传递的对象值为空”);
如何处理异常
throw关键字
作用:可以使用throw关键字在指定的方法中抛出指定的异常。
格式:throw new xxxException(“异常产生的原因”)
注意:
1.throw关键字必须写在方法内部
2.throw关键字后面new的对象必须是Exception或者Exception的子类
3.throw关键字后面创建的是RuntimeException或者是RuntimeException的子类对象,我们就可以不处理,默认交给JVM处理
4.throw关键字后面创建的是编译异常(写代码时报错),我们就必须处理这个异常,要么throws要么try/catch
throws关键字
作用:当方法内部抛出异常对象的时候,那么我们就必须处理这个异常对象,可以使用throws关键字处理异常,会把异常对象声明抛出给方法的调用者处理(自己不处理)最终交给JVM处理
格式:修饰符 返回值类型 方法名(
参数列表) throws AAAException,BBBException …{
throw new AAAException(“产生原因”);
throw new BBBException(“产生原因”);
…
}
注意:
1.throws关键字必须写在方法声明处
2.throws关键字后面new的对象必须是Exception或者Exception的子类
3.方法内部如果抛出了多个异常对象,那么throws后面也要声明多个异常,如果抛出的多个异常对象有父子关系,那么直接声明父类异常即可。
4.调用了一个声明抛出异常的方法,我们就必须处理声明的异常
要么继续使用throws交给方法的调用者处理,最终交给JVM处理,要么try。。。。。catch自己处理异常。
try/catch关键字
作用:异常处理的第二种方式,自己处理异常
格式:try{
可能产生异常的代码
}catch(定义一个异常的变量,用来接收try中抛出的异常对象){
异常的处理逻辑,抓住异常对象之后,怎么处理异常对象
一般会记录到日志中
}
…
catch(异常类名,变量名){
注意:
1.try中可能会抛出多个异常对象,那么就可以使用多个catch来处理这些异常对象
2.如果try中产生了异常,那么就会执行catch中异常处理逻辑,执行完毕catch中的处理逻辑,继续执行try。。。。。catch之后的代码
3.如果try中没有产生异常,那么就不会执行catch中的代码块,执行玩try中的代码后,继续执行try。。。。。catch之后的代码。
PS:如果finally有return语句,永远返回finally中的结果
Throwable类中3个异常处理的方法
String getMessage()返回throwable的简短描述
String toString()返回此throwable的详细信息的字符串
void printStackTrace() JVM打印异常对象,默认此方法,打印的异常信息是最全面的
多异常的捕获处理
1.多个异常分别处理(即正常处理)
2.多个异常一次捕获,多次处理
如果捕获的异常有父子类,那么子类的异常变量必须写在上面,否则就会报错
3.多个异常一次捕获一次处理(即异常直接用父类涵盖全部异常)
子父类异常
如果父类抛出了多个异常,子类重写父类方法是抛出和父类相同的异常或者是父类异常的子类或者不抛出异常。
父类方法没有抛出异常,子类重写父类该方法也不可抛出异常,此子类产生该异常,只能捕获处理,不能声明抛出。
总结:父类异常什么样,子类异常就什么样。
自定义异常
作用:java提供的异常类不够我们使用,需要自己定义一些异常类
格式:
public class xxxException extends Exception | Runtimexception {
}
注意:
1.自定义异常类一般都是以Exception结尾,说明该类是异常类
2.自定义异常类,必须继承Exception或者RuntimeException
继承Exception,那么自定义的异常类就是一个编译期的异常,如果方法内部抛出了编译期异常,就必须处理这个异常,要么throws,要么try/catch
3.继承RuntimeException,那么自定义异常就是一个运行期异常,无需处理,交给虚拟机处理(中断处理)
public class RegisterException extends Exception{
public RegisterException (){
surper();
}
public RegisterException (String message){
surper(message);//调用父类的异常信息的构造方法。
}
}
自定义异常练习
需求:我们模拟注册操作,如果用户名已存在,则抛出异常并提示:亲,该用户名已经被注册。
分析:
1.使用数组保存已经注册过的用户名
2.使用Scanner获取用户输入的注册的用户名进行判断
3.定义一个方法,对用户输入的注册的用户名进行判断
遍历存储已经注册过的用户名和用户输入的进行比较
true:用户名存在,抛出异常告知用户已经被注册
false:继续遍历
结束条件:没有找到重复的用户名,提示注册成功
public class Demo01RegisterException{
static String[] userNames = {"张三","李四","王五"};
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
System.out.println("请输入您要注册的用户名");
String username = sc.next();
CheckUserName(username);
}
public static void CheckUserName(String username) throws RegisterException {
for (String name : userNames) {
if(name.equals(username)) {
throw new RegisterException("用户名已经被注册");
}
}
System.out.println("注册成功");
}
}
finally代码块
作用:无论是否出现异常都会执行
格式:
try {
} catch (Exception e) {
// TODO: handle exception
}finally {
}
注意:
1.finally不能单独使用,必须和try一起使用
2.finally一般用于资源释放,无论程序是否出现异常,最后都会释放资源