IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Java中关于异常的基本用法介绍 -> 正文阅读

[Java知识库]Java中关于异常的基本用法介绍

前言

所谓异常指的就是程序在运行时出现错误时通知调用者的一种机制。
有些错误是这样的, 例如将 System.out.println 拼写错了, 写成了system.out.println. 此时编译过程中就会出错, 这是 “编译期” 出错。而运行时指的是程序已经编译通过得到 class 文件了, 再由 JVM 执行过程中出现的错误。
异常的种类有很多, 不同种类的异常具有不同的含义, 也有不同的处理方式。


一、常见的异常

1.1算数异常

public static void main(String[] args) {
        System.out.println(10/0);
    }

执行结果:
在这里插入图片描述

1.2数组下标越界异常

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

执行结果:
在这里插入图片描述

1.3空指针异常

public class Test {
	public int num = 10;
	public static void main(String[] args) {
	Test t = null;
	System.out.println(t.num);
	}
}

运行结果:
在这里插入图片描述

1.4克隆异常

class Person implements Cloneable{
    public int age;
    
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class teat01 {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person = new Person();
        Person person1 = (Person)person.clone();
    }

1.5 输入不匹配异常

public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int ret = scanner.nextInt();
        System.out.println(ret);
    }

要求输入数字,错误输入成字母
运行结果:
在这里插入图片描述

二、防御式编程

错误在代码中是客观存在的. 因此我们要让程序出现问题的时候及时通知程序员. 这里有两种主要的方式:

  • LBYL: Look Before You Leap. 在操作之前就做充分的检查.
  • EAFP: It's Easier to Ask Forgiveness than Permission. “事后获取原谅比事前获取许可更容易”. 也就是先操作, 遇到问题再处理.
    异常的核心思想就是 EAFP

三、异常的基本用法

3.1捕获异常

基本语法:

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

} 
finally {
异常的出口
}
  • try代码块中放的是可能出现异常的代码.
  • catch 代码块中放的是出现异常后的处理行为.
  • finally 代码块中的代码用于处理善后工作, 会在最后执行.
    其中 catchfinally 都可以根据情况选择加或者不加.

示例:

 public static void main(String[] args) {
        int[] arr =  {1,2,3};
        try{
            System.out.println(arr[9]);
            System.out.println("nihao");//这行代码不会被执行
        }catch (ArrayIndexOutOfBoundsException e){
            e.printStackTrace();
            System.out.println("捕获到数组越界异常");
        }
        System.out.println("niHao");
    }

运行结果:
在这里插入图片描述
一旦 try 中出现异常, 那么 try 代码块中的程序就不会继续执行, 而是交给 catch 中的代码来执行. catch 执行完毕会继续往下执行。如果不处理异常,那么这个异常机会交给JVM处理,一旦交给JVM处理,程序就立马终止了。

3.2关于异常的处理方式

异常的种类有很多, 我们要根据不同的业务场景来决定。

  • 对于比较严重的问题(例如和算钱相关的场景), 应该让程序直接崩溃, 防止造成更严重的后果。
  • 对于不太严重的问题(大多数场景), 可以记录错误日志, 并通过监控报警程序及时通知程序猿。
  • 对于可能会恢复的问题(和网络相关的场景), 可以尝试进行重试。
    在我们当前的代码中采取的是经过简化的第二种方式. 我们记录的错误日志是出现异常的方法调用信息, 能很快速的让我们找到出现异常的位置。

3.3关于 “调用栈”

方法之间是存在相互调用关系的, 这种调用关系我们可以用 调用栈"来描述. 在 JVM 中有一块内存空间称为 "虚拟机栈" 专门存储方法之间的调用关系. 当代码中出现异常的时候, 我们就可以使用 e.printStackTrace(); 的方式查看出现异常代码的调用栈。

可以使用catch捕获多个异常:
try发生了异常之后,要在对应的catch里面捕获对应的异常。如果没有捕获这个异常,程序就会交给JVM处理,一旦交给JVM处理,程序就会终止。
例:

public static void main(String[] args) {
        int[] arr =  {1,2,3};
        try{
            arr = null;
            System.out.println(arr[9]);
        }catch (ArrayIndexOutOfBoundsException | NullPointerException e){
            System.out.println("捕获到数组越界异常/空指针异常");
        }
        System.out.println("执行后续程序");
    }

也可以用一个 catch 捕获所有异常由于 Exception 类是所有异常类的父类. 因此可以用这个类型表示捕捉所有异常。但是不建议这样写,这样的话捕获到的异常太大了。
在这种情况下,catch 进行类型匹配的时候, 不光会匹配相同类型的异常对象, 也会捕捉目标异常类型的子类对象。
catch在捕获异常的时候,从上往下,最好是子类->父类

3.4 finally 表示最后的善后工作, 例如释放资源

public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        try{
            int n = scanner.nextInt();
            System.out.println(10/n);
        }catch (InputMismatchException e){
            e.printStackTrace();
            System.out.println("输入有误");

        }catch (ArrayIndexOutOfBoundsException e){
            e.printStackTrace();
            System.out.println("算数异常,可能0作为了除数");
        }finally {
            //一般用作资源的关闭
            scanner.close();
            System.out.println("finally执行了");
        }
    }

无论是否存在异常, finally 中的代码一定都会执行到. 保证最终一定会执行到 Scannerclose 方法.

3.5使用 try 负责回收资源

上面的代码可以有一种等价写法, 将 Scanner 对象在 try( ) 中创建, 就能保证在 try 执行完毕后自动调用 Scannerclose 方法。

public static void main(String[] args) {
        try (Scanner scanner = new Scanner(System.in)) {
            int n = scanner.nextInt();
            System.out.println(10 / n);
        } catch (InputMismatchException e) {
            e.printStackTrace();
            System.out.println("输入有误");

        } catch (ArrayIndexOutOfBoundsException e) {
            e.printStackTrace();
            System.out.println("算数异常,可能0作为了除数");
        } finally {
            System.out.println("finally执行了");
        }
    }

如果本方法中没有合适的处理异常的方式, 就会沿着调用栈向上传递,如果向上一直传递都没有合适的方法处理异常, 最终就会交给 JVM 处理, 程序就会异常终止(和我们最开始未使用 try catch 时是一样的)。

异常的抛出也可以使用throw来手动抛出某个异常。
例:

 public static void func1(int x) throws RuntimeException{
        if (x == 10){
            throw new RuntimeException("x=" + x);//throw抛出自定义的异常
        }
    }

throw(抛出自定义的异常)和throws(声明这个异常)一般成对出现。使用 throws 关键字, 把可能抛出的异常显式的标注在方法定义的位置. 从而提醒调用者要注意捕获这些异常

尽量避免finally当中使用return(被编译器当做一个警告)。

 public static int func(){
        int a = 10;
        try{
            return a;
        }catch (ArithmeticException e){
            e.printStackTrace();

        }finally {
            return 20;//最后输出的结果为20
        }
    }
   public static void main(String[] args) {
        System.out.println(func());//20
    }

finally 执行的时机是在方法返回之前(try 或者 catch 中如果有 return 会在这个 return 之前执行 finally). 但是如果finally 中也存在 return 语句, 那么就会执行 finally 中的 return, 从而不会执行到 try 中原有的 return.

3.6异常处理流程

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

四、Java 异常体系

Java 内置了丰富的异常体系, 用来表示不同情况下的异常。
在这里插入图片描述

  • 顶层类 Throwable 派生出两个重要的子类, ErrorException
  • 其中 Error 指的是 Java 运行时内部错误和资源耗尽错误. 应用程序不抛出此类异常. 这种内部错误一旦出现,除了告知用户并使程序终止之外, 再无能为力. 这种情况很少出现.
  • Exception 是我们程序猿所使用的异常类的父类.其中 Exception 有一个子类称为 RuntimeException , 这里面又派生出很多我们常见的异常类
    NullPointerException , IndexOutOfBoundsException 等.
    Java语言规范将派生于 Error 类或 RuntimeException 类的所有异常称为 非受查异常, 所有的其他异常称为受查异常.
    如果一段代码可能抛出受查异常, 那么必须显式进行处理:
    a) 使用 try catch 包裹起来
    b) 在方法上加上异常说明, 相当于将处理动作交给上级调用者

五、自定义异常类

Java 中虽然已经内置了丰富的异常类, 但是我们实际场景中可能还有一些情况需要我们对异常类进行扩展, 创建符合我们实际情况的异常。
例:实现一个用户登录功能。

class NameException extends RuntimeException{
    public NameException(String message){
        super(message);
    }
}
class PasswordException extends RuntimeException{
    public PasswordException(String message){
        super(message);
    }
}
public class test02 {
    private static final String name = "zhang";
    private static final  String password = "123";

    public static void login(String name,String password)throws NameException,PasswordException{
        if (!test02.name.equals(name)){
//            System.out.println("用户名错误");
            throw  new NameException("用户名错误");
        }
        if (!test02.password.equals(password)){
//            System.out.println("密码错误");
            throw  new PasswordException("密码错误");
        }
    }

    public static void main(String[] args) {
        try{
            login("zhang","1236");
        }catch (NameException e){
            e.printStackTrace();
            System.out.println("用户名错误了");
        }catch (PasswordException e){
            e.printStackTrace();
            System.out.println("密码错误了");
        }
        finally {
            System.out.println("finally执行了!");
        }
    }
}
  • 自定义异常通常会继承自 Exception 或者 RuntimeException
  • 继承自 Exception 的异常默认是受查异常
  • 继承自 RuntimeException 的异常默认是非受查异常
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-11-26 08:43:52  更:2021-11-26 08:44:49 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 3:34:21-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码