java异常捕捉陷阱(内存泄漏,finally块,catch块,继承得到的异常)

手把手教你用光耦搭建安全隔离电路:从洗衣机控制板到PLC输入模块实战 本文通过洗衣机控制板驱动高压电机和PLC输入模块采集现场信号两个实战场景,手把手教你使用光耦搭建安全隔离电路。文章详细解析了电路架构、关键器件选型、参数计算、仿真验证及PCB布局避坑技巧,并对比了光耦与数字隔离器的适用场景,帮助电子工程师掌握这门保障系统稳定与安全的必备技能。 阅读详情
 

 

1.    异常捕捉的陷阱

异常处理机制是java语言的特色之一,尤其是java语言的Checked异常,更是体现了java语言的严谨性:没有完善错误处理的代码根本不会被执行。对于Checked异常,java程序要么声明抛出,要么使用try……catch进行捕获。

1.1  正确关闭资源的方式

在实际开发中,经常需要在程序中打开一些物理资源,如数据库连接,网络连接,磁盘文件等,打开这些物理资源之后必须显示关闭,否则将会导致资源泄漏。因为垃圾回收机制属于java内存管理的一部分,它只是负责会受堆内存中分配出来的内存,至于程序中打开的物理资源,垃圾回收机制是无能为力的。

为了正常关闭程序中打开的物理资源,应该使用finally块来保证回收。比如下面三种关闭资源的方式,哪种更好些?

public static void main(String args[]) throws Exception {
                   Student student_new = new Student("liyafang");
                   Student student_recover = null;
                   ObjectOutputStream oos = null;
                   ObjectInputStream ois = null;
                   try {
                            oos = new ObjectOutputStream(new FileOutputStream("liyafang.txt"));
                            ois = new ObjectInputStream(new FileInputStream("liyafang.txt"));
                            oos.writeObject(student_new);
                            oos.flush();
                            student_recover = (Student) ois.readObject();
                            System.out.println(student_recover.equals(student_new));
                            System.out.println(student_recover == student_new);
                   } finally {
//1.第一种关闭资源的方式(不够安全):程序刚开始指定oos = null;ois = null;完全有可能在程序运行过程中初始化oos之前就引发了异常,那么oos,ois还没有来得及初始化,因此oos,ois根本无需关闭。
                            oos.close();
                            ois.close();
//2.第二种关闭资源的方式(还是不够安全):假如程序开始已经正常初始化了oos,ois两个IO流,在关闭oos是出现了异常,那么程序将在关闭oos时非正常退出,这样就导致ois得不到关闭,从而导致资源泄漏。为了保证关闭各资源时出现的异常不会相互影响,应该在关闭每个资源时分开使用try catch块来保证关闭操作不会导致程序非正常退出。
                            if(oos != null){
                                     oos.close();
                            }
                            if(ois != null){
                                     ois.close();
                            }
//3.第三种关闭资源的方式(比较安全):主要保证一下几点:
//(1)使用finally块来关闭物理资源,保证关闭操作始终会被执行;
//(2)关闭每个资源之前首先保证引用该资源的引用变量不为null;
//(3)为每个物理资源使用单独的trycatch块关闭资源,保证关闭资源时引发的异常不会影响其他资源的关闭。
                            if(oos != null){
                                     try{
                                               oos.close();
                                     }catch (Exception ex){
                                               ex.printStackTrace();
                                     }
                            }
                            if(ois != null){
                                     try{
                                               ois.close();
                                     }catch (Exception ex){
                                               ex.printStackTrace();
                                     }
                            }                 }
         }

1.2  finally块的陷阱

当程序在finally之前使用System.exit(0),finally将不执行。调用System.exit(0)将使JVM退出,只要JVM不退出,finally就一定会得到执行。

在java程序执行try块、catch块时遇到了return语句,return语句会导致该方法立即结束。系统执行完return语句之后,并不会立即结束该方法,而是去寻找该异常处理流程中是否包含Finally块,如果没有Finally块,方法终止,返回相应的返回值。如果有Finally块,系统立即开始执行Finally块,只有当Finally执行完成后,系统才会再次跳回来根据return语句结束方法。如果Finally块使用了return语句来导致方法的结束,则finally块已经结束了方法,系统不会跳回去执行trycatch里的任何代码。

public int test(){
                   int count = 1;
                   try{
                            return ++count;
                   }finally{
                            return ++count;
                   }
         }
//以上代码最终返回值是:3
public int test(){
                   int count = 1;
                   try{
                            return ++count;
                   }finally{
                            return count++;
                   }
         }
//以上代码最终返回值是:2


throw语句的执行和return语句比较类似。当程序执行trycatch块遇到throw语句时,throw语句会导致该方法立即结束,系统执行throw语句时并不会立即抛出异常,而是去寻找该异常处理流程中是否包含finally块。如果没有finally块,程序立即抛出异常。如果有finally块,系统立即执行finally块,只有当finally块执行完成之后,系统才会再次跳出来抛出异常。如果finally块里使用return语句来结束方法,系统将不会跳回去执行try块,catch块去抛出异常。

例如1:

int count = 1;
                   try{
                            throw new RuntimeException("异常1");
                   }finally{
                            return count++;
                   }
//执行结果:返回值是1,同时不会抛出任何异常。


例如2:

int count = 1;
                   try{
                            throw new RuntimeException("异常1");
                   }finally{
                            throw new RuntimeException("异常2");
                   }
//执行结果:Exception in thread "main" java.lang.RuntimeException: 异常2


1.3  catch块的用法

1.3.1 catch的顺序

对于java的异常捕获来说,每个try块至少需要一个catch块或一个finally块,绝不能只有单独一个孤零零try块。通常情况下,如果try块被执行一次,则try块后只有一个catch块会被执行,绝不可能有多个catch块被执行。除非在循环中使用了continue开始下一次循环,下一次循环又重新运行了try块,才可能导致多个catch块被执行。由于异常处理机制中排在前面的catch(XxxException ex)块总是会优先获得执行的机会,因此java对try块后的多个catch块的排列顺序是有要求的。

   因为java的异常有非常严格的继承体系,许多异常类之间有严格的父子关系,比如程序FileNotFoundException异常就是IOException的子类。捕获父类异常的catch块都应该排在捕捉子类异常的catch块之后【先处理小异常(子类异常),在处理大异常(父类异常)】,否则将出现编译错误。

         例如以下两个catch语句不能颠倒顺序:

                 

 FileInputStream fis = null;
                   try{
                            fis = new FileInputStream("a.bin");
                            fis.read();
                   }catch(FileNotFoundException ex){
                            ex.printStackTrace();
                   }catch(IOException e){
                            e.printStackTrace();
                   }

1.3.2不要用catch代替流程控制

如下边这个例子:

String[] students = {"liyafang","zhoushilong","luorongbo"};
                   int i = 0;
                   while(true){
                            try{
                                     System.out.println(students[i++]);
                            }catch(IndexOutOfBoundsException ex){
                                     break;
                            }
                   }


这种遍历数组的方式不仅难以阅读,而且运行速度还非常慢。

千万不要使用异常来进行流程控制。异常机制不是为流程控制而准备的,异常机制知识为程序的意外情况准备的,因此程序只应该为异常情况使用异常机制。所以,不要使用这种“别出心裁”的方法来遍历数组。

1.3.3只能catch可能抛出的异常

    /*public static void test1(){
                   try{
                            System.out.println("something");
                   }catch(IOException e){
                            e.printStackTrace();
                   }
         }
         public static void test2(){
                   try{
                            System.out.println("something");
                   }catch(ClassNotFoundException e){
                            e.printStackTrace();
                   }
         }*/


以上代码java编译器是不允许的。

根据java语言规范,如果一个catch子句试图捕获一个类型为XxxException的Checked异常时,那么它对应的try子句必须可能抛出XxxException或其子类的异常,否则编译器将提示该程序具有编译错误—但在所有的Checked异常中,Exception是一个异类,无论try块是怎样的代码,catch(Exception e)总是正确的。

RuntimeException 类及其子类的实例被称为Runtime异常,不是RuntimeException类及其子类的异常实例则被称为Checked异常,只要愿意,程序员总可以使用catch(XxxException ex)来捕获运行时异常。

总之,程序使用catch捕捉异常时,其实并不能随心所欲地捕捉所有异常。程序可以在任意想捕捉的地方捕捉RuntimeException异常,Exception,但对于其他的Checked异常,只有当try块可能抛出该异常时(try块中调用的某个方法声明抛出了该Checked异常),catch块才捕捉该Checked异常。

 1.3.4实际的修复

如果程序知道如何修复指定异常,应该在catch块内尽量修复该异常,当该异常情况被修复后可以再次调用该方法;如果程序不知道如何修复该异常,也没有进行任何修复,千万不要再次调用可能导致该异常的方法。

无论如何不要在finally块中递归调用可能引起异常的方法,因为这将导致该方法的异常不能被正常抛出,甚至StackOverflowError错误也不能中止程序,只能采用强行结束java.exe进程的方法来中止程序的运行。

1.4  继承得到的异常

Java语言规定:子类重写父类的方法时,不能声明抛出比父类方法类型更多,范围更大的异常。也就是说,子类重写父类方法时,子类方法只能声明抛出父类方法所声明抛出的异常的子类。

例如:

public interface Type1 {
         void test() throws ClassNotFoundException;
}
public interface Type2 {
         void test() throws NoSuchMethodException;
}
class Test implements Type1, Type2 {
         @Override
         public void test() {
         }
}


上面代码的异常处理是正确的。

Test实现了Type1接口,实现Type1接口里的test()方法时可以声明抛出ClassNotFoundException异常或该异常的子类,或者不声明抛出;Test类实现了Type2接口,实现了Type2接口里的test()方法时可以声明抛出NoSuchMethodException异常或该异常的子类,或者不声明抛出。由于Test类同时实现了Type1,Type2两个接口,因此需要同时实现两个接口中的test()方法。只能是上面两种声明抛出的交集,不能声明抛出任何异常。

 

自动驾驶算法/规划决策控制算法面经汇总、学习路线、面经心得 自动驾驶算法学习路线,面试求职大全 阅读详情

相关推荐

医学图像处理实战:3D Slicer从安装到病灶分析全流程指南

本文提供了一份详尽的3D Slicer实战指南,涵盖从软件安装、DICOM数据导入到图像增强、病灶分割及三维可视化的全流程。重点演示了如何利用阈值分割、区域生长等核心图像处理技术进行病灶分析,并生成定量报告,是医学影像分析初学者的实用入门教程。

weixin_29278805的博客 600

JasperReport报表导出常见问题(内存泄漏)

JasperReport报表导出常见问题 (内存泄漏)

一个记录的地方 2235

手把手教你用Trae配置Python开发环境(含Claude 3.5代码生成实战)

本文详细介绍了如何使用字节跳动推出的Trae智能开发环境配置Python开发环境,并实战演示了Claude 3.5代码生成功能。从环境准备到项目初始化,再到AI辅助编码和调试优化,全面展示了Trae在提升开发效率方面的强大能力,特别适合Python开发者快速搭建项目和解决复杂问题。

weixin_28309571的博客 976

Avoid empty catch blocks

http://www.javapractices.com/topic/TopicAction.do?Id=16 Most contend that it's usually a very bad idea to have an empty catch block. When the exception occurs, nothing happens, and the program fai

guolong1983811的专栏 2389

数控弯管机xyz转换ybc的算法_花了一年时间开发的三维弯管机交互式转档软件(三维管子模型UG,SOLIDWORK,PRO/E文件转成YBC)...

在弯管机加工中,由管子模型生成可直接进行弯管加工的YBC数据可以大大提高弯管编程过程.传统的做法是先用dxf数据文件(用autocad绘制管子的轴心线数据)转出XYZ数据,然后由XYZ数据转成YBC数据,而且大部分厂家对文件版本以及软件做管方式都有不少限制,这大大花费了用户的时间跟精力.随着企业的信息化管理以及不断的技术升级,传统用autocad线条模式来描述管子的方式正在被用户用PRO/E,UG...

weixin_29065959的博客 1961

HTML入门(详细教程),前端入门从这里开始

HTML基础教程,网页框架搭建,表单制作,了解HTML标签的基本用法,每个标签具备哪些属性。

wandertp的博客 1283

PMD规则之Basic Rules

Normal 0 7.8 磅 0 2 false false false MicrosoftInternetExplorer4 <! /* Style

jack0511的专栏 9774

保边滤波之Mean shift filter

保边滤波之Mean shift filter 目录 保边滤波之Mean shift filter 一、算法原理 二、练手实现的算法代码如下: 三、实现结果 一、算法原理 在OpenCV中,meanshift filter函数为 p...

大熊 1561

Android代码中遇到的一些警告或问题汇总

1. ‘catch’branch identical to‘instantiationexception’branch: Reports identical catch sections in try blocks under JDK 7. A quickfix is available to collapse the sections into a multi-catch section. ...

Lewis的专栏 6872

Unity中语法糖带来的GC问题 ——那些看起来优雅、实际上在背后偷偷生垃圾的代码

*语法糖(Syntactic Sugar)**指的是编程语言中为了让代码更简洁、易读而提供的简便写法。比如C#中的foreachlambda表达式LINQ自动属性等。语法糖本身不是坏事,但在Unity等对GC敏感的环境下,要警惕语法糖带来的隐式内存分配。合理使用语法糖,关键场合用更“丑陋”但高效的写法,才能保证游戏流畅运行。下面我将更深入地分析Unity中语法糖导致GC的原理、具体场景、检测与优化技巧,并补充一些容易忽视的细节。

本博客聚焦游戏开发技巧、创业实战心得及大学热门课程干货。这里既有技术深度,也有思维广度,无论你是开发者、创业者还是高校学子,都能在这里找到适合自己的成长之路! 517

Vue3 - Element Plus上传组件el-upload上传多个文件时,让on-change监听事件仅执行一次并获取最终文件列表方法(开启多选文件并手动上传,拿到文件列表统一循环调用接口上传)

vue3,elementplus,Upload上传,el-upload,文件上传组件,上传组件on-change里执行多次,取消自动上传后change重复执行问题,upload上传多个文件后导致on-change执行多次拿不到最终文件列表,Element-plus的upload组件on-change不断执行怎么办,上传多个文件多次执行调用,上传多个文件时如何只执行一次on-change方法拿到最终的文件列表,vue3elementplus上传组件开启多个上传后导致change方法执行好几次,仅调用一

🏆 前端领域优质创作者 1万+

第77项:不要忽略异常

  尽管这条建议看上去是显而易见的,但是它却常常被违反,因而值得重复提出来。当API的设计者声明一个方法将抛出某个异常的时候,它们是在试图告诉你某些事情。所以,不要忽略它!要忽略一个异常非常容易,只需要将方法调用通过try语句包围起来,并包含一个空的catch块: // Empty catch block ignores exception - Highly suspect! try { ...

Coloured_Glaze的博客 661

实战:批量抓取免费代理IP全流程(附自动验证+失效剔除,爬虫抗封必备)

本文分享了一套从免费代理IP中筛选可用高匿代理的实用方案。作者通过半年实践,总结出"批量抓取+精准验证+动态维护"的方法,能从2000条免费IP中筛选出30-50条可用代理,满足中小规模爬虫需求。 方案包含四个核心环节: 多源代理抓取:针对快代理、西刺代理等不同网站定制解析规则 三层验证机制:检查有效性、匿名度和响应速度 代理池自动维护:实时淘汰失效IP Scrapy整合实战:提供可直接复用的代码 文章特别指出免费代理的三大痛点:存活率低(80%10分钟内失效)、匿名性差(仅5%是高匿代

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1601

java try catch陷阱_java异常捕捉陷阱(内存泄漏,finally块,catch块,继承得到的异常)...

1. 异常捕捉的陷阱异常处理机制是java语言的特色之一,尤其是java语言的Checked异常,更是体现了java语言的严谨性:没有完善错误处理的代码根本不会被执行。对于Checked异常,java程序要么声明抛出,要么使用try……catch进行捕获。1.1 正确关闭资源的方式在实际开发中,经常需要在程序中打开一些物理资源,如数据库连接,网络连接,磁盘文件等,打开这些物理资源之后必须显...

weixin_36444104的博客 549

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

Java异常捕捉陷阱(内存泄漏,finally块,catch块,继承得到的异常)

1.    异常捕捉的陷阱 异常处理机制是java语言的特色之一,尤其是java语言的Checked异常,更是体现了java语言的严谨性:没有完善错误处理的代码根本不会被执行。对于Checked异常,java程序要么声明抛出,要么使用try……catch进行捕获。1.1  正确关闭资源的方式 在实际开发中,经常需要在程序中打开一些物理资源,如数据库连接,网络连接,磁盘文件等,打开这些物

Thancks 2432

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

java try catch陷阱_java异常捕捉陷阱(事务的异常,内存泄漏,finally块,catch块,继承得到的异常)...

事务的异常回滚默认spring只在发生未被捕获的runtimeexcetpion时才回滚。1、事务不是遇到所有异常都会回滚,默认只有遇到遇到运行异常(RuntimeException)和程序错误(Error)才会回滚,非运行异常必须在@Transactional 注解中使用 rollbackFor 属性来指定异常,比如:@Transactional(rollbackFor = Exception....

weixin_29442503的博客 310

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

java 异常处理 最佳_Java异常处理最佳实践及陷阱防范

前言不管在我们的工作还是生活中,总会出现各种“错误”,各种突发的“异常”。无论我们做了多少准备,多少测试,这些异常总会在某个时间点出现,如果处理不当或是不及时,往往还会导致其他新的问题出现。所以我们要时刻注意这些陷阱以及需要一套“最佳实践”来建立起一个完善的异常处理机制。正文异常分类首先,这里我画了一个异常分类的结构图。在JDK中,Throwable是所有异常的父类,其下分为”Error“和”Ex...

weixin_31076517的博客 117

java陷进

1.    异常捕捉的陷阱 异常处理机制是java语言的特色之一,尤其是java语言的Checked异常,更是体现了java语言的严谨性:没有完善错误处理的代码根本不会被执行。对于Checked异常,java程序要么声明抛出,要么使用try……catch进行捕获。1.1  正确关闭资源的方式 在实际开发中,经常需要在程序中打开一些物理资源,如数据库连接,网络连接,磁盘文件等,打开这些物

xyjikl 684

基于字节码的统一异常上报实践

一、前言 二、异常介绍 2.1 认识异常 2.2 Java异常的分类 2.3 异常的处理流程 2.4 异常抛出与捕获的原则 2.5 认识try/catch/finally

java_beautiful的博客 518

Java架构治理新范式:用AST静态分析实现模块自治与契约验证

在微服务与模块化开发日益普及的今天,‘高内聚低耦合’常沦为口号,而真实系统中隐性依赖、跨模块契约违规、运行时类加载冲突等问题频发。AST(抽象语法树)作为编译前端的核心结构,能精准捕获设计意图——从import声明、new表达式到Lambda闭包中的类型引用,远超字节码或IDE级分析的粒度。它使架构约束可编程、可验证、可嵌入CI,将传统依赖评审转化为自动化守门机制。Smart-Bus项目正是这一理念的工程落地:通过AST驱动的调用图生成、作用域契约检查与热插拔状态迁移,实现了无Spring的轻量自治架构。本

weixin_34059951的博客 125

Servlet监听器原理与实战:ServletContext、HttpSession、ServletRequest生命周期管理

Servlet监听器是Java Web应用中实现系统可观测性与生命周期治理的核心基础设施,其本质是对ServletContext、HttpSession和HttpServletRequest三大域对象及其属性变更的事件响应机制。基于Servlet规范,监听器通过回调方法在对象创建/销毁、属性增删改等关键节点触发,不干预流程但提供精准状态感知能力。技术价值在于保障资源启停安全、会话状态一致性和请求链路可审计性,广泛应用于连接池管理、用户登出清理、购物车变更追踪、性能监控等生产场景。本文深入剖析三类生命周期监听

weixin_34364071的博客 217

Java AI项目监控实战:5类指标+4条告警打造可靠防线

在传统Java服务中,HTTP状态码、CPU与内存构成监控的“老三样”,但在大模型驱动的AI应用里,这些指标远远不够。可观测性工程的核心在于,通过指标、日志与追踪构建系统全貌。Micrometer作为Java生态的指标门面,搭配Prometheus的时序数据采集与Grafana的可视化能力,形成一套标准化的监控方案。它通过埋点记录请求量、错误率、延迟分位数、Token消耗、队列积压等关键数据,配合合理的告警规则,能在用户投诉前捕捉到模型静默退化、成本飙升等隐患。无论你是做RAG知识库问答、AI客服还是Age

weixin_33806300的博客 286

Copilot实战协作协议:从代码补全到可信协作者

GitHub Copilot 不仅是智能代码补全工具,更是一种新型人机协作范式。其核心原理在于基于上下文的序列预测与语义对齐,技术价值体现在提升开发一致性、加速领域知识沉淀和强化工程合规性。在企业级Java/Python/TypeScript项目中,需通过语义锚点(如@domain、@security)、结构化反馈(@avoid/@require)和CI/CD合规检查链实现可控落地。本文聚焦真实生产环境中Copilot的语义注入、错误闭环训练与AI协作治理,解决‘能用’到‘敢用’的关键断层,尤其适用于Spr

congsikuai0611的博客 341
下一篇: 表达式陷阱(字符串,表达式类型,输入法,注释字符,转义字符,正则表达式)
方方
博客等级 码龄15年 6粉丝 7原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值