JAVA基础 —— 认识异常

JAVA基础 —— 认识异常,第1张

JAVA基础 —— 认识异常

目录

1 异常的背景

1.1初识异常

1.2 防御式编程

2 异常的基本用法

2.1捕获异常

2.2 异常的处理方式

2.3 finally的使用

2.4 异常处理流程

2.5 抛出异常

2.5.1 异常说明

3.自定义异常类


1 异常的背景 1.1初识异常

相信我们在日常编程之中一定遇到过一些“异常”,例如:常见的数组越界异常及空指针异常。

数组越界异常:

    public static void main(String[] args) {
        int[] arr = {1,2};
        System.out.println(arr[2]);
    }

 空指针异常:

public static void main(String[] args) {
        int[] arr = null;
        System.out.println(arr[2]);
    }

 所谓异常,就是程序在运行时,出现错误时通知调用者的一种机制。异常的种类有很多,不同的异常有不同的含义,处理方式也不尽相同。

1.2 防御式编程

在编程的时候,即使我们尽力去规避错误,但是错误在代码当中不可能完全消除,因此我们需要在出现错误时让程序可以即使通知我们,目前我们有两种主要的机制:

1.LBYL:Look Before You Leap. 在 *** 作之前就做充分的检查。

2.EAFP: It's Easier to Ask Forgiveness than Permission. " 先 *** 作, 遇到问题再处理。

LBYL风格的代码(不使用异常):

boolean ret = false;
ret = 登陆游戏();
if (!ret) {
 处理登陆游戏错误;
    return; }
ret = 开始匹配();
if (!ret) {
 处理匹配错误;
    return; }
ret = 游戏确认();
if (!ret) {
 处理游戏确认错误;
    return; }

EAFP风格的代码(利用异常):

try {
    登陆游戏();
    开始匹配();
    游戏确认();
    选择英雄();
    载入游戏画面();
   ...
} catch (登陆游戏异常) {
    处理登陆游戏异常;
} catch (开始匹配异常) {
 处理开始匹配异常;
} catch (游戏确认异常) {
 处理游戏确认异常;
} catch (选择英雄异常) {
 处理选择英雄异常;
} catch (载入游戏画面异常) {
 处理载入游戏画面异常; }
......
2 异常的基本用法 2.1捕获异常

基本语法:

try { 有可能出现异常的语句 ; }[ catch ( 异常类型 异常对象 ) { } ... ] [ finally { 异常的出口 }]

例:

   public static void main(String[] args) {
        int[] arr = null;
        try {
            System.out.println(arr);
        } catch(NullPointerException e) {
            e.printStackTrace();
            System.out.println("捕捉到了一个空指针异常!");
        } finally {
            System.out.println("我执行了!");
        }
    }

1.假如说我们在编写代码的时候并没有使用上述代码,也就没有对异常进行捕捉。

    public static void main(String[] args) {
        int[] arr = null;
        System.out.println(arr);
        System.out.println("我执行了!");
    }

 执行结果:

我们发现,一旦程序出现异常就会整个程序崩溃,下面的代码也就无法执行了,最后的一条语句并没有正确输出。

 2.对异常进行捕捉

   public static void main3(String[] args) {
        int[] arr = null;
        try {
            System.out.println(arr[0]);
            System.out.println("try");
        } catch(NullPointerException e) {
            e.printStackTrace();
            System.out.println("捕捉到了一个空指针异常!");
        }
        System.out.println("我执行了!");
    }

执行结果:

我们发现 , 一旦 try 中出现异常 , 那么 try 代码块中的程序就不会继续执行 , 而是交给 catch 中的代码来执行。 catch 执行完毕会继续往下执行。 2.2 异常的处理方式 异常的种类有很多, 我们要根据不同的业务场景来决定。 对于比较严重的问题(例如和算钱相关的场景), 应该让程序直接崩溃, 防止造成更严重的后果。对于不太严重的问题(大多数场景), 可以记录错误日志, 并通过监控报警程序及时通知程序猿对于可能会恢复的问题(和网络相关的场景), 可以尝试进行重试。 在我们当前的代码中采取的是经过简化的第二种方式。 我们记录的错误日志是出现异常的方法调用信息, 能很快速的让我们找到出现异常的位置。 在处理异常的时候,同一段代码可能会抛出不同的异常,因此我们可以使用多个catch对对应的异常进行捕获。 例:
    public static void main(String[] args) {
        int[] arr1 = new int[0];
        int[] arr2 = null;
        try {
            System.out.println(arr1[0]);
        } catch (NullPointerException e) {
            e.printStackTrace();
            System.out.println("我捕捉到了一个空指针异常!");
        } catch (IndexOutOfBoundsException e) {
            e.printStackTrace();
            System.out.println("我捕捉到了一个数组越界异常!");
        }
        System.out.println("我执行了!");
    }

执行结果: 

一段代码可能会抛出多种不同的异常 , 不同的异常有不同的处理方式 。 因此可以搭配多个 catch 代码块。 如果多个异常的处理方式是完全相同, 也可以写成这样 :
    public static void main(String[] args) {
        int[] arr1 = new int[0];
        try {
            System.out.println(arr1[0]);
        } catch (NullPointerException | IndexOutOfBoundsException e) {
            e.printStackTrace();
            System.out.println("我捕捉到了一个 空指针/数组越界 异常!");
        }
        System.out.println("我执行了!");
    }

当然,如果我们嫌一个一个捕获不同的异常麻烦,我们也可以一次性捕捉所有的异常(不推荐使用):

    public static void main(String[] args) {
        int[] arr1 = new int[0];
        try {
            System.out.println(arr1[0]);
        } catch (Exception e) {//一次性捕获所有异常,但不推荐使用
            e.printStackTrace();//如果没有这条语句,我们根本不知道是发生了什么异常
            System.out.println("我捕捉到了一个异常!");
        }
        System.out.println("我执行了!");
    }

因为Exception是所有异常的父类,所以这个类型可以捕获所有的异常。

2.3 finally的使用

finally表示最后被的善后工作,一般用作释放资源,例如我们使用了Scanner,或者打开了文件,我们都可以在finally内关闭

代码示例:

    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        try {
            int a = scan.nextInt();
            System.out.println(div(a));
        } catch(Exception e) {
            e.printStackTrace();
        } finally {
            scan.close();
        }
    }
    public static int div(int b) {
        return 100 / b;
    }

无论是否发生异常,finally当中的代码都一定会被执行。因此我们也需要注意:finally当中要尽可能避免使用return。

另外,try也可以负责回收资源

代码示例:

    public static void main(String[] args) {
        try (Scanner scan = new Scanner(System.in)) {
            int a = scan.nextInt();
            System.out.println(div(a));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

注意:如果发生异常之后,当前方法没有处理异常的方式就会沿着调用栈向上传递。如果一直没有处理异常,那么最终就会交给JVM处理,程序也随之崩溃。

2.4 异常处理流程 1.程序先执行 try 中的代码 2.如果 try 中的代码出现异常, 就会结束 try 中的代码, 看和 catch 中的异常类型是否匹配 3.如果找到匹配的异常类型, 就会执行 catch 中的代码 4.如果没有找到匹配的异常类型, 就会将异常向上传递到上层调用者 5.无论是否找到匹配的异常类型, finally 中的代码都会被执行到(在该方法结束之前执行) 6.如果上层调用者也没有处理的了异常, 就继续向上传递 7.一直到 main 方法也没有合适的代码处理异常, 就会交给 JVM 来进行处理, 此时程序就会异常终止 2.5 抛出异常

除了Java内置的类会抛出一些异常之外,我们也可以手动抛出一个异常,我们使用throw这个关键字来完成。

代码示例:

    public static void main(String[] args) {
        div(3, 0);
    }
    public static void div(int x, int y) {
      if(y == 0) {
          throw new ArithmeticException("y == 0");//手动抛出异常
      }
        System.out.println(x / y);
    }

在手动抛出异常的时候,我们还可以对这个异常添加一些描述。

2.5.1 异常说明 我们在处理异常的时候 , 通常希望知道这段代码中究竟会出现哪些可能的异常, 我们可以使用throws 关键字 , 把可能抛出的异常显式的标注在方法定义的位置 .。 从而提醒调用者要注意捕获这些异常。 代码示例:
   public static void div(int x, int y) throws ArithmeticException {
      if(y == 0) {
          throw new ArithmeticException("y == 0");//手动抛出异常
      }
        System.out.println(x / y);
    }
3.自定义异常类

Java当中虽然实现丰富的异常类,但是实际工作场景中可能还有一些情况需要我们直接去定义一个新的异常类。

例如我们现在来实现一个登陆功能。

public class Main {
    private static final String user = "张三";
    private static final String password = "ab123";
    public static void main(String[] args) throws UserNameError,PasswordError{
        login("zhangsan", "ab123");
    }
    public static void login(String user , String password) throws UserNameError,PasswordError{
        if(!Main.user.equals(user)) {
            throw new UserNameError("用户名错误!");
        }
        if(!Main.password.equals(password)) {
            throw new PasswordError("密码错误!");
        }
        System.out.println("登陆成功!");
    }
}

异常定义:

class UserNameError extends Exception {
    public UserNameError(String message) {
        super(message);
    }
}

class PasswordError extends Exception {
    public PasswordError(String message) {
        super(message);
    }
}

 

此时我们在处理用户名密码错误的时候可能就需要抛出两种异常。 我们可以基于已有的异常类进行扩展 ( 继承 ), 创建和我们业务相关的异常类。 我们也可以将上述代码改成:
    public static void main(String[] args) {
        try {
            login("zhangsan", "ab123");
        } catch(UserNameError e) {
            e.printStackTrace();
        } catch(PasswordError e) {
            e.printStackTrace();
        }
    }

以上就是Java异常认识的全部内容了,喜欢的话请点个赞吧!

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5611951.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-15
下一篇 2022-12-15

发表评论

登录后才能评论

评论列表(0条)

保存