前言:经过了十二天的java基础补习阶段,从今天开始我们正式开启java的学习之路。未来路途遥远,我们一起奋斗,砥砺前行。
一、异常
(一)概述
1、在
Java
运行过程中,出现了不正常的情况,称为异常
2、异常就是一个对象,描述的是那些和正常情况不相符的情况
3、异常也是一种处理异常情况的机制,可以对异常对象进行捕获、或者使程序发生跳转甚至停止
(二)体系结构
1、
Throwable
:可抛出的,是异常体系和错误体系的总父类
2、
Error
:错误;用于描述那些无法捕获和处理的错误情况,属于非常严重的错误
3、
Exception
:异常;拥有描述那些可以被捕获和处理的异常情况,属于不太严重的情况
4、
RuntimeException
:是
Exception
的子类,它的子类都是运行时异常,在
Exception
中除了RunTimeException之外都是编译时异常
(三)JVM默认处理异常机制
JVM默认处理异常的方式:一层一层往上抛,
JVM
接收到之后将异常信息打印在控制台
public class Demo01_Throwable {
public static void main(String[] args) {
test3();
}
private static void test3() {
test2();
}
private static void test2() {
test1();
}
private static void test1() {
System.out.println(10 / 0);
}
}
(四)手动处理异常的方式
1、有两大类的处理异常的方式
(1)异常的声明:某个方法存在编译时异常,编译期无法通过的时候,需要在编译时异常的方法声明上,对可能发生异常的类型进行声明
(2)异常的捕获:出现异常情况之后,可以通过某段代码格式对异常对象进行捕获和处理;此时,程序出现的异常对象,就不会再往上抛了,而是捕获下来了
2、捕获格式
(1)
try...catch
(2)
try...catch...catch...catch
(3)
try...catch..finally
(4)
try...finally
(五)try...catch
1、
try
:关键字;含义:试一试,可能出现问题的代码放在
try
模块中
2、
catch
:关键字;含义:捕获;当真的出现问题之后应该怎样去处理
3、格式:
try {
可能出现问题的代码;
} catch(可能出现异常的类型 标识符) {
出现了这种问题之后处理方式;
}
public class Demo02_TryCatch {
public static void main(String[] args) {
/**
* try {
* 可能出现问题的代码;
* } catch(可能出现异常的类型 标识符) {
* 出现了这种问题之后处理方式;
* }
*
* 1、try模块中除零异常之后的代码,不能执行
* 2、try...catch模块之后的代码正常执行
* 3、如果没有异常情况,try中的代码正常执行,catch中的代码不执行
* 4、try模块中可能出现的异常类型必须和catch模块中对应,或者是其父类
* 5、当catch中接收异常情况的时候,发现类型不匹配,就会按照默认的处理方式进行处理
*/
try {
//System.out.println(10 / 0);
System.out.println("try模块中除零异常之后的代码,不能执行");
System.out.println("111");
//try模块中可能出现的异常类型必须和catch模块中对应,或者是其父类
} catch (Exception ae) {
ae.printStackTrace();
}
System.out.println("除零异常之后的代码,可以执行");
}
}
(六)try...catch...catch
1、概述:一段代码中可能出现多个异常信息,这个时候就需要多个异常类型进行接收
2、格式:
try {
可能出现问题的代码;
} catch(可能出现异常的类型1 标识符) {
出现了这种问题之后处理方式1;
} catch(可能出现异常的类型2 标识符) {
出现了这种问题之后处理方式2;
} catch(可能出现异常的类型3 标识符) {
出现了这种问题之后处理方式3;
}
public class Demo03_ManyCatch {
public static void main(String[] args) {
/**
* 1、当有多个异常的情况下,会先执行最先出现异常地方捕获的那种异常
* 2、在catch模块中异常类型的定义,如果有子父级关系,子类在上,父类在下;
* 如果没有子父级关系,书写的顺序没有任何影响
* 3、多种异常情况可以采用一种处理方式,在catch小括号中定义异常类型的时候,中间用【|或】隔开
*/
try {
//除零异常
//System.out.println(10 / 0);
//数组越界
int[] arr1 = new int[3];
System.out.println(arr1[3]);
//空指针
String str = null;
System.out.println(str.charAt(0));
} catch (ArrayIndexOutOfBoundsException |
StringIndexOutOfBoundsException e) {
e.printStackTrace();
} catch (ArithmeticException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
(七)try...catch..finally
1、
finally
:关键字;含义:最后,当代码中有必须要执行的代码的时候,放在
finally
模块中
2、格式
try {
可能出现问题的代码;
} catch(可能出现异常的类型 标识符) {
出现了这种问题之后处理方式;
} finally {
必须要执行的代码;
}
public class Demo04_TryCatchFinally {
public static void main(String[] args) {
/**
* 1、finally模块中放的是必须要执行的代码块,一般用于关闭资源
* 2、如果有多个异常都需要判断的时候,就可以在finally模块中进行其他异常的处理
*/
try {
//return;
//System.exit(0);
//可能出现异常的代码
System.out.println(10 / 0);
} catch (ArithmeticException e) {
e.printStackTrace();
} finally {
System.out.println("finally中的代码执行了");
//可能出现异常的代码
try {
String str = null;
System.out.println(str.charAt(0));
} catch (NullPointerException e) {
e.printStackTrace();
}
}
System.out.println("异常处理之后的代码执行了");
}
}
(八)try...finally
1、格式:
try {
可能出现问题的代码;
} finally {
必须要执行的代码;
}
public class Demo05_TryFinally {
public static void main(String[] args) {
try {
//可能出现异常的代码,因为没有catch模块,出现异常之后就会找虚拟机关机
System.out.println(10 / 0);
//因为有finally模块,在关闭虚拟机之前要先去执行finally中的内容
} finally {
System.out.println("finally中的代码");
try {
//finally中有异常情况,出现了异常之后,因为没有catch模块,出现异常之后就会找虚拟机关机
int[] arr = {};
System.out.println(arr[0]);
//但是因为有finally模块,在关机之前先执行完finally中的内容
} finally {
System.out.println("555");
}
}
//没有执行,使用系统默认方式进行处理异常情况
System.out.println("异常之后的代码");
}
}
(九)throw关键字
1、
throw
:关键字;含义:抛出,用于抛出一个异常对象
2、作用:创建一个异常对象,使用
throw
关键字抛出,实现程序的跳转
3、说明:当代码正常允星河的时候,运行时异常不会发生,就相当于没有任何异常对象;当代码中出现了异常的情况,就会创建对象对异常信息进行处理
public class Demo06_Throw {
public static void main(String[] args) {
Person p = new Person();
p.setName("张三");
p.setAge(253);
System.out.println(p.toString());
}
}
public class Person {
private String name;
private int age;
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public Person() {
}
public Person(String name, int age) {
this.name = name;
if (age >= 0 && age <= 150) {
this.age = age;
} else {
System.out.println("年龄输入有误");
throw new RuntimeException();
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age >= 0 && age <= 150) {
this.age = age;
} else {
System.out.println("年龄输入有误");
throw new RuntimeException("年龄不合法");
}
}
}
(十)throws关键字
1、
throws
:关键字;含义:抛出,用于声明一个或者多个异常类型
2、在某个方法中,如果存在一些编译时异常,并且这些编译时异常还未处理,就会报错阻止编译,我们就必须对这些编译时异常进行处理;捕获或者声明
3、声明:就是在方法的声明上,参数列表之后,跟上关键字
throws
,并且注明声明一个或者多个异常类型
4、格式:
修饰符 【static】 返回值类型 方法名(参数列表) throws 异常类型1, 异常类型2... {
}
5、如果某个方法中出现了编译时异常,并且处理的方式是声明,其他方法在调用该方法的时候也需要进行异常的处理
6、如果某个方法中出现了编译时异常,并且处理的方式是捕获,那么后续别的方法在调用的时候就不需要进行异常的处理
7、异常声明原则:尽量声明少的、声明小的异常
import java.text.ParseException;
import java.text.SimpleDateFormat;
public class Demo07_Throws {
public static void main(String[] args) {
/**
* 1、如果某个方法中出现了编译时异常,并且处理的方式是声明,
* 其他方法在调用该方法的时候也需要进行异常的处理
* 2、如果某个方法中出现了编译时异常,并且处理的方式是捕获,
* 那么后续别的方法在调用的时候就不需要进行异常的处理
* 3、异常声明原则:尽量声明少的、声明小的异常
*/
/*try {
test();
} catch (ParseException e) {
e.printStackTrace();
}*/
//test();
}
public static void test() throws StringIndexOutOfBoundsException,
ArrayIndexOutOfBoundsException, NullPointerException,
ArithmeticException, ParseException {
try {
new SimpleDateFormat("").parse("");
} catch (ParseException e) {
e.printStackTrace();
}
}
}
(十一)throw和throws
1、
throw
是对已经出现的异常对象进行抛出,
throws
关键字是对可能发生的异常类型进行声明
2、
throw
是对异常对象实实在在的抛出,一旦执行到了
throw
关键字,就一定会有一个异常对象出现,throws关键字是对多个可能出现的异常类型的声明,即使声明多个异常类型,也有可能一个都不发生
3、
throw
后面跟的是一个异常对象;
throws
后面跟的是一个或者多个异常类型
4、异常声明原则:尽量声明少的、声明小的异常
(十二)方法重写的补充
1、在子父类中,方法名相同,参数列表相同,与返回值类型有关,
2、有关:子类返回值类型要么和父类保持一致;要么子类返回值类型是父类返回值类型的子类
3、如果父类有异常情况,并且进行了异常类型的声明,那么子类在重写的时候也需要进行异常的处理,子类在处理异常的时候,可以声明也可以捕获
4、如果父类有异常情况,并且进行了异常类型的捕获,那么子类在重写的时候就不需要进行异常的处理
5、如果父类没有异常,子类有了异常情况,这个时候不能进行异常的声明,只能捕获异常
import java.text.ParseException;
import java.text.SimpleDateFormat;
public class Demo08_Method {
}
class Father {
/**
* 1、如果父类有异常情况,并且进行了异常类型的声明,那么子类在重写的时候也需要进行异常的处理,
* 子类在处理异常的时候,可以声明也可以捕获
* 2、如果父类有异常情况,并且进行了异常类型的捕获,那么子类在重写的时候就不需要进行异常的处理
* 3、如果父类没有异常,子类有了异常情况,这个时候不能进行异常的声明,只能捕获异常
* @throws ParseException
*/
public void test3() {
}
public void test2() {
try {
new SimpleDateFormat("").parse("");
} catch (ParseException e) {
e.printStackTrace();
}
}
public void test1() throws ParseException {
new SimpleDateFormat("").parse("");
}
}
class Son extends Father {
@Override
public void test3() {
try {
new SimpleDateFormat("").parse("");
} catch (ParseException e) {
e.printStackTrace();
}
}
@Override
public void test2() {
super.test2();
}
@Override
public void test1() {
try {
super.test1();
} catch (ParseException e) {
e.printStackTrace();
}
}
}
(十三)自定义异常
1、官方提供的异常类型有限,可能不能满足日常开发需求,如果自己想要说明出现的问题是什么就需要自定义类型异常,对异常情况进行详细的描述
2、步骤:
(1)创建一个异常类型,类名做到见名知意
(2)需要让自定义类型异常加入异常体系
如果自定义类型异常是运行时异常:就继承RuntimeException
如果自定义类型异常是编译时异常,就继承Exception
(3)因为所有异常都是为了方便统一处理,都会使用到
Throwable
中的方法,并且为了以后方便创建异常对象和处理异常对象,根据父类构造方法的情况,提供相应的构造方法
public class AgeNotIsTrueException extends RuntimeException {
public AgeNotIsTrueException() {
}
public AgeNotIsTrueException(String message) {
super(message);
}
public AgeNotIsTrueException(String message, Throwable cause) {
super(message, cause);
}
public AgeNotIsTrueException(Throwable cause) {
super(cause);
}
public AgeNotIsTrueException(String message, Throwable cause, boolean
enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}