Java:优雅地处理异常真是一门学问啊!

java.lang.NullPointerException出现的几种原因及解决方案 java.lang.NullPointerException(空指针异常)是Java开发中常见错误,多因对null对象执行操作所致。常见原因包括:调用null对象的方法或属性、将null作为数组访问、null参与自动拆箱、集合未初始化就操作等。 解决方案涵盖:调用前判空(如if语句、Objects.requireNonNull)、初始化对象与集合、使用Optional类规避风险、借助IDE调试定位null源头等。掌握其成因与解决办法,能有效提升代码健壮性,减少程序崩溃隐患,是Java开发者必备技能。 阅读详情

点关注,不迷路;持续更新Java架构相关技术及资讯热文!!!

眼尖的朋友可能还看见了此博客页面左上角还有惊喜哟

Ⅰ

你有没有这样的印象,当你想要更新一款 APP 的时候,它的更新日志里总有这么一两句描述:

  • 修复若干 bug
  • 杀了某程序员祭天,并成功解决掉他遗留的 bug

作为一名负责任的程序员,我们当然希望程序不会出现 bug,因为 bug 出现的越多,间接地证明了我们的编程能力越差,至少领导是这么看的。

事实上,领导是不会拿自己的脑袋宣言的:“我们的程序绝不存在任何一个 bug。”但当程序出现 bug 的时候,领导会毫不犹豫地选择让程序员背锅。

为了让自己少背锅,我们可以这样做:

  • 在编码阶段合理使用异常处理机制,并记录日志以备后续分析
  • 在测试阶段进行大量有效的测试,在用户发现错误之前发现错误

还有一点需要做的是,在敲代码之前,学习必要的编程常识,做到兵马未动,粮草先行。

Ⅱ

在 Java 中,异常(Throwable)的层次结构大致如下。

Error 类异常描述了 Java 运行时系统的内部错误,比如最常见的 OutOfMemoryError和NoClassDefFoundError。

导致 OutOfMemoryError 的常见原因有以下几种:

  • 内存中加载的数据量过于庞大,如一次从数据库取出过多数据;
  • 集合中的对象引用在使用完后未清空,使得 JVM 不能回收;
  • 代码中存在死循环或循环产生过多重复的对象;
  • 启动参数中内存的设定值过小;

OutOfMemoryError的解决办法需要视情况而定,但问题的根源在于程序的设计不够合理,需要通过一些性能检测才能找得出引发问题的根源。

导致NoClassDefFoundError的原因只有一个,Java 虚拟机在编译时能找到类,而在运行时却找不到。

NoClassDefFoundError的解决办法,我截了一张图,如上所示。当一个项目引用了另外一个项目时,切记这一步!

Exception(例外)通常可分为两类,一类是写代码的人造成的,比如访问空指针(NullPointerException)。应当在敲代码的时候进行检查,以杜绝这类异常的发生。

if (str == null || "".eqauls(str)) {
}

另外一类异常不是写代码的人造成的,要么需要抛出,要么需要捕获,比如说常见的IOException。

抛出的示例。

public static void main(String[] args) throws IOException {
	InputStream is = new FileInputStream("Java____superman.txt");
	int b;
	while ((b = is.read()) != -1) {
	}
}

捕获的示例。

public static void main(String[] args) {
	try {
		InputStream is = new FileInputStream("Java____superman.txt");
		int b;
		while((b = is.read()) != -1) {
		}
	}
	catch (IOException e) {
		e.printStackTrace();
	}
}

Ⅲ

当抛出异常的时候,剩余的代码就会终止执行,这时候一些资源就需要主动回收。Java 的解决方案就是finally子句——不管异常有没有被捕获,finally子句里的代码都会执行。

在下面的示例当中,输入流将会被关闭,以释放资源。

public static void main(String[] args) {
	InputStream is = null;
	try {
		is = new FileInputStream("Java____superman.txt");
		int b;
		while ((b = is.read()) != -1) {
		}
	}
	catch (IOException e) {
		e.printStackTrace();
	}
	finally {
		is.close();
	}
}

但我总觉得这样的设计有点问题,因为 close() 方法同样会抛出 IOException :

public void close() throws IOException {}

也就是说,调用close()的 main 方法要么需要抛出IOException,要么需要在finally子句里重新捕获IOException。

选择前一种就会让try catch略显尴尬,就像下面这样。

public static void main(String[] args) throws IOException {
	InputStream is = null;
	try {
		is = new FileInputStream("Java____superman.txt");
		int b;
		while ((b = is.read()) != -1) {
		}
	}
	catch (IOException e) {
		e.printStackTrace();
	}
	finally {
		is.close();
	}
}

选择后一种会让代码看起来很臃肿,就像下面这样。

public static void main(String[] args) {
	InputStream is = null;
	try {
		is = new FileInputStream("Java____superman.txt");
		int b;
		while ((b = is.read()) != -1) {
		}
	}
	catch (IOException e) {
		e.printStackTrace();
	}
	finally {
		try {
			is.close();
		}
		catch (IOException e) {
			e.printStackTrace();
		}
	}
}

总之,我们需要另外一种更优雅的解决方案。JDK7 新增了 Try-With-Resource 语法:如果一个类(比如 InputStream )实现了 AutoCloseable 接口,那么就可以将该类的对象创建在 try 关键字后面的括号中,当 try-catch 代码块执行完毕后,Java 会确保该对象的 close 方法被调用。示例如下。

public static void main(String[] args) {
	try (InputStream is = new FileInputStream("Java____superman.txt")) {
		int b;
		while ((b = is.read()) != -1) {
		}
	}
	catch (IOException e) {
		e.printStackTrace();
	}
}

Ⅳ

关于异常处理机制的使用,我这里总结了一些非常实用的建议,希望你能够采纳。

1、尽量捕获原始的异常。

实际应该捕获 FileNotFoundException ,却捕获了泛化的 Exception 。示例如下。

InputStream is = null;
try {
	is = new FileInputStream("Java____superman.txt");
}
catch (Exception e) {
	e.printStackTrace();
}

这样做的坏处显而易见:假如你喊“王二”,那么我就敢答应;假如你喊“老王”,那么我还真不敢答应,万一你喊的我妹妹“王三”呢?

很多初学者误以为捕获泛化的 Exception 更省事,但也更容易让人“丈二和尚摸不着头脑”。相反,捕获原始的异常能够让协作者更轻松地辨识异常类型,更容易找出问题的根源。

2、尽量不要打印堆栈后再抛出异常

当异常发生时打印它,然后重新抛出它,以便调用者能够适当地处理它。就像下面这段代码一样。

public static void main(String[] args) throws IOException {
	try (InputStream is = new FileInputStream("Java____superman.txt")) {
	}
	catch (IOException e) {
		e.printStackTrace();
		throw e;
	}
}

这似乎考虑得很周全,但是这样做的坏处是调用者可能也打印了异常,重复的打印信息会增添排查问题的难度。

java.io.FileNotFoundException: Java____superman.txt (系统找不到指定的文件。)
	at java.io.FileInputStream.open0(Native Method)
	at java.io.FileInputStream.open(FileInputStream.java:195)
	at java.io.FileInputStream.<init>(FileInputStream.java:138)
	at java.io.FileInputStream.<init>(FileInputStream.java:93)
	at learning.Test.main(Test.java:10)
Exception in thread "main" java.io.FileNotFoundException: Java____superman.txt (系统找不到指定的文件。)
	at java.io.FileInputStream.open0(Native Method)
	at java.io.FileInputStream.open(FileInputStream.java:195)
	at java.io.FileInputStream.<init>(FileInputStream.java:138)
	at java.io.FileInputStream.<init>(FileInputStream.java:93)
	at learning.Test.main(Test.java:10)

3、千万不要用异常处理机制代替判断

我曾见过类似下面这样奇葩的代码,本来应该判 null 的,结果使用了异常处理机制来代替。

public static void main(String[] args) {
	try {
		String str = null;
		String[] strs = str.split(",");
	} catch (NullPointerException e) {
		e.printStackTrace();
	}
}

捕获异常相对判断花费的时间要多得多!我们可以模拟两个代码片段来对比一下。

代码片段 A:

long a = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
	try {
		String str = null;
		String[] strs = str.split(",");
	} catch (NullPointerException e) {
	}
}
long b = System.currentTimeMillis();
System.out.println(b - a);

代码片段 B:

long a = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
	String str = null;
	if (str != null) {
		String[] strs = str.split(",");
	}
}
long b = System.currentTimeMillis();
System.out.println(b - a);

100000 万次的循环,代码片段 A(异常处理机制)执行的时间大概需要 1983 毫秒;代码片段 B(正常判断)执行的时间大概只需要 1 毫秒。这样的比较虽然不够精确,但足以说明问题。

4、不要盲目地过早捕获异常

如果盲目地过早捕获异常的话,通常会导致更严重的错误和其他异常。请看下面的例子。

InputStream is = null;
try {
	is = new FileInputStream("Java____superman.txt");

} catch (FileNotFoundException e) {
	e.printStackTrace();
}

int b;
try {
	while ((b = is.read()) != -1) {
	}
} catch (IOException e) {
	e.printStackTrace();
}

finally {
	try {
		is.close();
	} catch (IOException e) {
		e.printStackTrace();
	}
}

假如文件没有找到的话, InputStream 的对象引用 is 就为 null ,新的 NullPointerException 就会出现。

java.io.FileNotFoundException: Java____superman.txt (系统找不到指定的文件。)
	at java.io.FileInputStream.open0(Native Method)
	at java.io.FileInputStream.open(FileInputStream.java:195)
	at java.io.FileInputStream.<init>(FileInputStream.java:138)
	at java.io.FileInputStream.<init>(FileInputStream.java:93)
	at learning.Test.main(Test.java:12)
Exception in thread "main" java.lang.NullPointerException
	at learning.Test.main(Test.java:28)

NullPointerException 并不是程序出现问题的本因,但实际上它出现了,无形当中干扰了我们的视线。正确的做法是延迟捕获异常,让程序在第一个异常捕获后就终止执行。

Ⅴ

好了,关于异常我们就说到这。异常处理是程序开发中必不可少的操作之一,但如何正确优雅地对异常进行处理却是一门学问,好的异常处理机制可以确保程序的健壮性,提高系统的可用率。

Java 进阶之路:异常处理的内在原理及优雅的处理方式 永远不要期待程序在完全理想的状态下运行,异常往往不期而遇,如果没有完善的异常处理机制,后果可能是灾难性的。对于 Java 工程师而言,合理地处理异常是一种基本而重要的能力,然而,在近来的面试中,笔者发现很多应聘者对异常处理的内在原理几无了解,现场手写的异常处理代码也极为“原始”。 鉴于此,笔者将通过本场 Chat 为读者呈现 Java 异常处理的内在原理、处理原则及优雅的处理方式。主要内容如下: Java 异常的层次结构和处理机制 Java 异常表与异常处理的内在原理 .Java 异常处理的基本原则 优雅 阅读详情

相关推荐

Java:如何优雅地处理异常

在 Java 中,异常处理是一种控制程序流的方法,它允许你捕捉并响应程序执行过程中可能出现的问题。Java 的异常处理机制主要包括以下几个关键字:try、catch、finally、throw 和 throws。在某些情况下,你可能需要创建自己的异常类来更准确地描述错误条件。示例代码try {throw new InvalidAgeException("年龄不能为负数");System.out.println("年龄验证通过");哇塞!

java专栏 4631

极光java sdk_极光使用服务端使用java sdk 出现异常 日志如下

服务器已经开启了443端口 ,并且开通了ip 白名单, 但是 使用java jpush sdk 报错```cn.jiguang.common.resp.APIConnectionException: Connection IO error.Can not connect to JPush Server. Please ensure your internet connection is o...

weixin_42138545的博客 820

SDM量化噪声等效到PLL输出的传递函数推导

在历年文章或书本中少见SDM量化噪声等效到PLL输出的传递函数推导。需了解SDM量化噪声的本质,配合欧拉方程简化,并将Z域转化成S域。最终结合断环处等效到PLL输出的传递函数,方可完成。

u010486560的博客 1407

Java程序员如何优雅编程

导读本文结合作者经验提出了一些编程的建议,这些建议旨在告诉读者如何更好的构造代码以便于它们能更好的工作,也便于将来对代码进行修改和改善的时候有一个参考。甚至,程序也会因此变得更加令人愉悦,更加优雅。01前言在今年的敏捷团队建设中,我通过Suite执行器实现了一键自动化单元测试。Juint除了Suite执行器还有哪些执行器呢?由此我的Runner探索之旅开始了!编程不仅是一项单纯的技能,更是一个充...

架构师小秘圈 416

WPS Office 2026免费安装指南:AI办公与安全使用全解析

办公软件作为数字化办公的核心工具,其基本原理是通过文档处理、数据计算和演示展示等功能模块满足用户日常办公需求。随着人工智能技术的发展,现代办公软件逐步集成AI能力,通过自然语言处理和数据分析算法提升工作效率。在技术价值层面,优秀的办公软件不仅需要保持格式兼容性和跨平台同步能力,更要注重用户数据安全防护。从应用场景来看,无论是个人文档编辑、企业报表分析还是团队协作演示,办公软件都发挥着关键作用。WPS Office 2026作为国产办公软件代表,深度融合AI助手功能,支持智能写作和数据分析,同时通过官方免费策

weixin_30599769的博客 721

【5G演进】4G到5G演进之网络架构与协议栈

4G到5G演进之网络架构与协议栈

Learning makes me happy (0^◇^0) 5530

Java异常处理:优雅应对错误,保障程序稳健运行

异常处理是编写健壮和可靠代码的重要方面。通过适当的异常处理,我们可以保护代码免受意外情况的影响,并提供有用的错误信息和调试信息。同时,合理的异常处理策略和最佳实践可以提高代码的可读性、可维护性和可测试性。在编写Java代码时,不要忽视异常处理,让你的代码更加健壮和可靠。

weixin_43885959的博客 443

乐企归集能力说明文档V2.0006

纳税人销售货物、提供服务开具的增值税发票及购进货物、接受服务取得的增值税发票、海关缴款书(含出口转内销证明)、代扣代缴完税凭证,可以通过本能力进行归集。纳税人可将本能力中的各类规则和接口嵌入本单位信息化系统中(如:销售、报销、财务等),实现发票自动化归集,便于纳税人完成发票入账、抵扣、退税以及代办退税等操作,有效提升涉税业务办理效率。

记录点滴 573

java.lang.NullPointerException出现的几种原因以及解决

java.lang.NullPointerException出现的几种原因: 1、字符串变量未初始化 2、接口类型的对象没有用具体的类初始化,比如: Map map // 会报错 Map map = new Map(); //则不会报错了 3、当一个对象的值为空时,你没有判断为空的情况。 4、字符串与文字的比较,文字可以是一个字符串或Enum的元素,如下会出现异常 String str...

宜春 96万+

CMCC-IPC-A410串口刷机救砖教程

《CMCC-IPC-A410摄像头串口刷机指南》摘要 本指南针对2018年前老款CMCC-IPC-A410摄像头变砖/升级失败的情况,提供串口刷机方案。需准备CH340G串口模块、杜邦线、海康V5.5.82固件等工具。操作包含硬件连接(TX/RX交叉接线)、115200波特率终端配置、CTRL+U进入刷机模式,通过UPF格式化、tftp传输固件、update写入等步骤完成修复。刷机后设备恢复未激活状态,需重置密码,原定制功能可能失效。整个过程需稳定供电,耗时约15-20分钟,注意此操作将使原厂保修失效。(1

海康威视技术支持 1846

手把手教你ensp仿真搭建校园网(含防火墙及无线网络)系列(一)校园网核心交换机配置

本系列博客将带你从零开始,使用 华为 eNSP(Enterprise Network Simulation Platform) 仿真搭建一个完整的校园网络,涵盖 核心层、汇聚层、接入层、防火墙安全策略、无线AC+AP组网 等实战场景。无论你是网络初学者还是希望深化实战经验的工程师,都能通过本教程掌握企业级网络的规划、配置与排错技巧。

echo的博客 3797

java if 异常_Java:优雅地处理异常真是一门学问啊!

本篇我们来谈谈如何优雅地处理异常。01、异常处理机制可以少出 bug你有没有这样的印象,当你想要更新一款 APP 的时候,它的更新日志里总有这么一两句描述:修复若干 bug杀了某程序员祭天,并成功解决掉他遗留的 bug作为一名负责任的程序员,我们当然希望程序不会出现 bug,因为 bug 出现的越多,间接地证明了我们的编程能力越差,至少领导是这么看的。事实上,领导是不会拿自己的脑袋宣言的:“我们的...

weixin_35695430的博客 321

GJB 5000B二级-II实施基础

本文主要描述GJB 5000B二级II实施基础与GJB 5000A的变化情况,以及过程域各条款的实施要点

Abel的博客 2581

java < 处理_Java:优雅地处理异常真是一门学问啊!

01、你有没有这样的印象,当你想要更新一款 APP 的时候,它的更新日志里总有这么一两句描述:修复若干 bug杀了某程序员祭天,并成功解决掉他遗留的 bug作为一名负责任的程序员,我们当然希望程序不会出现 bug,因为 bug 出现的越多,间接地证明了我们的编程能力越差,至少领导是这么看的。事实上,领导是不会拿自己的脑袋宣言的:“我们的程序绝不存在任何一个 bug。”但当程序出现 bug 的时候,...

weixin_34307029的博客 190

BART non-Cartesian 重建:并行成像 压缩感知

本文主要使用并行成像和压缩感知方法实现non-Cartesian MRI 数据的重建。

张哥频道:电生理信号和磁共振成像 1182

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

java清空txt内容_Java:优雅地处理异常真是一门学问啊!

01、你有没有这样的印象,当你想要更新一款 APP 的时候,它的更新日志里总有这么一两句描述:修复若干 bug杀了某程序员祭天,并成功解决掉他遗留的 bug作为一名负责任的程序员,我们当然希望程序不会出现 bug,因为 bug 出现的越多,间接地证明了我们的编程能力越差,至少领导是这么看的。事实上,领导是不会拿自己的脑袋宣言的:“我们的程序绝不存在任何一个 bug。”但当程序出现 bug 的时候,...

weixin_36132709的博客 637

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

未捕获异常string was not recognized_Java:优雅地处理异常真是一门学问啊!

01、你有没有这样的印象,当你想要更新一款 APP 的时候,它的更新日志里总有这么一两句描述:修复若干 bug杀了某程序员祭天,并成功解决掉他遗留的 bug作为一名负责任的程序员,我们当然希望程序不会出现 bug,因为 bug 出现的越多,间接地证明了我们的编程能力越差,至少领导是这么看的。事实上,领导是不会拿自己的脑袋宣言的:“我们的程序绝不存在任何一个 bug。”但当程序出现 bug 的时候,...

weixin_39625782的博客 247

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

优雅地处理异常真是一门学问啊!

优雅的异常处理

沉默王二 5927

Java异常链:如何优雅地传递和处理异常!

ava 中虽然已经内置了丰富的异常类, 但是并不能完全表示实际开发中所遇到的一些异常,此时就需要维护符合我 们实际情况的异常结构.例如, 我们实现一个用户登陆功能.if (!if (!System.out.println("登陆成功");此时我们在处理用户名密码错误的时候可能就需要抛出两种异常. 我们可以基于已有的异常类进行扩展(继承), 创建 和我们业务相关的异常类.具体方式:1. 自定义异常类,然后继承自Exception 或者 RunTimeException。

2301_80221228的博客 2154

如何优雅地处理 Java 异常

点击上方"Java学习之道",选择"关注"公众号每天早晨,干货准时奉上!本文作者:lrwinx 链接:https://lrwinx.github.io...

Java学习之道 2329

Java异常处理全解析:从崩溃到优雅恢复的秘诀

主要介绍Java异常处理体系,Java 异常处理体系包括多种类型的异常和处理机制,合理使用异常处理可以提高程序的健壮性和可维护性。

qq_45438032的博客 2579
上一篇: Java面试中最高频的那20%知识点是什么?
下一篇: 面试官:为什么 Java 中只有值传递?
程序员摩西
博客等级 码龄7年 45粉丝 104原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值