异常的概念
所谓异常是指程序中出现一些意外状况,不可控的,
出现此类问题如果程序不进行异常的处理,会导致程序终止,导致后续功能无法正常的运行。
异常的继承结构图

异常总结:
Throwable 异常的基类代表所有异常
Error:严重错误,依靠程序本身无法恢复,没有办法进行异常处理...
比如CPU资源不够用了,或者栈内存溢出等等...
Exception:程序异常,程序中出现一种突发状况,进行异常处理之后,程序是可以恢复运行的。
1.运行时异常:程序在编译的时候能够通过,在运行的时候出现突发状况,比如:除法运算分母为0,数组越界,空指针等等都属于运行时异常(编译时正常)。可以处理,也可以不处理。(都能够正常编译)
不处理:出现异常程序直接终止,处理了,自动跳过异常,然后执行后续的程序
2.编译时异常:必须进行异常处理,否则无法完成编译。(比如:文件,IO流异常,sql异常)。
异常的关键字
try:用来监测可能出现异常的代码块,一般与catch合起来用。
catch:如果对应的try中出现对应类型的异常,则通过catch进行捕获此异常,对此异常进行处理。
throw:手动抛出异常(编写工具类的时候,当输入内容不符合要求的时候,手动抛出异常,用来提醒程序员哪里出错了)
throws:声明方法需要抛出来的异常(提醒调用此方法的程序员,调用此方法可能会出现什么异常,提醒其进行异常处理)
声明的是是编译时异常,那么调用此方法必须进行异常处理。
声明的是运行时异常,那么调用此方法可以进行异常处理,也可以不处理。
finally:最终的,无论是否发生异常,都会执行,一般用于释放try -catch 里面的资源(打开了一个IO流,打开了一个数据库连接,用完了,可以在finally里面释放资源)
处理异常
try-catch
try{
...代码块
}catch(异常类型 e){
....
}
注意:
1、try中可能会抛出多个异常对象,那么就可以使用catch来处理这些异常对象
2、如果try中产生了异常,那么就会执行catch中的异常处理逻辑,执行完毕catch中的处理逻辑,继续执行try...catch之后的代码
如果try中没有产生异常,那么就不会执行catch中的异常的处理的逻辑,执行完try中的代码,继续执行try...catch之后的代码
public static void main(String[] args) {
//1.进行异常处理
try {
int i=1/0;
}catch(ArithmeticException e) {
e.printStackTrace();
}
//2.进行异常处理必须属于同一种类型的异常 才能正常处理
try {
String str=null;
System.out.println(str.equals("123"));
}catch (NullPointerException e) {
e.printStackTrace();
}
System.out.println("---------------------------------------------------");
//3.同时处理多个异常(可以解决多种不同类型的异常,但是一次只能处理一种异常) 无多态的思想
try {
int i=1/10;
String str="123";
System.out.println(str.equals("123"));
int[] arr=new int[10];
System.out.println(arr[10]);
}catch(ArithmeticException e1) {//1.处理数学异常
e1.printStackTrace();
}catch (NullPointerException e2) {//2.空指针异常
e2.printStackTrace();
}catch (ArrayIndexOutOfBoundsException e3) {//3.数组越界异常
e3.printStackTrace();
}
System.out.println("--------------------------");
//4. 利用多态的思维方式 进行异常处理(处理多种不同类型的异常)
try {
int i=1/0;
String str="123";
System.out.println(str.equals("123"));
int[] arr=new int[10];
System.out.println(arr[10]);
}catch (RuntimeException e) {// 可以处理任意RunTimeException 的类型(所有子类)
e.printStackTrace();
}
//5. 处理多个异常的设计思路(多个catch中,先写子类的异常,父类异常必须写在子类异常的后面)
try {
int i=1/10;
String str="123";
System.out.println(str.equals("123"));
int[] arr=new int[10];
System.out.println(arr[10]);
}catch(ArithmeticException e1) {//1.处理数学异常
e1.printStackTrace();
}catch (NullPointerException e2) {//2.空指针异常
e2.printStackTrace();
}catch (ArrayIndexOutOfBoundsException e3) {//3.数组越界异常
e3.printStackTrace();
}catch(Exception e) {//4.处理其他异常
e.printStackTrace();
}
//2.后续程序任然会执行,不会受到异常的影响
System.out.println("程序结束...");
}
throws
声明方法需要抛出来的异常,交给调用者去进行异常处理。
throws关键字:异常处理的第一种方式,交给别人处理
作用:
当方法内部抛出异常对象的时候,那么我们就必须处理这个异常对象
可以用throws关键字处理异常对象,会把异常对象声明抛出给方法的调用者处理(自己不处理,交给别人)
交给JVM处理-->中断处理
使用格式:
修饰符 返回值类型 方法名(参数列表) throws {
throw AAAException();
}
注意:
1。throws关键字必须写在方法声明处
2。throws关键字后边声明的异常必须是Exception或者是Exception的子类
3。方法内部如果抛出了很多个异常对象,那么throws必须也声明多个异常
如果抛出的多个异常有子父类关系,那么直接声明父类即可。
4。调用了一个声明抛出异常的方法,我们就必须处理声明的异常
要么继续使用throws声明抛出,交给方法的调用者处理,最终交给JVM
要么try...catch 自己处理
声明方法需要抛出来的异常
public static void main(String[] args) {
try {
method1();
method2();
method3();
method4();
}catch (NullPointerException e) {
e.printStackTrace();
} catch (ArrayIndexOutOfBoundsException e) {
e.printStackTrace();
}catch (Exception e) {
e.printStackTrace();
}
}
//1.编译时异常1
public static void method1() throws IOException{
System.out.println("声明第一个编译时异常....");
}
//2.编译时异常2
public static void method2() throws SQLException{
System.out.println("声明第二个编译时异常...");
}
//3.运行时异常1
public static void method3() throws NullPointerException{
System.out.println("声明第一个运行时异常");
}
//4.运行时异常2
public static void method4() throws ArrayIndexOutOfBoundsException {
System.out.println("声明第二个运行时异常");
}
throw
故意自己抛出异常。(输入内容明显不对的时候,为了调用者)
作用:可以使用Throw关键字在指定的方法中抛出指定的异常
使用格式:
throw new xxxException("异常产生的原因")
注意:
1。throw必须写在方法的内部
2。throw关键字后边new的对象必须是Exception的子类对象
3。throw关键字抛出指定的异常对象,我们就必须处理这个异常对象
throw关键字后面创建的是RuntimeException或者是RuntimeException的子类,我们可以不处理,交给JVM(打印异常对象,中断程序)
throw关键字后边创建的是编译异常(写代码的时候报错),我们就必须处理掉这个异常,要么throws,要么try...catch
throw:手动抛出异常 (提醒调用者出现什么错误了...) 封装工具类,自定义异常...
public static void main(String[] args) {
divide(100,0);
}
public static int divide(int num1,int num2) {
if(num2==0) {
//手动抛出异常,提醒调用者...
throw new ArithmeticException("分母不能为0");
}
return num1/num2;
}
finally
try中无论是否发生异常finally里面的代码都会执行,不仅如此try中如果执行了return ,finally里面的代码照样执行。(先执行return再执行finally)
public static void main(String[] args) {
add();
}
public static int add() {
int res=0;
try {
res+=10;
return res++;
}catch (Exception e) {
e.printStackTrace();
System.out.println("异常处理:"+res);//10
}finally {
System.out.println("程序结束:"+res);//11
}
return res;
}
父子类异常
子父类的异常:
如果父类抛出了多个异常,子类重写父类方法时,抛出和父类相同的异常或者是父类异常的子类或者是不抛出异常。
父类方法没有抛出异常,子类重写父类该方法时也不可抛出异常。此时子类产生该异常,只能捕获处理,不能声明抛出。
注意:
父类异常什么样,子类异常就是什么样
class Fu {
public void show01() throws NullPointerException,ClassCastException{}
public void show02() throws IndexOutOfBoundsException{}
public void show03() throws IndexOutOfBoundsException{}
public void show04() {}
}
class Zi extends Fu {
//子类重写父类方法时,抛出和父类相同的异常
public void show01() throws NullPointerException,ClassCastException{}
//子类重写父类方法时,抛出父类异常的子类
public void show02() throws ArrayIndexOutOfBoundsException{}
//子类重写父类方法时,可以不抛出异常
public void show03() {}
//父类方法没有抛出异常,子类重写父类该方法时也不可抛出异常
//捕获处理,不能声明抛出
public void show04() {
try {
}catch (Exception e) {}
}
}
自定义异常
编写一个类继承Exception 或者其子类的过程我们称之为自定义异常
1.为什么要使用到自定义异常?
java提供的异常类不够我们使用,需要自己定义一些异常类
程序中,年龄只能是0-100之间(系统底层并不知道),比如性别只能是男和女,像上述这些系统底层没有的异常,才需要根据项目的需求进行自定义异常。
<1>继承的是编译时异常,那么得到的自定义异常就属于编译时异常 Exception
<2>.如果继承的是运行时异常,那么得到的自定义异常就属于运行时异常 RuntimeException
格式:
lass XXXException extends Exception / RuntimeException {
添加一个空参数的构造方法
添加一个带异常信息的构造方法
}
注意:
1、自定义异常类一般都是以Exception结尾,说明该类是一个异常类
2、自定义异常类,必须继承Exception 或 RuntimeException
继承Exception:自定义的异常类就是编译期异常,如果方法内部抛出了编译期异常就必须处理这个异常要么throws,要么try...
继承RuntimeException:运行时异常无需处理,交给虚拟机中断处理
代码实现:
//1.自定义一个异常
public class AgeException extends Exception{
public AgeException() {}
public AgeException(String message) {
super(message);
}
}
//2.测试类中调用
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int age=0;
while(true) {
try {
System.out.println("请输入一个年龄:");
age=sc.nextInt();
if(age<0||age>100) {
throw new AgeException("请输入0-100之间的年龄...");
}else {
break;
}
}catch (InputMismatchException e) {
System.err.println("您输入的格式不正确,请重新输入...");
sc.nextLine();
} catch (AgeException e) {
System.err.println(e.getMessage());
}
}
System.out.println("年龄合格:"+age);
}
-------------------------------------------------------------------------------------