Java学习24--异常

异常

软件运行过程中的各种意料之外叫做Exception,比如要读取的文件找不到,准备联网发现没网,等着int参数来了个String

注意Error和exception不一样,error错的比较猛,一般是直接把JAVA整个搞崩了,比如内存空间异常等等,JVM只好终止线程,这一般都是大错了。Exception一般是程序员脑子暂时抽风了,修修改改程序还能救回来。

举例,method a 和b互相无限调用对方,陷入无限循环。运行程序,观察系统输出什么。

package exception;public class Demo01 {public static void main(String[] args) {new Demo01().a();}public void a(){b();}public void b(){a();}
}

运行结果:

观察到系统输出了一句StackOverflowError这意思是stack内空间耗尽了,因为我们运行了一个没有终止条件的无限循环(记住做循环或者递归,一定要有可触发的程序终止条件)。


Exception in thread "main" java.lang.StackOverflowErrorat exception.Demo01.a(Demo01.java:8)at exception.Demo01.b(Demo01.java:11)at exception.Demo01.a(Demo01.java:8)at exception.Demo01.b(Demo01.java:11)N行循环

再举一个例子,除法分母是0,这在数学计算上本身就是不允许的。观察程序运行结果。


package exception;public class Demo01 {public static void main(String[] args) {System.out.println(6 / 0);}
}

运行结果:
观察到程序出了关键字“ArithmeticException: / by zero”这句的意思就是,数学错误: 除以零。通过观察输出的字样,程序员可以快速找到程序出错的位置。

Exception in thread "main" java.lang.ArithmeticException: / by zeroat exception.Demo01.main(Demo01.java:5)Process finished with exit code 1

异常处理的思维

Java异常处理是Java编程语言中用于处理程序中可能出现的错误或异常情况的一种机制。它提供了一种结构化的方式来响应和处理运行时错误,使程序能够在遇到问题时相对优雅的输出有效提示,而不是程序直接崩溃。

JAVA把异常当object处理,定义一个java.lang.Throwable 作为所有异常class的超类class

JAVA API已经提前定义了许多异常class,分为两大类:错误Error和异常Exception

在这里插入图片描述

如上图,错误error class:JAVA直接崩了,表示JVM无法处理或恢复的严重问题

  • 比如stack满了,compile一般检查不到,一般与“无限递归忘记写终止条件”或者“设置了一堆超大局部变量”或者“写了一大堆method互相调用”把stack空间占满了
  • 虚拟机运行错误 Virtual MachineError 比如当JVM不再有继续执行操作所需的内存资源,会报错OutOfMemoryError。
  • JVM运行时报错,比如 定义错误NoClassDefFoundError,链接错误LinkageError

如上图,Exception class一般还能救,一般都是程序员自己的锅:
Exception下分为unchecked exceptions 和 checked exception。

非检查异常unchecked exceptions:在compile阶段不需要catch或声明。并且是RuntimeException(运行时异常类)或它的子类,详细列出如下

  • RuntimeException(运行时异常)
    • ArrayIndexOutOfBoundsException数组下标越界
    • NullPointerException空指针异常
    • ArithmeticException算术异常
    • MissingResourceException丢失资源
    • ClassNotFoundException找不到类
    • 等等

检查异常checked exception :这类异常必须在方法签名中使用throws关键字声明,或者在方法体内部使用try-catch块进行处理。这意味着编译器要求这些method要么有程序块处理这些异常(使用try-catch块),要么在方法签名中使用throws关键字声明它们(等着这个class的父类try-catch)。比如程序想开文件 文件找不到了。检查异常类一般是指Exception下的IOException类或其子类。

Exception class存在的意义----让系统跑程序时候别崩溃,抛出一下这有个XXException,JVM不崩溃。

异常处理机制:抛出异常+捕获异常
五个关键字
try catch finally throw throws(注意throw和throws完全不一样)

try-catch

try-catch一般是成对使用。try块用于包含可能会抛出异常的代码。当try块中的代码抛出异常时,控制流将立即转移到与之匹配的catch块。catch块用于捕获并处理特定类型的异常。你可以有多个catch块来处理不同类型的异常。

在非常个别情况下,也有try-finally模块一起用,一般是文件调用,网络连接,数据库连接的method结束时被释放的情况下。

比如下面的例子,
try块内int r= m/n;是可能会抛出异常的代码,当异常被捕捉到,立刻转到catch块,如果直接碰到throw语句,那么后续代码就不看了,因为因为throw语句会立即结束当前方法的执行并将异常传递给调用者。如果throw旁边还有代码(包括System.out.println这种语句),建议写在catch块内throw关键字前面。
try块内可以写多个可能会抛出异常的代码,但一次只会触发一个,触发了一个就直接走catch模块了。

catch模块可以存在多个,是按顺序catch的,不要把大的父类放在第一个catch,那样后面的catch模组都不触发了。

package exception.demo02;public class mytest {public static void main(String[] args) {int m = 10;int n = 0;try {int r= m/n;} catch (ArrayIndexOutOfBoundsException e) {System.out.println("发现ArrayIndexOutOfBounds报错");}catch (ArithmeticException e){System.out.println("发现Arithmetic报错");}catch (RuntimeException e){System.out.println("发现Runtime报错");}}
}

运行结果

发现Arithmetic报错

throw关键字

在Java中,throw是一个关键字,不是method。当你想在代码中抛出一个异常时,你使用throw关键字并跟随一个异常object。这个异常对象可以是Java标准库中的异常类的一个实例object,也可以是你自定义的异常类的一个实例object。
一旦异常被抛出,程序的正常执行流程将被中断,并且控制权将转移到最近的异常处理代码,通常是catch块。

简单而言 throw后面跟着一个object,是继承于系统(或者自定义)Throwable class的object(见上图分类),触发后立刻终止程序,跳到最近的(或父级们)能处理该异常的catch模块,直到被处理或程序中止。

比如这句throw e;用在catch模块里,直接throw了异常object e,那么运行后我们会直接获得系统默认输出的这类Exception提示信息。这个提示或许不够清晰明确,有时程序员会将throw e;换成类似这样写 throw new ArithmeticException("啊啊啊你为什么要除以零");,用来输出自己想要的Exception提示信息。

Exception in thread "main" java.lang.ArithmeticException: / by zeroat exception.demo02.mytest.main(mytest.java:8)

整体代码见下面的例子:

先用简单的throw e;

package exception.demo02;public class mytest {public static void main(String[] args) {int m = 10;int n = 0;try {int r= m/n;} catch (ArrayIndexOutOfBoundsException e) {System.out.println("发现ArrayIndexOutOfBounds报错"); throw e;}catch (ArithmeticException e){System.out.println("发现Arithmetic报错");throw e;}catch (RuntimeException e){System.out.println("发现Runtime报错");throw e;}}
}

运行结果

Exception in thread "main" java.lang.ArithmeticException: / by zeroat exception.demo02.mytest.main(mytest.java:8)
发现Arithmetic报错

再将throw后面换成新建object new Exception_class(“用户自定义提示信息”) ;


package exception.demo02;public class mytest {public static void main(String[] args) {int m = 10;int n = 0;try {int r= m/n;} catch (ArrayIndexOutOfBoundsException e) {System.out.println("发现ArrayIndexOutOfBounds报错"); throw new ArrayIndexOutOfBoundsException("数组下标啊大哥大姐");}catch (ArithmeticException e){System.out.println("发现Arithmetic报错");throw new ArithmeticException("你除数是零啊!牛逼");}catch (RuntimeException e){System.out.println("发现Runtime报错");throw new RuntimeException("我点炒蘑菇没让你从种蘑菇开始啊");}}
}

程序运行结果

发现Arithmetic报错
Exception in thread "main" java.lang.ArithmeticException: 你除数是零啊!牛逼at exception.demo02.mytest.main(mytest.java:10)Process finished with exit code 1

printStackTrace()

除了在catch模块里直接throw异常object e使用语句throw e;有时程序员也选择使用printStackTrace(); printStackTrace()是Java中的一个异常处理方法,用于在控制台或日志文件中打印异常的堆栈跟踪信息。通过调用printStackTrace()方法,可以将这些Exception信息打印到控制台中。

package exception.demo02;public class mytest {public static void main(String[] args) {int m = 10;int n = 0;try {my_div(m,n);}catch (ArrayIndexOutOfBoundsException e) {e.printStackTrace();}catch (ArithmeticException e){e.printStackTrace();}catch (RuntimeException e){e.printStackTrace();}}public static int my_div(int a, int b) throws ArithmeticException {return a/b;}
}

运行结果:

java.lang.ArithmeticException: / by zeroat exception.demo02.mytest.my_div(mytest.java:21)at exception.demo02.mytest.main(mytest.java:8)Process finished with exit code 0

throws

Java允许程序员在method的声明中使用throws关键字来声明可能会抛出的异常。throws的位置写在method名称那行的最后面+可能出现的Exception种类,可写多个exception种类,用逗号隔开),比如public void doSomething() throws IOException,RuntimeException,ArithmeticException

如果一个方法的声明中使用了throws关键字来声明可能会抛出的异常,那么调用这个方法的代码不一定需要使用try-catch块来捕获这个异常。有几种处理异常的方式:

  • 使用try-catch块:这是最常见的处理方式。调用者可以使用try-catch块来捕获并处理可能抛出的异常。
  • 使用finally块:finally块可以用于在try块之后执行一些清理代码,无论是否发生异常都会执行。但请注意,finally块不能用来处理异常,它仅仅是用来执行清理任务。

以下是伪处理方式:(实际没有真的处理异常,而是丢给了别人或者直接摆烂)

  • 继续向上抛出异常:如果调用者不想在当前方法中处理异常,它可以选择不捕获该异常,这样异常会继续向上抛出,直到被某个上层方法捕获或者最终由JVM处理(通常会导致程序终止)。
  • 声明方法也抛出异常:如果调用者是一个方法,并且它也不想处理异常,那么它可以在自己的方法签名中使用throws关键字来声明同样的异常。这样,异常会继续向上传递,直到最终有某个方法处理了它。
  • 忽略异常:在某些特殊情况下,调用者可能会选择忽略异常。这是一种非常不推荐的做法,因为它可能会隐藏问题,导致程序在后续执行中出现不可预测的行为。

下面这个例子中,my_div method声明了它可能会抛出ArithmeticException,RuntimeException,于是在main模块try-catch程序对这些exception统统进行了涵盖,完成了异常(们)的处理。

package exception.demo02;public class mytest {public static void main(String[] args) {int m = 10;int n = 0;try {my_div(m,n);}catch (ArrayIndexOutOfBoundsException e) {e.printStackTrace();}catch (ArithmeticException e){e.printStackTrace();}catch (RuntimeException e){e.printStackTrace();}}public static int my_div(int a, int b) throws ArithmeticException, RuntimeException{return a/b;}
}
java.lang.ArithmeticException: / by zeroat exception.demo02.mytest.my_div(mytest.java:21)at exception.demo02.mytest.main(mytest.java:8)Process finished with exit code 0

throws和throw关键字经常一起使用来处理异常,但它们也可以单独使用。可以只使用throws,表明方法不处理某些异常,让调用者去处理。也可以只使用throw,在方法内部遇到错误时直接抛出异常,并不在方法签名中声明任何异常。

下面这个例子,doSomething方法声明了它可能会抛出IOException,但方法内部没有使用throw关键字来实际抛出异常。调用这个方法的代码需要处理或继续传递这个异常。

public class Example {  public void doSomething() throws IOException {  // 这里可能会抛出IOException  FileInputStream fis = new FileInputStream("file.txt"); // ...  }  
}

如果声明了可能抛出的异常,但层层调用它时最终到了main都没人处理这个异常(没人用try-catch模块处理),编译器会报错。

public class mytest {  public static void main(String[] args) {  //下面这个try-catch模块要是不存在,直接调用mymethod(),绝对报错!try {  mymethod();  } catch (Exception e) {  e.printStackTrace();  }  }  public static void mymethod() throws Exception {  throw new Exception("An exception occurred");  }  }

特殊的情况是,如果method声明了可能抛出的异常,层层调用它时最终到了main没人用try-catch模块处理,都在一层一层throws向上抛,main也摆烂直接用了throws向上抛,这种编译器不会报错。而是会在编译器输出Exception的具体内容。

下面这个例子就相当于层层向上抛,最后main也抛,编译器是不会报错的。

public class mytest {  public static void main(String[] args) throws Exception {  mymethod();  }  public static void mymethod() throws Exception {  throw new Exception("An exception occurred");  }  }

知识补充

快速生成try catch finally结构块:

IDEA有一个功能可以快速生成try catch finally结构块,这个功能叫做Surround with,快捷键是ctrl+alt+t
由于它和ubuntu open terminal重复了,我们可以用下面的方法,将快捷键更改,改为alt+c,下次使用时,将待检验模块高亮,然后alt+c,在里面选择 try catch finally即可。

Tips: IntelliJ IDEA 中如何更改快捷键设置?

 - 打开 IntelliJ IDEA,在顶部菜单栏选择 "File",然后在下拉菜单中选择 "Settings"(对于 macOS 用户,选择 "IntelliJ IDEA" -> "Preferences")。- 在弹出的 "Settings" 对话框中,在左侧的导航栏选择 "Keymap"。-  在 "Keymap" 界面,你可以看到所有的快捷键设置。你可以通过搜索功能找到你想要更改的特定快捷键。在搜索框中输入你想要更改的功能名称,然后在下方的列表中找到它。- 找到你想要更改的快捷键后,右键点击它,然后在弹出的菜单中选择 "Remove" 来删除原有的快捷键。- 接着,右键点击你刚刚删除快捷键的功能,然后在弹出的菜单中选择 "Add Keyboard Shortcut"。- 在弹出的 "Enter Keyboard Shortcut" 对话框中,按下你想要设置的新快捷键,然后点击 "OK"。- 最后,点击 "Apply" 按钮应用更改,然后点击 "OK" 按钮关闭 "Settings" 对话框。

throw和throws关键字的用法:

助记
主动throw exception object inside method block using throw
主动throws (potential) exception class on method title using throws

举例,分母参数为零的情况下,将算式写完,用alt+c快捷键打开surround with选择try catch finally快速生成exception抛出模块

package exception;public class test2 {public static void main(String[] args) {int a = 5;int b = 0;int c = 7;try {System.out.println(a+c/b);} catch (Exception e) {//e.printStackTrace();//做法1:打印错误的stack信息//System.exit(0); //做法2:直接退出 里面的参数可以写0或者1throw new RuntimeException(e); //做法3:直接抛出错误} finally {}}
}

运行结果

Exception in thread "main" java.lang.RuntimeException: java.lang.ArithmeticException: / by zeroat exception.test2.main(test2.java:13)
Caused by: java.lang.ArithmeticException: / by zeroat exception.test2.main(test2.java:9)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/259644.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构通讲

目录 集合源码详解 一、常见数据结构讲解 1. 线性数据结构 1.1 数组 1.2 队列 1.3 链表 1.3.1 单向链表 1.3.2 双向链表 1.4 栈 2. 非线性数据结构 2.1 树 2.2 二叉树 2.2.1 概念介绍 2.2.2 遍历操作 2.2.3 删除节点 2.2.4 查找局限性 2.2.5 AVL( …

linux kernel 内存踩踏之KASAN_SW_TAGS(二)

一、背景 linux kernel 内存踩踏之KASAN(一)_kasan版本跟hasan版本区别-CSDN博客 上一篇简单介绍了标准版本的KASAN使用方法和实现,这里将介绍KASAN_SW_TAGS和KASAN_HW_TAGS 的使用和背后基本原理,下图是三种方式的对比&#x…

Ps:焦点堆栈

焦点堆栈 Focus Stacking是一种摄影和图像处理技术,通过合并多张在不同焦距拍摄的照片来创建一张具有更大景深的图像,特别适用于微距摄影、风景摄影和任何需要在整个场景中保持尖锐对焦的情况。 ◆ ◆ ◆ 拍摄注意事项 1、使用三脚架 为了确保图像之间…

【Node-RED】安全登陆时,账号密码设置

【Node-RED】安全登陆时,账号密码设置 前言实现步骤密码生成setting.js 文件修改 安全权限 前言 Node-RED 在初始下载完成时,登录是无账号密码的。基于安全性考虑,本期博文介绍在安全登陆时,如何进行账号密码设置。当然&#xff…

git相关内容

一.git安装 该操作相信不用介绍了,为什么用yum,大家也是非常清楚的。 如果是root账户:yum -y install git 如果是普通账户: sudo yum -y install git 二.git和gitee/github区别 Git(读音为/gɪt/)是一个…

CDP和Chrome

CDP和Chrome CDP和WebDriver Protocol WebDriver和 Chrome DevTools Protocol(CDP) 是用于自动化浏览器的两个主要协议,大多数的浏览器自动化工具都是基于上述其中之一来实现的。可以通过这两种形式来和浏览器交互,通过代码来控…

语义分割-基础知识

1.cls_iou计算: cls0_iou预测正确的像素个数/(预测为该类别的像素个数真实标签为该类别的像素个数-预测正确的像素个数) mean_iou各个类别的像素预测准确值相加/像素总个数2.转置卷积(Transposed Convolution) 转置卷积不是卷积的逆运算 转置卷积也是卷…

Java on VS Code 2024年1月更新|JDK 21支持!测试覆盖率功能最新体验!

作者:Nick Zhu - Senior Program Manager, Developer Division At Microsoft 排版:Alan Wang 大家好,欢迎来到 Visual Studio Code for Java 2024年的第一期更新!提前祝愿大家春节快乐!在本博客中,我们将有…

Vue+Vite项目初建(axios+Unocss+iconify)

一. 创建项目 npx --package vue/cli vue 项目成功启动后,进入http://localhost:3200,即可进入创建好的页面(假设启动端口为3200) 二. 测试网络通讯模块 假设有本地服务器地址localhost:8000提供接口服务,接口为localhost:8000/token&#…

使用 apt 源安装 ROCm 6.0.x 在Ubuntu 22.04.01

从源码编译 rocSolver 本人只操作过单个rocm版本的情景,20240218 ubuntu 22.04.01 1,卸载原先的rocm https://docs.amd.com/en/docs-5.1.3/deploy/linux/os-native/uninstall.html # Uninstall single-version ROCm packages sudo apt autoremove ro…

openresty (nginx)快速开始

文章目录 一、什么是openresty?二、openresty编译安装1. 编译安装命令1.1 编译完成后路径1.2 常用编译选项解释 2. nginx配置文件配置2.1 nginx.conf模板 3. nginx常见配置一个站点配置多个域名nginx配置中location匹配规则 三、OpenResty工作原理OpenResty工作原理…

蓝牙BLE学习-概述

1. 简介 1.1 蓝牙发展历程 蓝牙,直接来自于一位国王的名字--King Harald ‘Bluetooth Gromsson。这位国王因两件事留名于史,其一是在公园958年统一了丹麦和挪威,其二是在其死后,其牙齿呈现出暗蓝色的颜色,因而得名蓝牙…

【MATLAB GUI】 1. 普通按钮、静态文本和可编辑文本

看B站up主freexyn的freexyn编程实例视频教程系列36Matlab GUI的学习笔记 文章目录 初步认识普通按钮静态文本和可编辑文本设计一个简易计算机 初步认识普通按钮 任务要求:点击一次“100”按钮,按钮上的文字值就递增1;点击“close”按钮&…

RIP协议详解

​RIP是最早的动态路由协议,虽然已经过时并且很少使用,但是可以通过学习RIP并且和ospf等现在正在使用的路由协议对比,了解其工作原理和过时原因,具有很强的学习性。 一、RIP协议简介 RIP(Routing Information Protoc…

2024.2.18 C++QT 作业

思维导图 练习题 1>定义一个基类 Animal&#xff0c;其中有一个虛函数perform&#xff08;)&#xff0c;用于在子类中实现不同的表演行为。 #include <iostream>using namespace std;class Animal { public:virtual void perform() {cout << "这是一个动…

css2的三大特性

css的三大特性 一.层叠性概念 二.继承性行高的继承 三. 优先级概念a标签默认蓝色继承注意事项 一.层叠性 概念 二.继承性 行高的继承 可用倍数表示三. 优先级 概念 a标签默认蓝色 继承注意事项 例子

使用倒模耳机壳UV树脂胶液制作HIFI耳机隔音降噪耳机壳有哪些缺点?

虽然使用倒模耳机壳UV树脂胶液制作HIFI耳机隔音降噪耳机壳有很多优点&#xff0c;但也存在一些缺点和需要注意的事项&#xff1a; 技术要求高&#xff1a;制作过程需要一定的技术和经验&#xff0c;如模具制作、树脂混合和填充等。如果没有足够的经验和技巧&#xff0c;可能会…

DS:八大排序之归并排序、计数排序

创作不易&#xff0c;感谢三连支持&#xff01;&#xff01; 一、归并排序 1.1 思想 归并排序&#xff08;MERGE-SORT&#xff09;是建立在归并操作上的一种有效的排序算法,该算法是采用分治法&#xff08;Divide andConquer&#xff09;的一个非常典型的应用。将已有序的子…

Python学习(16)|列表_遍历_排序_max_min_sum

列表的遍历&#xff1a; a [10,20,30,40] for obj in a: #obj 是临时变量名称&#xff0c;随意起名print(obj) 执行结果&#xff1a; 复制列表所有的元素到新列表对象&#xff1a; list1 [30,40,50] list2 list1 #只是将list2也指向了列表对象。也就是说list…

Maven - Plugins报错的正确解决之道

背景&#xff1a; 正确解决之道&#xff1a; 在自己本地Maven的安装目录中找到自己的仓库地址目录&#xff1a;直接搜索自己报错的插件文件&#xff0c;把它们删除&#xff0c;如图&#xff1a; 接着回到IDEA点击Maven刷新按钮重新加载即可&#xff1a;已解决 反例&#xff1…