Java中的异常

目录

1.什么是异常

2.Java中有哪些异常

3.异常的处理流程

1.EAFP

2.防御式编程

try……catch代码块

finally代码块:

3.异常的抛出

throws:

​编辑 throw关键字

自定义异常:


1.什么是异常

在程序执行过程中发生的不正常行为/非预期行为,称为异常

public class NormalException {
    public static void main(String[] args) {
        //异常之前的代码
        System.out.println(10/2);
        System.out.println(10/0);
        System.out.println("after exception");
    }
}

        int[]arr={1,3,5,7,9};
        System.out.println(arr.length);
        arr=null;
        System.out.println(arr[0]);
        System.out.println("after exception");

通过以上两个例子我们发现:

1.当异常发生之后,异常之后的代码不再执行

2.产生错误的原因不同,相关抛出的错误名称也不同

Java中一切皆对象,产生异常的原因不同,就会有对应的“异常类”的产生,因此在Java中异常也是类。

2.Java中有哪些异常

说明:

1.Thorwable这个类是Java中异常的最顶层父类,继承自这个类的子类,当发生一些特殊场景时,由JVM来自动产生该类的对象并传递给程序(就是对象)

2.Error及其子类(内部错误):这类异常一旦发生,当前程序是无法解决的,属于JVM的内部错误。栈溢出Error,堆内溢出Error,这类问题一旦产生,程序只有退出。

public class StackError {
    public static void main(String[] args) {
        //方法的调用相当于一个“栈帧”入栈的过程。
        //每当程序调用一次方法,就会产生一个栈帧这个数据结构
        //当无限的调用方法时,一定会将“方法栈”沾满
        fun();
    }
    public static void fun(){
        int a=10;
        fun();
    }
}

3.Exception及其子类:这种异常属于程序开发过程中,可以由程序员写代码进行异常处理的异常类型,当异常发生之后,程序可以捕获该异常,使得异常发生之后,正常的代码可以继续执行。

3.异常的处理流程

以王者荣耀的启动加载为例。两种不同的处理方式:

1.EAFP

try{

//可能出现的方法或代码

//尝试运行

登录游戏:

开始匹配:

确认进入:

选择英雄:

载入界面:

}cath(处理游戏登录异常){

//若登录方法出现问题,在这个代码块中处理

}cath(匹配异常){

//在这个代码块中处理匹配异常

}cath(.......){

//.......

}

2.防御式编程

确保某个方法无误之后再进行执行

boolean ret=false;

ret=登录游戏();

if(!ret){

   ret=开始匹配();

}

if(!ret){

   ret=确认进入();
}

Java中使用方法1。

异常中的五个关键字:try cath finally throws throw

两个手段

异常的捕获与处理:在当前程序中处理该异常 try cath finally

try{

存放可能出现异常的代码

}cath(异常类型 异常对象){

   出现该类异常之后,如何处理

}finally{

   无论是否产生异常,最后都会执行的代码

}

三种组合:

try……cath

try……finally

try……cath……finally

try……catch……代码块:异常的捕获并处理

出现异常,JVM就会寻找与之相关的catch代码块

捕获异常,只能捕获特定类型的异常对象,当前catch代码块只能处理除0异常

try……catch代码块

public class TryAndCatch {
    public static void main(String[] args) {
        System.out.println(10+3);
        try{
            //try代码块存放可能出现问题的代码
            System.out.println(10/5);
            System.out.println(10/0);
            System.out.println("异常之后的代码块");
        }catch (ArithmeticException e){
            System.out.println("除0异常");
        }
        System.out.println("try……catch之后的代码块");
    }
}

1.若try中出现的异常,有与之相关的catch代码块捕获,程序处理异常之后,恢复执行直到结束。

2.若catch捕获的异常类型与try中产生的异常类型不相同时,程序还是会退出。 

public class TryAndCatch {
    public static void main(String[] args) {
        System.out.println(10+3);
        try{
            //try代码块存放可能出现问题的代码
            System.out.println(10/5);
            int[]arr=null;
            System.out.println(arr.length);
            System.out.println(10/0);
            System.out.println("异常之后的代码块");
        }catch (ArithmeticException e){
            System.out.println("除0异常");
        }
        System.out.println("try……catch之后的代码块");
    }
}

当try中产生的异常有多种类型时,可以使用多个catch代码块进行捕获处理。

public class TryAndCatch {
    public static void main(String[] args) {
        System.out.println(10+3);
        try{
            //try代码块存放可能出现问题的代码
            System.out.println(10/5);
            int[]arr=null;
            System.out.println(arr.length);
            System.out.println(10/0);
            System.out.println("异常之后的代码块");
        }catch (ArithmeticException e){
            System.out.println("除0异常");
        }catch (NullPointerException e){
            System.out.println("空指针异常");
        }
        System.out.println("try……catch之后的代码块");
    }
}

 

关于多个代码块的说明:

由于异常也是类,异常类之间存在继承关系。

当try代码块中出现很多异常时,且编码时也不确定到底会有多少种异常,就可以使用try代码块捕获exception异常(不推荐)

public class TryAndCatch {
    public static void main(String[] args) {
        System.out.println(10+3);
        try {
            //try代码块存放可能出现问题的代码
            System.out.println(10 / 5);
            int[] arr = {1, 3, 5, 7, 9};
            System.out.println(arr[5]);
            System.out.println(10 / 0);
            System.out.println("异常之后的代码块");
            }catch (Exception e){
            System.out.println("捕获异常");
        }
        System.out.println("try……catch之后的代码块");
    }
}

 

 若先定义的是父类的catch代码块,则子类catch代码块永远不会执行

若出现多个catch代码块时,程序只会进入一个catch代码块执行

多个catch块只会执行其中一个,处理之后,从第一个正常代码开始恢复执行。

public class TryAndCatch {
    public static void main(String[] args) {
        System.out.println(10+3);
        try {
            //try代码块存放可能出现问题的代码
            System.out.println(10 / 5);
            int[] arr = {1, 3, 5, 7, 9};
            System.out.println(arr[6]);
            int[]arr1=null;
            System.out.println(arr[0]);
            System.out.println(10 / 0);
            System.out.println("异常之后的代码块");
        }catch (ArithmeticException e){
            System.out.println("除0异常");
        }catch (NullPointerException e){
            System.out.println("空指针异常");
        }catch (ArrayIndexOutOfBoundsException e){
            System.out.println("数组越界异常");
        }
//        }catch (Exception e){
//            System.out.println("捕获异常");
//        }
//        catch (NullPointerException e){
//
//        }
        System.out.println("try……catch之后的代码块");
    }
}

打印异常的错误堆栈

当异常捕获时,可以调用异常类提供的printStackTrace方法来输出异常的具体信息

public class TryAndCatch {
    public static void main(String[] args) {
        System.out.println(10+3);
        try {
            //try代码块存放可能出现问题的代码
            System.out.println(10 / 5);
            int[] arr = {1, 3, 5, 7, 9};
            System.out.println(arr[6]);
            int[]arr1=null;
            System.out.println(arr[0]);
            System.out.println(10 / 0);
            System.out.println("异常之后的代码块");
        }catch (ArithmeticException e){
            e.printStackTrace();
            System.out.println("除0异常");
        }catch (NullPointerException e){
            e.printStackTrace();
            System.out.println("空指针异常");
        }catch (ArrayIndexOutOfBoundsException e){
            e.printStackTrace();
            System.out.println("数组越界异常");
        }
//        }catch (Exception e){
//            System.out.println("捕获异常");
//        }
//        catch (NullPointerException e){
//
//        }
        System.out.println("try……catch之后的代码块");
    }
}

 

finally代码块:

无论是否有异常产生,都一定会执行的代码块。

public class TryFinally {
    public static void main(String[] args) {
        try{
            System.out.println(10/5);
            System.out.println(10/0);
        }finally {
            System.out.println("finally中的代码块");//1
        }
        System.out.println("异常体系之后的代码块");//2
    }
}

1位置不管是否有异常且是否处理,finally位置的代码,都一定会执行

2位置的代码,若程序产生异常且未正常处理时,不会执行 

关于finally代码块和return语句:

只要finally代码块存在return语句,无论是否有异常产生,finally中的返回值都会覆盖try或者catch中的返回值。因此一般在finally中不要写返回值

public static int fun(){
        try {
            System.out.println("try中的代码块");
            return 1;
        }catch (Exception e){
            System.out.println("catch中的代码块");
            return 2;
        }finally {
            System.out.println("finally中的代码块");
            return 3;
        }
    }

3.异常的抛出

throws:

用在方法声明,表示当前方法可能产生的异常,且当前方法不处理该异常。异常产生之后,将异常交给调用者处理。

public class ThrowsTest {
    public static void main(String[] args) {
        fun();

    }
    public static void fun()throws NullPointerException{
        int[]arr={1,3,5,7,9};
        System.out.println(arr.length);
        arr=null;
        System.out.println(arr.length);
    }
}

方法的调用链:JVM->main->fun

若方法中产生了多种异常,可以在方法声明处,声明多个异常类型,和多个catch块类似,实际抛出时,只会抛出遇到的第一个类型。

public class ThrowsTest {
    public static void main(String[] args) {
        fun();

    }
    public static void fun()throws NullPointerException,ArrayIndexOutOfBoundsException{
        int[]arr={1,3,5,7,9};
        System.out.println(arr[5]);
        System.out.println(arr.length);
        arr=null;
        System.out.println(arr.length);
    }
}

 throw关键字

用在方法体内部,人为进行异常对象的抛出,一般这个关键字搭配自定义异常类来使用。

throw关键字由自己程序产生异常

public class ThrowTest {
    public static void main(String[] args) {
        fun();

    }
    public static void fun(){
        System.out.println("方法开始");
        //此处由程序自己产生了一个空指针的异常现象
        //当异常对象产生时==此处发生了空指针异常
        throw new NullPointerException();
    }
}

综上:

1.throws关键字用在方法声明,表示该方法可能产生的异常,且该方法不处理,交给调用者处理。

2.throw关键字用在方法体内部,表示人为进行异常对象的产生,当异常对象产生时,就相当于此处发生了该类型的异常

一般throw搭配自定义的异常来使用。

自定义异常:

虽然JDK提供了各种各样的异常类,但是实际开发过程中会有很多的业务类异常(例如:命名错误,密码错误),因此开发项目时,会根据项目的具体异常来自定义异常类。

要定义异常类,需要继承JDK的异常父类

补充说明:

关于受查异常与非受查异常

图中:

1.红色框及其子类都属于受查异常,指的是程序编译阶段,若产生了受查异常,必须进行异常处理的异常类,称为受查异常。

无论当前是否有异常产生,调用位置必须进行异常处理,要么try……catch,要么继续向调用链抛出该异常。

public class CheckExecption {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person=new Person("王源");
        Person person1=person.clone();

    }
}
class Person implements Cloneable{
    private String name;

    public Person(String name) {
    }

    public Person clone() throws CloneNotSupportedException {
        return (Person) super.clone();
    }
}


public class CheckExecption {
    public static void main(String[] args) {
        Person person=new Person("王源");
        try {
            Person person1=person.clone();
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }

    }
}
class Person implements Cloneable{
    private String name;

    public Person(String name) {
    }

    public Person clone() throws CloneNotSupportedException {
        return (Person) super.clone();
    }
}

2.蓝色框以及其子类都属于非受查异常,编译阶段碰到非受异常,可以不进行异常处理,运行时出现问题再解决。

public class NonCheckedEXception {
    public static void main(String[] args) {
        fun();
    }
    public static void fun()throws NullPointerException{
        System.out.println("hello");
        int[]arr=null;
        System.out.println(arr.length);
    }
}

自定义的异常只需要继承自Exception或RuntimeException即可,若继承Exception,则当前异常类就属于受查异常,若继承RuntimeException,则当前异常类就属于非受查异常。

public class MyException {
    private static String userName="王源";
    private  static String password="1234";
    public static void main(String[] args) throws UserNameException {
        login("wy","1234");

    }
    public static boolean login(String userName,String password) throws UserNameException {
        if(userName.equals(MyException.userName)){
            System.out.println("用户名正确");
        }else {
            throw new UserNameException("用户名错误");
        }
        if(password.equals(MyException.password)){
            System.out.println("密码正确");
        }else {
            throw new PassWordException("密码错误");
        }
        return true;
    }

}
class UserNameException extends Exception{
    public UserNameException(String msg){
        super(msg);
    }

}
class PassWordException extends RuntimeException{
    public PassWordException(String msg){
        super(msg);
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小李(写代码版)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值