java语言对异常处理运行的初步探索(try-catch-finally)

news2024/12/23 16:57:50

​​​​​​异常处理机制

java中的异常处理机制使得即使程序出现异常,代码也能够继续执行下去而不是直接退出程序。下面我们先来简单的了解一下异常处理是怎么使用。

在引用异常处理之前,代码运行中存在异常会导致JVM直接中断该程序并输出异常信息,如下:

public class ExceptionTry {
    public static void main(String[] args) {
        int i = 0;
        System.out.println(9 / i);
        System.out.println("程序继续执行");
    }
}

而在使用异常处理机制之后,我们可以对异常进行简单的处理,应用场景有很多,假如淘宝商品的筛选中价格筛选区间实现是使用如下的代码(目前学习还不够深入,淘宝具体功能的实现可能不是这么简单,只是我是这么理解的):

Scanner scanner = new Scanner(System.in);
double a = scanner.nextDouble();

假如用户玩心大起,或者输入时有误触,输入字符串,这会产生InputMismatchException异常,也就是输入类型无法转换为double型,数据输入类型不匹配,从而导致程序直接中断退出,用户再次使用就只能重新启动,极度影响软件的使用体验。同时,在debug代码中也会带来许多不必要的麻烦。这个时候使用异常处理可以很好的优化使用体验,同时极大的提高了代码的健壮性。还是使用第一个例子:
 

public class ExceptionTry {
    public static void main(String[] args) {
        try {
            int i = 0;
            System.out.println(9 / i);
        } catch (Exception e) {
            System.out.println("代码出现异常:" + e.getMessage());
        }
        System.out.println("程序继续执行");
    }
}

这个时候代码是正常运行结束的:

异常和错误的区分

异常(Exception)和错误(Error)是两个完全不同的概念,在我的理解中前者是代码在偶然性或者编程错误等因素导致的一般性问题,可以使用针对性的代码来进行处理的,比如空指针使用异常,算数错误异常(除零,开负数根等等),类型转换错误,数组越界等等;而错误则是更加严重的JVM系统内部错误或者资源耗尽导致程序完全不能执行,比如栈溢出,内存不足等等。通俗来讲就是前者是肚子疼,后者是癌症。

异常中又可以细分为运行时异常和编译时异常,前者是编译器无法检查出的逻辑错误,如上面那个例子中的by zero的除零错误就是运行时异常,而后者是编译器要求必须处理的异常,不然编译过不了,比如在开文件流的时候使用空文件出现的FileNotFundException。
 

try-catch-finally的使用

try-catch-finally语法了解

了解了异常处理机制的作用接下来我们可以来先看看这个语句是怎么使用的

整体上是很好理解的,try后面的代码是我们认为的可能出现异常的代码,在这个代码块中如果出现异常,JVM就会把出现的异常捕获到catch模块中,然后我们可以在其中进行针对性的操作,比如还是第一个例子,我们可以在catch中输出报错然后要求进行重新输入:
 

public class ExceptionTry {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int i = 0;
        try {
            System.out.println(9 / i);
        } catch (Exception e) {
            System.out.println("代码出现异常:" + e.getMessage());
            System.out.println("请重新输入i");
            i = scanner.nextInt();
        }
        System.out.println("程序继续执行");
    }
}

我们还可以在外层套循环来保证输入的数据不会出现异常,出现异常则会一直在循环中重复进行输入,甚至之后我们可以自定义异常来使得输入的数据符合我们的要求(异常除了系统自己规定的类以外还可以自定义,毕竟异常本质上也还是一种类)。

在出现异常的情况下,代码是按照try-catch-finally的执行顺序来的,finally可以省略,finally是语句必须执行的内容,一般是在执行一段代码中不管是否发生异常都必须执行其中的业务逻辑的应用场景中,比如不管是否发生异常都需要关闭一些文件流,关闭一些资源等等。catch其实也可以省略,不过这样的话程序异常会和之前一样由JVM来处理:中断程序,输出异常信息。
 

try-catch-finally的具体使用实例
import java.util.Scanner;
 
public class Try {
    public static void main(String[] args) {
        while(true) {
            try {
                Scanner scanner = new Scanner(System.in);
                System.out.println("请输入一个整数");
                int a = scanner.nextInt();
                System.out.println("a的值为:" + a);
                break;
            } catch (Exception e) {
                System.out.println("输入错误,请重新输入");
            }
        }
    }
}

以上就实现了数据输入时限定只能得到整数,输入异常时还不会退出程序的数据输入。我们还可以在其中添加我们想要具体限定的条件,比如大小,位长等等。

多说一句,如果尝试在循环外部创建Scanner对象,然后内部依旧使用nextInt方法,并在调试时第一次输入异常的话,那么之后就不会再有输入的机会了,会陷入一个死循环,无法实现我们想要的功能。有兴趣的朋友可以看一下。
 

我们在出现异常的时候是直接跳出代码的执行的,通过断点追踪进去Scanner具体的原码后发现,本来退出被调用方法时为了不影响下一次操作需要对一些参数进行重置的操作,现在因为异常直接跳出导致重置操作无法进行,这样就会对下一次数据的读取造成影响。关于上面那个问题,我发现的是Scanner里面的skipped属性(用来判断分隔符是否被跳过了,应该就是字段是否已经被读取完毕)没有被改回false,所以导致之后的循环中scanner对象的每一次使用skipped属性都无法被修改。(因为skipped每次都是true,就代表字段已经被读取完毕了;被读取的字段token是空,无法进行重置参数的操作;needInput初始就是false,而且只有第一次正常的读取中readInput后也被修改为false,不需要更多的输入,跳过了输入阶段;所以又抛出异常throwFor()退出方法的调用到nextInt(),但是退出时又没有修改skipped属性,所以下一次还是true,就这样进入了一个死循环)具体有问题的源码内容如下:

我们可以通过在循环体内创建对象,这样scanner会在每次调用的时候重新创建从而来进行更新;或者我们可以通过使用Integer.paseInt(scanner.next())来改变数据类型,这样就不会让scanner的属性没有重新初始化遭受异常强制中断了,因为这个时候异常时发生在外部的paseInt中的。

当然严谨来说我其实应该还要具体进去看看getCompleteTokenInBuffer方法的,并且我的解释在自己看来都不是很好,但是这对于我这个小垃圾来说源码看着属实是有点头晕了,看着getCompleteTokenInBuffer的注释大概应该可能是这么回事吧,但是又想具体搞清楚,属于是又菜又爱玩了。之后要是实力有所精进会更加具体详实的搞清楚这个问题。诚心欢迎各位大佬朋友、兄弟姐妹指正我说法里面的错误和不足,拜谢!
 

异常处理的整体机制

知道try-catch-finally的用法之后我们可以来看看异常处理的整体的处理机制了。我们知道,在使用try-catch-finally之前,异常都是由我们的JVM系统来处理的,JVM在异常处理中有着我们Object类一样的顶级地位,Object是所有类的最终父类,JVM也是所有类的异常处理的最终处理单位。具体是像下图中的结构:

我们的main调用了f1方法,f1方法又调用了f2方法。这里用到了我们的throws了,throws就像是摆烂摸鱼,如果f2中没有显式地处理这个异常,那么f2就会把这个异常抛给调用他的f1,这个异常我不想管,不管了。所以在没有使用try处理前,异常会被一层一层的被抛给最高级的JVM系统,并最终由他来处理这个异常。同时我们可以修改异常类型来选择性的抛弃指定的异常。(将Exception修改为具体的异常类型)
 

try-catch-finally的使用细节

public class Try {
   public static void main(String[] args) {
       System.out.println(a.method());
   }
}
class a{
   public static int method() {
       int i = 0;
       try {
           return 9 / i;
       } catch (Exception e) {
           System.out.println("catch");
           return ++i;
       } finally {
           System.out.println("finally");
           return ++i;
       }
   }
}

关于这一段代码的执行顺序,我们只需要明确一个概念就可以迎刃而解了——finally中的代码是必须执行的业务逻辑。在这个语句中try中发生了异常被捕获到了catch中,执行完之后到return ++i;当然是先执行完  ++i 之后发现finally没有被执行,所以就在return之前先去执行finally 的语句,并最终在finally中return。所以最后的结果是2;
 

如果将catch中的 ++i 换成 i - 8,我们的过程其实没有变化,只不过 i - 8 和 ++i有很大的区别,后者是可以作为一个独立的语句来执行的,而前者没有接收者,所以return i - 8;这里其实在底层先用一个临时变量temp储存了 i - 8 的值,然后再去执行finally的代码。如果finally中的代码没有出口return,就算finally中修改了 i ,最终还是会返回temp的值;如果有,那么会在finally中直接return。

public class Try {
    public static void main(String[] args) {
        System.out.println(a.method());
    }
}
class a{
    public static int method() {
        int i = 0;
        try {
            return 9 / i;
        } catch (Exception e) {
            System.out.println("catch");
            return i - 8;
        } finally {
            System.out.println("finally");
            i++;
//            return ++i; //返回2
 
        }
    }
}

结果如下:

catch
finally
-8

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

stack的使用以及模拟实现

🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨ 🐻强烈推荐优质专栏: 🍔🍟🌯C的世界(持续更新中) 🐻推荐专栏1: 🍔🍟🌯C语言初阶 🐻推荐专栏2: 🍔…

活动预告|Dragonfly 与你相约 2023 KubeCon Shanghai!

KubeCon CloudNativeCon Open Source Summit China 2023,由 Linux 基金会、CNCF 主办,将在 9 月 26-28 日于上海跨国采购会展中心盛大开幕。本次峰会将聚集全球社区,共同探讨云原生和开源领域的前沿洞察、核心技术与最佳实践,会…

Java基于SpringBoot的藏区特产销售系统的研究与实现

今天为大家带来的是基于 Java SpringBootVue 的藏区特产销售系统,大家有兴趣的可以看一下 博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W,Csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 文章目…

ruoyi(若依)接口拦截路径配置,接口访问要授权,放开授权直接访问

1.找到文件SecurityConfig.java文件,里面配置相应的放行路径

[计算机入门] Windows附件程序介绍(办公类)

3.13 Windows附件程序介绍(办公类) 3.13.1 写字板 Windows系统中的写字板程序是一款简单而实用的文本编辑工具,它被广泛应用于快速记录笔记、绘制草图和进行简单的文档编辑。以下是写字板程序的主要功能和作用: 文本输入和编辑:写字板程序允…

数据结构-----二叉树的创建和遍历

目录 前言 二叉树的链式存储结构 二叉树的遍历 1.前序遍历 2.中序遍历 3.后序遍历 二叉树的创建 创建一个新节点的函数接口 1.创建二叉树返回根节点 2.已有根节点,创建二叉树 3.已有数据,创建二叉树 前言 在此之前我们学习了二叉树的定义和储…

HTML5+CSS3小实例:脉冲波纹催眠动画特效

实例:脉冲波纹催眠动画特效 技术栈:HTML+CSS 效果: 源码: 【html】 <!DOCTYPE html> <html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"><meta name="viewport" content=&qu…

ThingsBoard 前端项目背景图片部件开发

前言 ThingsBoard 是目前 Github 上最流行的开源物联网平台&#xff08;14.4k Star&#xff09;&#xff0c;可以实现物联网项目的快速开发、管理和扩展, 是中小微企业物联网平台的不二之选。 本文介绍如何在 ThingsBoard 前端项目中开发背景图片部件。 产品需求 最近接到产…

掌握可扩展和可维护应用程序:12-Factor应用程序开发的全面指南

1*vhxOhTuKSyuuAKu-nUQ5SA.jpeg 在今天的快节奏世界中&#xff0c;软件开发人员需要创建可扩展、可维护和适应性强的应用程序。12-Factor应用程序方法论是一组最佳实践&#xff0c;可以帮助开发人员实现这些目标。 本文深入探讨了12个因素&#xff0c;详细解释了它们的重要性以…

python 深度学习 解决遇到的报错问题5

目录 一、conda安装shapefile失败 二、conda安装osmnx失败&#xff1a;To search for alternate channels that may provide the conda package yourelooking for, navigate to 三、ERROR: Could not build wheels for llvmlite, which is required to install pyproject.to…

算法基础--位运算

一、常见位运算总结&#xff1a; 1、基础位运算&#xff08;^&#xff09; 其中异或^有2种理解。 2、位图bitset相关&#xff08;&|&#xff09; test判断第x位是1函数0: 可以让n右移&#xff0c;也可以让1左移&#xff0c;习惯上选择第一种 (n>>x)&1 判…

初创企业应该选一款怎样的客服系统?

互联网经济时代的飞速发展&#xff0c;促使客户市场对于企业服务的要求越来越高。客户在选择产品的时候已经不单单却决于产品功能和价格&#xff0c;客户服务也是其关注的重点。 优质的客户服务所带来的是客户满意度的提升&#xff0c;以及品牌影响力的提高。所以&#xff0c;…

Linux 服务器下 pypy 下载数据集

Linux 服务器下 pypy 下载数据集 安装 pip install bypy链接自己的百度网盘 命令行直接输入 byby info 就行 byby info查看网盘里面的内容 bypy listbyby list 只显示自动生成的bypy中的文件&#xff0c;上传也是在这个目录中&#xff0c;可以自己在里面新建文件夹 4. 上传…

tsar-性能监控工具

简介 tsar是淘宝自己开发的一个采集工具&#xff0c;主要用来收集服务器的系统信息&#xff08;如cpu&#xff0c;io&#xff0c;mem&#xff0c;tcp等&#xff09;&#xff0c;以及应用数据&#xff08;如squid haproxy nginx等&#xff09;。收集到的数据存储在磁盘上&#…

SMOKE-CMAQ实践技术应用

大气污染物排放是空气污染的源头&#xff0c;气象因素是影响污染程度的重要因素&#xff0c;因此空气质量模式要求气象资料和污染物排放清单作为输入&#xff0c;其中由于大气污染源复杂性、数据滞后性、动态变化、规律性不明显等特点&#xff0c;使得大气污染源排放清单输入准…

【牛客网】OR63 删除公共字符串

思路 创建哈希表,将第二个字符串中出现过的字符添加到哈希表中创建StringBuffer来拼接最后的结果字符串遍历字符串一,如果字符在哈希表中出现过,就不拼接到字符串中,反之则拼接 Java代码 import java.util.*;// 注意类名必须为 Main, 不要有任何 package xxx 信息 public cl…

ISIS的高级特性

1、IS-IS邻接关系建立原则 L1的路由器只能和L1的路由器建立邻接关系&#xff0c;也可以和L1、2的路由建立邻接关系 L2的路由器只能和L2的路由器建立邻接关系&#xff0c;也可以和L1、2的路由建立邻接关系 DIS只有在广播型网络中才会选举 LSP相当于OSPF中的LSA IS-IS链路状态报文…

JUC第十讲:CAS,Unsafe和原子类详解

JUC第十讲&#xff1a;CAS,Unsafe和原子类详解 JUC中多数类是通过volatile和CAS来实现的&#xff0c;CAS本质上提供的是一种无锁方案&#xff0c;而Synchronized和Lock是互斥锁方案; java原子类本质上使用的是CAS&#xff0c;而CAS底层是通过Unsafe类实现的。本文是JUC第十讲&a…

广东海颐开发笔试编程题回顾

题目一 1、现以序列{22, 24, 30, 14, 10, 17, 15, 20, 16, 23}的顺序进行输入&#xff0c;请画出构造出的平衡二叉树?请写出实现二叉树左旋的代码?&#xff08;具体题目忘记了&#xff0c;就随机搞个排序&#xff0c;思路和方法都是一样的&#xff09; 图 顺序 {22, 14, 10…

【C++】多态,从使用到底层。

文章目录 前言一、多态的概念二、多太的定义和实现2.1 多太的构造条件2.2 虚函数2.3 重写(覆盖)2.4 C11 override 和 final2.5 重载&#xff0c;隐藏&#xff0c;重写 三、多态的原理3. 1虚函数表3.2 虚函数表如何完成多态的功能3.3 虚函数表存储在内存空间的那个区域&#xff…