java什么时候用异常_深入理解Java异常的使用场景

2023-11-09

最近在项目代码中,遇见异常滥用的情形,分析下会带来哪些后果。

1. 代码可读性变差,业务逻辑难以理解

异常流与业务状态流混在一起,无法从接口协议层面理解业务代码,只能深入到方法(Method)内部才能准确理解返回值的行为

可看一下代码:

public UserProfile findByID(longuser_id) {

Map cond = new HashMap();

cond.put("id", user_id);

UserProfile userInfo= null;try{

userInfo= DBUtil.selecta(UserProfile.class, "user_info", cond);

}catch(Throwable e) {

log.error(e,"UserProfile findByID");

}returnuserInfo;

}

DAO层负责数据库的基本操作,该方法返回值为查询结果用户对象数据。代码强行抓了所有的异常,并以null返回,后来人无法确认null是代表该用户不存在还是出现异常。

2. 代码健壮性变差,异常信息被随意捕捉,甚至被吃掉

同样上述代码,首先抓了Throwable这个所有异常,包括Error(后文会介绍异常体系)。代码内部隐藏了问题,只是打印了一行日志,并且让程序可以正常继续往后走,带来的不确定性和风险都很大,这也极大的影响代码的健壮。

3. 破坏架构的分层清晰,职责单一的原则,为系统扩展带来很大阻碍

随着系统的发展,往往会沉淀出一些平台系统,比如调用监控。会负责统一采集系统的各类信息,因为这样的错误异常处理,将很难统一分离出异常信息。

那我们在实际编写代码的如何正确考虑异常的使用呢?

首先了解下Java异常的设计初衷。

Exceptions are the customary way in Java to indicate to a calling method that an abnormal condition has occurred. 一个很重要的概念——不正常情形。Java异常旨在处理方法调用时不正常情形,但我们该如何理解“不正常情形”?

看下图,JDK给我们定义了以下异常体系:

f7da1533321f254be7578a5d63219244.png

根节点是Throwable,代表Java内所有可以Catch的异常都继承此,向下有两类,Exception和Error,日常用到较多的都是Exception,Error一般留给JDK内部自己使用,比如内存溢出OutOfMemoryError,这类严重的问题,应用进程什么都做不了,只能终止。用户抓住此类Error,一般无法处理,尽快终止往往是最安全的方式,既然什么都干不了就没必要抓住了。Exception是应用代码要重点关心的,其下又分为运行时异常RuntimeException和编译时异常,各自区分就不在详述了。

了解异常的结构后,接下来解决两个重要问题,何时抛异常和抛什么异常,何时抓异常和抓什么异常 何时会有异常抛出,总结起来有以下三个典型的场景:

调用方(Client)破坏了协议

说白了就是调用方法时没有按照约定好的规范来传参数,典型的比如参数是个非空集合却传入了空值。这种破坏协议的还可以细分两类,一类是调用方从接口形式上不易觉察的规则但需要在出现时给调用方些强提示,带些信息上去,这时异常就是特别好的方式;另一类是调用方可以明确看到的规则,正常情况会正常处理协议,不会产生破坏,但可能因为bug导致破坏协议。

public voidmethod(String[] args) {int temperature = 0;if (args.length > 0) {try{

temperature= Integer.parseInt(args[0]);

}catch(NumberFormatException e) {throw newIllegalArgumentException("Must enter integer as first argument, args[0]="+args[0],e);

}

}//其他代码

}

要求传入整数,但转换数字时出错,此时可抛出特定异常并附上提示信息

(Method)知道有问题,但自己处理不了

这里"有问题",可能是调用方破坏了协议,但是单独提出来是要从被调用方出发考虑,比如Method内部有读取文件操作,但发现文件并不存在

1 public static voidmain(String[] args) {2 if (args.length == 0) {3 System.out.println("Must give filename as first arg.");4 return;5 }6 FileInputStream in = null;7 try{8 in = new FileInputStream(args[0]);9 }10 catch(FileNotFoundException e) {11 System.out.println("Can't find file: " + args[0]);12 return;13 }14 //其他代码

15 }

FileInputStream在创建时抛出了FileNotFoundException,显然出现该问题时FileInputStream是处理不了的。

预料不到的情形

空指针异常、数组越界是这种典型的场景,一般是由于有代码分支被忽略

了解了何时会出现异常,但是需要抛出异常时是选择编译时异常还是运行时异常呢? 很多人可能会说,很简单啊,需要调用方catch的就编译时,否则运行时。问题来了,什么时候需要调用方catch?

分析编译时和运行时对代码编写的影响,可以总结出来区分时考虑的点有:调用方能否处理、严重程度、出现的可能性。

调用方能处理->编译时

调用方不能处理->运行时

严重程度高->运行时

出现可能性低->运行时

本人细化了这个分类的考虑过程如下:

9e46015f189e042f00bb4a0f30cc4796.png

首先从调用方开始考虑,如果是调用方破坏了协议,则抛出运行时异常,这类异常一般出现可能性较低,调用方已知,所以没必要强制调用方抓此异常。

然后如果问题出现被调用方,无法正常执行完成工作,这时候考虑该问题调用方是否可以处理,如果能处理,比如文件找不到、网络超时,则抛出编译时异常,否则比如磁盘满,抛运行时异常

解决了何时抛异常和抛什么异常,接下来是调用这些有异常的代码时,何时catch和catch什么异常呢? 攻守不分离... 免不了俗,总结一下几点供大家探讨:

不要轻易抓Throwable,图省事可能会带来巨大的隐患

1 try{2 someMethod();3 } catch(Throwable e) {4 log.error("method has failed", e);5 }

应该尽量只去抓关注的异常,明确catch的都是什么具体的异常

自己处理不了,不要抓

比如上文DB可能会有异常,在DAO层是处理不了这种问题的,交由上层处理。抓异常宜晚不宜早,抛异常宜早不宜迟。

切忌抓了,又把异常吞掉,不留下一丝痕迹

抓住异常,打行日志完事儿,不是一个好习惯。

切忌抓异常了将异常状态流和业务状态流混在一起,这样你算是彻底抛弃了Java的异常机制

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java什么时候用异常_深入理解Java异常的使用场景 的相关文章

  • GPIO口的脚本配置之——全志H3script.bin

    此脚本的作用之一是配置GPIO的默认状态 如 功能 内部电阻状态 驱动能力等 1 但是直接打开script bin 文件则会出现乱码 那么我们怎么才可以打开并更改该脚本的配置呢 在路径uboot kernel orangepi sdk to
  • PyTorch分布式训练进阶:这些细节你都注意到了吗?

    导语 pytorch作为目前主流的深度学习训练框架之一 可以说是每个算法同学工作中的必备技能 此外 pytorch提供了极其方便的API用来进行分布式训练 由于最近做的工作涉及到一些分布式训练的细节 在使用中发现一些之前完全不会care的点
  • cnn 验证集 参与训练吗_使用Sentencepiece +CNN进行文本分类

    1 前言 Sentencepiece是google开源的文本Tokenzier工具 其主要原理是利用统计算法 在语料库中生成一个类似分词器的工具 外加可以将词token化的功能 对比开源的分词器 它会将频繁出现的字符串作为词 然后形成词库进
  • 简而易懂的CPU和MMU画图讲解

    我们知道 程序文件一般放在硬盘上 当把程序运行起来时 程序被放入内存中 通过内存放入cache 通过cache进入cpu 下图中预取器就是负责从cache取出指令 然后由译码器译码 译码的作用就是要知道需要哪些寄存器配合完成指令 如该指令是
  • 对比学习损失 InfoNCE

    对比学习损失 Contrastive Learning Loss 是一种用于自监督学习的损失函数 它侧重于学习一个特征空间 其中相似的样本被拉近 而不相似的样本被推远 在二分类任务中 对比学习损失可以用来学习区分正负样本的特征表示 下面是使
  • 连 JetBrains 都在劝你用正版软件

    https www qikqiak com post free use jetbrains ide https blog csdn net cygcsdn article details 88313512
  • 要想“掌握”自己的命运,就要学会“把控”自己

    近期发生的新闻热点再度引发公众对稳定情绪和心理健康的关注 有时候我们遇到的最大的敌人 不是运气也不是能力 而是失控的情绪和口无遮拦的自己 如何在工作中保持稳定的情绪 谈谈你的看法 作为新时代的打工人 因何会情绪波动 工作中的情绪波动因个人
  • 【计算机科学】【2019】基于深度学习的车辆相关场景理解

    本文为新西兰奥克兰理工大学 作者 Xiaoxu Liu 的硕士论文 共110页 自动驾驶技术是未来交通发展的必然趋势 也是人工智能领域的杰出成就之一 主要是深度学习对自动驾驶的发展做出了重大贡献 深度学习不仅能促进自主车辆感知 识别周围环境
  • Acwing789. 数的范围

    Acwing789 数的范围 题目描述 代码展示 题目描述 代码展示 include
  • C# 获取System.Color 中所有颜色

    将 System Color 中的全部颜色提取出来 经过简单筛选后打乱顺序 做成随机颜色数组 用于存取取出的颜色对象 List
  • node + alipay-sdk 沙箱环境简单测试电脑网站支付

    正式上线需要上传营业执照 不知道怎么去申请一个 使用沙箱测试 首先前往支付宝开放平台控制台可看到左下方的沙箱测试链接 然后设置接口加签方式 选择系统默认密钥 系统默认密钥 gt 公钥模式 gt 查看 相关密钥分3种 应用公钥 应用私钥 选择
  • nestjs:使用nodemailer发送邮件提示mailer Error: Unexpected socket close

    问题 如上 参考 javascript nodemailer Connection closed unexpectedly Stack Overflow 解决办法 如果端口用的465 需要加上 secure true 之前没加导致上述报错
  • qt中将按钮指向的鼠标变成手型

    具体操作的方式有两种 一种是直接通过界面来进行更改 如下 第二种 就是使用代码的形式 ui gt pushButton gt setCursor QCursor Qt PointingHandCursor
  • unix时间戳c语言源码

    在单片机程序开发中 经常会遇到做数据存储 利用时间信息做数据的搜索查询 时间格式最好还是用unix时间戳的形式 可以直接对时间进行加减运算 从RTC中读取的时间一般都是BCD码 如何转换成unix时间戳 简单的做了实现 并开N台电脑从0开始
  • meidaPlayer java.io.IOException: setDataSource failed.: status=0x800000

    1 权限
  • pfSense多拨网速叠加教程

    0 废话 前后一共折腾了两天 发现网上很少有pfsense的多拨教程 查了好多资料终于摸索出来了方法 记录一下 坐标山东 联通光纤入户 200兆 实测稳定在250兆 赞 但是上行只有40兆 最后弄完 下行到了450M 一超过500就全部掉线
  • 杭电OJ 1003 Max Sum

    Max Sum 页面数据来自 this page from http acm hdu edu cn showproblem php pid 1003 Time Limit 2000 1000 MS Java Others Memory Li
  • Leetcode-1991. Find the Middle Index in Array

    Topic Background Given a 0 indexed integer array nums find the leftmost iddleIndex i e the smallest amongst all the poss
  • vben:vue3后台管理项目框架

    前言 Vue Vben Admin 是一个基于 Vue3 0 Vite Ant Design Vue TypeScript 的后台解决方案 目标是为开发中大型项目提供开箱即用的解决方案 包括二次封装组件 utils hooks 动态菜单 权

随机推荐

  • c++ const & constexpr c++98 c++11 c++14

    文章目录 c const 和 constexpr 知识点总结 一 const 1 const修饰变量 修饰普通变量 常量 修饰指针类型 修饰引用类型 2 const修饰函数 const修饰函数参数 const修饰函数返回值 const修饰成
  • 接口超时分析

    原文 接口突然超时 1 网络异常 1 1 网络抖动 经常上网的我们 肯定遇到过这样的场景 大多数情况下我们访问某个网站很快 但偶尔会出现网页一直转圈 加载不出来的情况 有可能是你的网络出现了抖动 丢包了 网页请求API接口 或者接口返回数据
  • Ubuntu16.04下caffe安装编译全过程(CPU)

    caffe是深度学习最好用的框架之一 但caffe的安装编译过程相对较复杂 本人在安装编译时百度了好几个版本 都没有一次成功过 因此在此总结一下自己的编译过程 本文是在Ubuntu16 04下安装编译caffe 其他版本会略有不同 该教程本
  • com.alibaba.druid.support.logging.JakartaCommonsLoggingImpl.

    问题 IDEA调试JDBC出错 com alibaba druid support logging JakartaCommonsLoggingImpl error create connection SQLException url jdb
  • 外包测试3年,离职后成功入职阿里,拿到offer的那天我泪目了...

    一提及外包测试 大部分人的第一印象就是 工作强度大 技术含量低 没有归属感 外包工作三年总体感受就是这份工作缺乏归属感 心里总有一种落差 进步空间不大 接触不到核心技术 公司没有针对你的技术培训与探究 工作简单 业务重复 通常是工具人的存在
  • QDockWidget布局方式

    上图为DockWidget多控件效果图 QDockWidget dock QLatin1String Last filters QWidget multiWidget new QWidget QVBoxLayout layout new Q
  • oracle生成不同uuid,oracle生成uuid

    select sys guid from dual gt 78AE331ADB2B4CE7AB598B1317B39D58 但该函数如下问题 1 返回类型为RAW 2 没有 dash 分隔符 3 返回的字母大写 为了使产生的uuid符合rf
  • vue3之createApp分析

    函数定义 createApp函数定义在文件 packages runtime dom src index ts中 export const createApp args gt const app ensureRenderer createA
  • Python 贝叶斯在文本分类的应用案例

    关注微信公共号 小程在线 关注CSDN博客 程志伟的博客 1 1 文本编码技术简介 1 1 1 单词计数向量 在开始分类之前 我们必须先将文本编码成数字 一种常用的方法是单词计数向量 在这种技术中 一个样本可以包 含一段话或一篇文章 这个样
  • 10种排序算法总结(Python 版)

    文章目录 1 冒泡排序 O n 2 2 快速排序 O nlogn 3 简单插入排序 O n 2 4 希尔排序 O n log n 5 简单选择排序 O n 2 6 堆排序 O n log n 7 归并排序 O n log n 8 计数排序
  • 解决keil5编译报错 undefined symbol

    在编译keil5 工程时出现报错 xxx axf Error L6218E Undefined symbol xxx referred from xxxo 正常情况下遇到Undefined symbol问题根据经验有以下几种原因 1 c文件
  • pinia实现持久化存储

    pinia的作用是什么 Pinia 是 Vue 的存储库 它允许您跨组件 页面共享状态 如果您熟悉 Composition API 您可能会认为您已经可以通过一个简单的 export const state reactive 这对于单页应用
  • 论文笔记--Attention is all you need

    Attention is all you need transformer模型 摘要 当前的序列转录模型基于encoder和decoder的循环或卷积神经网络 较好的做法是在encoder和decoder中间加入一个注意力机制 我们提出了一
  • 使用Spyder,导入tensorflow以及相关库出现kernel died等问题的解决方法

    自从使用了Spyder之后 感觉腰不算了 腿不疼了 走路都带风了 呵呵 好吧 那是之前 使用Spyder给我的感觉就好像一台快报废的电脑重新装了系统一样 刚开始顺风顺水 可是后来就发现毕竟是老年机 容易出现个什么白内障 风湿病什么的 做一些
  • 离散数学:数学语言与证明方法(练习题)

    练习1 1 判断下列命题是真是假 1 x x 答 假 x 并不是 x 元素 2 x x 答 真 x 是 x 子集 3 x x 答 真 x 是 x 元素 4 x x 答 假 x 不是 x 子集 5 x 答 真 是 x 元素但不是任何集合元素
  • SpringBoot:构建一个SpringBoot项目

    文章目录 一 创建项目 1 点击 File gt Project 2 选择 Spring Initializr 3 填写项目基本信息 5 目录结果 6 pom xml 依赖 7 主函数入口 二 项目启动 测试 三 项目源码 SpringBo
  • MongoDB常见问题

    问题一 还原报错 root mongodb bin mongorestore h 127 0 0 1 27017 d runoob directoryperdb data db runoob 2022 12 19T19 47 23 909
  • [LeetCode-21]-Merge Two Sorted Lists(有序列表合并)

    文章目录 题目相关 Solution 不带头结点 增加头结点 使用递归 题目相关 题目解读 合并两个有序列表 并返回新列表 原题描述 原题链接 Merge two sorted linked lists and return it as a
  • 合并两个有序表到新的有序表

    系列目录 左右移动 旋转 数组元素 查找两个升序数组的中间数 判断数组的某一个元素的数量是否超过了整个数组数量的一半 文图介绍 将有序数组A和有序数组B合并得有序数组C A 1 2 3 4 5 B 2 3 4 5 6 C 1 2 2 3 3
  • java什么时候用异常_深入理解Java异常的使用场景

    最近在项目代码中 遇见异常滥用的情形 分析下会带来哪些后果 1 代码可读性变差 业务逻辑难以理解 异常流与业务状态流混在一起 无法从接口协议层面理解业务代码 只能深入到方法 Method 内部才能准确理解返回值的行为 可看一下代码 publ