七千字带你了解异常处理下

简介: 七千字带你了解异常处理下

一、异常的处理

在Java中,异常处理主要的5个关键字:throw、try、catch、final、throws。

3.1 异常的捕获

使用 try 和 catch 关键字可以捕获异常。try/catch 代码块放在异常可能发生的地方。Catch 语句包含要捕获异常类型的声明,使用 try/catch 的语法如下:

try
{
   // 程序代码
}catch(ExceptionName e1)
{
   //Catch 块
}

具体实例:

public static void main(String[] args) {
        try{
            int[] arr = {1,2,3};
            arr[3] = 1;
        }catch(ArrayIndexOutOfBoundsException e) {
            e.printStackTrace();//打印异常信息
            System.out.println("数组越界异常!");
        }
        System.out.println("out");
    }

在这里插入图片描述
我们可以发现系统处理完异常后,程序正常进行到结束.

  1. try块内抛出异常位置之后的代码将不会被执行
  2. 如果抛出异常类型与catch时异常类型不匹配,即异常不会被成功捕获,也就不会被处理,继续往外抛,直到JVM收到后中断程序----异常是按照类型来捕获的

多重捕获块:

 public static void main(String[] args) {
        try{
            int arr[] = {0,1,2};
            arr[3] = 0;
            System.out.println(2/arr[0]);
        }catch(ArrayIndexOutOfBoundsException e) {
            e.printStackTrace();//打印异常信息
            System.out.println("数组越界异常!");
        }catch(ArithmeticException e) {
            e.printStackTrace();//打印异常信息
            System.out.println("算术异常!");
        }
        System.out.println("out");
    }

在这里插入图片描述

try中可能会抛出多个不同的异常对象,则必须用多个catch来捕获----即多种异常,多次捕获

捕获多个异常:

try{

}catch(ArrayIndexOutOfBoundsException | NullPointerException e) {

}

如果异常之间具有父子关系,一定是子类异常在前catch,父类异常在后catch,否则编译报错.

public static void main(String[] args) {
        try{
            
        }catch(Exception e) {
            
        }catch(ArrayIndexOutOfBoundsException e) {
            
        }
    }

在这里插入图片描述
也可以一个catch捕获,不建议,代码可阅读性差:

public static void main(String[] args) {
        try{

        }catch(Exception e) {

        }
    }

在这里插入图片描述
阅读时不知道这里的异常到底是什么异常.

3.2 异常的抛出

在编写程序时,如果程序中出现错误,此时就需要将错误的信息告知给调用者,比如:参数检测。在Java中,可以借助throw关键字,抛出一个指定的异常对象,将错误信息告知给调用者。具体语法如下:
throw关键字:

public static int fun(int[] arr,int index) {
        if(index < 0 || index >= arr.length) {
            throw new ArrayIndexOutOfBoundsException("数组越界!");
        }
        if(null == arr) {
            throw new NullPointerException("数组为空!");
        }
        return arr[index];
    }
    public static void main(String[] args) {
        int[] arr = {0,1,2};
        System.out.println(fun(arr, 3));
    }

在这里插入图片描述
我们可以自己指定异常信息.

  1. throw必须写在方法体内部
  2. 抛出的对象必须是Exception 或者 Exception 的子类对象
  3. 如果抛出的是 RunTimeException 或者 RunTimeException 的子类,则可以不用处理,直接交给JVM来处理
  4. 如果抛出的是编译时异常,用户必须处理,否则无法通过编译
  5. 异常一旦抛出,其后的代码就不会执行

throws关键字:
下面方法的声明抛出一个 RemoteException 异常:

 public void deposit(double amount) throws RemoteException
  {
    throw new RemoteException();
  }

一个方法可以声明抛出多个异常,多个异常之间用逗号隔开。例如,下面的方法声明抛出 RemoteException 和 InsufficientFundsException:

 public void withdraw(double amount) throws RemoteException,
                              InsufficientFundsException
   {

   }
  1. throws必须跟在方法的参数列表之后
  2. 声明的异常必须是 Exception 或者 Exception 的子类
  3. 方法内部如果抛出了多个异常,throws之后必须跟多个异常类型,之间用逗号隔开,如果抛出多个异常类型

具有父子关系,直接声明父类即可。

  1. 调用声明抛出异常的方法时,调用者必须对该异常进行处理,或者继续使用throws抛出

3.3 finally的使用

在写程序时,有些特定的代码,不论程序是否发生异常,都需要执行,比如程序中打开的资源:网络连接、数据库连接、IO流等,在程序正常或者异常退出时,必须要对资源进进行回收。另外,因为异常会引发程序的跳转,可能导致有些语句执行不到,finally就是用来解决这个问题的。

 public static void main(String[] args) {
        try{
            int[] arr = {1,2,3};
            arr[3] = 1;
        }catch(ArrayIndexOutOfBoundsException e) {
            e.printStackTrace();
        }finally {
            System.out.println("finally已执行!");
        }
    }

在这里插入图片描述
相信大家有一个疑问,try-catch后面的代码会执行,为什么还要使用finally?

public static int get() {
        Scanner scanner = null;
        int n = 0;
        try{
            scanner = new Scanner(System.in);
            n = scanner.nextInt();
            return n;
        }catch(InputMismatchException e) {
            e.printStackTrace();
        }finally {
            System.out.println("finally!");
        }
        System.out.println("try-catch执行完毕!");
        if(null != scanner) {
            scanner.close();
        }
        return n;
    }
    public static void main(String[] args) {
        int n = get();
    }

在这里插入图片描述
当我们输入的值为整型类型时,就会出现类型泄露.
在这里插入图片描述
这里执行到第二步程序就终止了,没有对scanner进行释放,只有在finally中加上才能实现程序的安全性.
finally的危险性:

public static int func1() {
        try{
            return 1;
        }finally {
            return 2;
        }
    }
    public static void main(String[] args) {
        System.out.println(func1());
    }

这里输出的是1还是2?

在这里插入图片描述
在这里插入图片描述

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

3.4 JVM处理异常

如果我们一直将异常向上抛,抛给主方法还没有处理,系统将会抛给JVM处理,异常终止程序.try中的异常如果没有catch捕捉处理也是一样的.

public static void func2() {
        int[] arr = {1,2,3};
        arr[3] = 1;
    }
    public static void main(String[] args) {
        func2();
        System.out.println("main未处理异常!");
    }

在这里插入图片描述

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

二、自定义异常类

在 Java 中你可以自定义异常。编写自己的异常类时需要记住下面的几点:

1.所有异常都必须是 Throwable 的子类。
2.如果希望写一个检查性异常类,则需要继承 Exception 类。
3.如果你想写一个运行时异常类,那么需要继承 RuntimeException 类。

可以像下面这样定义自己的异常类:

class MyException extends Exception{
}

实现一个登录功能,自定义异常类

public class NameException extends Exception{
    public NameException(String message) {
        super(message);
    }
}
public class PassException extends Exception{
    public PassException(String message) {
        super(message);
    }
}
1.自定义异常通常会继承自 Exception 或者 RuntimeException
2.继承自 Exception 的异常默认是受查异常
3.继承自 RuntimeException 的异常默认是非受查异常.
private String Name = "zd";
    private String Word = "000000";
    public static void login(String Name,String Word)throws NameException,WordException {
        if(!Name.equals(Name)) {
            throw new UserNameException("用户名错误!");
        }
        if(!Word.equals(Word)) {
            throw new PassWordException("密码错误!");
        }
        System.out.println("登录成功!");
    }
    public static void main(String[] args) {
        try {
            login("zd","000000");
        }catch (NameException e) {
            e.printStackTrace();
        }catch (WordException e) {
            e.printStackTrace();
        }
    }
目录
相关文章
|
机器学习/深度学习 人工智能 分布式计算
跨越时代的数据力量:大规模数据处理的技术突破
在信息爆炸的时代,大规模数据处理成为了推动科技进步的重要驱动力。本文将探讨大规模数据处理所涉及的技术突破,包括分布式计算、机器学习和人工智能等,以及其在各个领域的应用,展现数据的无限潜力。
|
安全 Java 开发者
Java并发编程的艺术:解锁多线程同步的奥秘
本文将深入探讨Java并发编程的核心概念,揭示多线程环境下同步机制的工作原理与实践技巧。我们将从基础的synchronized关键字讲起,逐步过渡到高级的Lock接口和并发工具类,最后通过实例分析来加深理解。文章不仅旨在为初学者提供一个清晰的并发编程入门指南,同时也希望能够帮助有一定经验的开发者巩固和提升他们的并发处理能力。
|
SQL 关系型数据库 MySQL
Mysql统计技巧:ON DUPLICATE KEY UPDATE用法
Mysql统计技巧:ON DUPLICATE KEY UPDATE用法
755 0
|
索引 Python
Python入门教程:掌握for循环、while循环、字符串操作、文件读写与异常处理等基础知识(上)
Python入门教程:掌握for循环、while循环、字符串操作、文件读写与异常处理等基础知识
317 0
|
存储 安全 前端开发
java学习之高级语法(十四)----- 异常
java学习之高级语法(十四)----- 异常
java学习之高级语法(十四)----- 异常
|
缓存 JavaScript Java
服务网格GRPC协议多种编程语言实践-5.GRPC协议Headers网格实践
在服务网格的流量管理和可观测性实现上,Headers发挥着非常关键的作用。相比而言,HTTP协议的Headers实现较为容易,因为HTTP是同步阻塞式的请求响应模式,可以很容易在GET/POST/UPDATE/DELETE方法中定义和使用读写Header的API。GRPC协议的Headers则要复杂一些,各种编程语言在4种不同通信模型中,读写Header的形式的差异化很大,同时还要考虑流式和异步的编程实现。 本篇首先介绍4种编程语言的Headers编程实践,然后讲述在服务网格实践中,GRPC协议Headers的两个重要实践:流量管理和可观测性。
3681 0
服务网格GRPC协议多种编程语言实践-5.GRPC协议Headers网格实践
|
关系型数据库 MySQL
MySQL · 引擎特性 · IO_CACHE 源码解析
概述 在数据库中 IO 的重要性不言而喻,为了更好的管理 IO 操作,大多数数据库都自己管理页数据和刷脏机制(例如 InnoDB 中的 Buffer pool),而不是交给文件系统甚至是操作系统调度。但是对于顺序写入的日志数据,使用文件系统接口方便的多,文件系统 也是以页的形式管理,呈现给应用层的是一片连续可写的空间,管理的单位称为 Sector 大小是 4KB,所以对于 4KB 对齐的地址读写可以避免跨多个 Sector,对文件系统的性能有很大的提高。
2081 0
|
C++ Windows
QT Creator 快捷键
来源:http://blog.csdn.net/desert187/article/details/23996821 一、快捷键配置方法: 进入“工具-&gt;选项-&gt;环境-&gt;键盘”即可配置快捷键。 二、常用默认快捷键: 编号 快捷键 功能 1 Esc 切换到代码编辑状态 2 F1 查看帮助(选中某
1734 0
|
1天前
|
数据采集 人工智能 安全