Java 开发者的实操避坑指南

本文介绍了Java中如何优雅地处理空指针异常,推荐使用Optional来避免NullPointerException。同时,讨论了Java异常处理的最佳实践,包括避免遍历集合时的并发修改异常,以及类型转换和枚举异常的处理策略。对于资源管理,文章提倡使用Java 7的try-with-resources来简化代码并提高容错性。在数值计算方面,强调了BigDecimal的使用,特别是精度设置和比较中的注意事项。最后,提到了Lombok工具使用时的潜在问题,特别是变量命名的规范对反序列化的影响。

1、Java 空指针处理

使用 Optional 优雅规避空指针时,需要注意什么?

Optional:
在这里插入图片描述

在这里插入图片描述


Option 优雅判空示例:
在这里插入图片描述

2、Java 异常处理

推荐 - 统一异常的处理,避免满屏的 try - catch
在这里插入图片描述

1. 并发修改异常(遍历集合时,删除集合的元素)

建议使用 JDK8 的 Stream 过滤,不建议遍历删除。否则务必使用 Iterator 迭代器遍历删除集合元素。

2.类型转换异常

当转换一个类,却不能确定该类的具体类型时,有以下两种方法获取对象的类型

1.object.getClass().getName(); - 返回类的类型,如:pers.cjh.java.Worker

2.object instanceof Manager(类名) - 返回 bool 值

3.枚举异常

当执行 枚举类.valueOf(“xx”),如果 xx 不是枚举类的枚举值,那么就会抛出 java.lang.IllegalArgumentException 异常。而很多情况下,xx 是用户输入的值,我们并不能保证其是否合理。
在这里插入图片描述
在这里插入图片描述

解决方案:
使用 Google Guava Enums,需要相关的依赖。

Guava 的依赖

<dependency>
	<groupId>com.google.guava</groupId>
	<artifactId>guava</artifactId>
	<version>12</version>
</dependency>

在这里插入图片描述
在这里插入图片描述
当存在枚举值时,照常返回枚举值。如果不存在枚举值,不会抛出异常,而是返回 Optional.absent(),即 Optional 类的子类 Absent 类。

使用 try finally 资源泄露隐患

初级程序的资源关闭:

// 1. 单个资源关闭
InputStream in = new FileInputStream("");
try {
	// do
} finally {
	in.close();
}

// 2. 多个资源的关闭
InputStream in = new FileInputStream("");
try {
	OutputStream out = new FileOutputStream("");
	try {
		byte[] buf = new byte[100];
		int n;

		while((n = in.read(buf)) >= 0) {
			out.write(buf, 0, n);
		}
	} finally {
		out.close();
	}
} finally {
	in.close();
}

从以上程序可以看出由 try finally 方式实现资源的关闭有很大的冗余代码,而且如果 try 和 finally 同时抛出异常,那么 finally 中的异常会覆盖 try 产生的异常,即抛出的最终异常中并不会出现 try 抛出的异常,又因为 finally 中的 close 方法也有小概率抛出异常,所以 try finally 实现关闭异常不利于异常排查。

下面介绍 java7 引入的 try with resources 实现自动的资源关闭,这种方式不仅使用更简单而且有更好的容错性。我们只需要去申明他、使用他,关闭的事情不需要我们再去关注,即将原先的 try-catch-finally 简化为 try-catch,而且最终抛出的异常也是 try 代码块产生的异常,便于排查异常。

// 1. 单个资源的关闭
try (BufferedReader br = new BufferedReader(new FileReader(""))) {
	return br.readLine();
}

// 2. 多个资源的关闭
try (FileInputStream in = new FileInputStream("");
	 FileOutputStream out = new FileOutputStream("")
) {
	byte[] buffer = new byte[100];
	int n = 0;
	while((n = in.read(buffer)) != -1) {
		out.write(buffer, 0, n);
}
 

3、Java 计算异常

数值计算经常考虑的三个问题

用于精确计算的类 BigDecimal,BigDecimal 可以用来对超过 16 位有效位的数进行精确的运算,Double 可以处理 16 位的数字,但是在实际运用中,可能需要对更大或者更小的数字进行运算和处理。而 BigDecimal 的核心就是精度,他活跃于对精度敏感的业务中,因为 BigDecimal 创建的是对象,所以我们不能直接使用 ±*/ 等运算,而需要调用对象提供的 API,而方法参数通常也是 BigDecimal 对象。

精度经常需要考虑的三个问题:1.初始化设置精度;2.除法结果的精度匹配;3.数值比较的精度匹配。
在这里插入图片描述

初始化设置精度的匹配解决方案

// 1. 初始化设置精度
BigDecimal decimal = new BigDecimal("12.222");
// 设置精度以后,如果出现了精度丢失就会直接抛出精度丢失异常
BigDecimal result = decimal.setScale(2);
System.out.println(result);

因为上面设置的精度太小,产生了精度丢失,所以抛出了如下的算数异常(精度丢失)。而设置的精度比数字的精度大则没有关系,小数部分会以零补齐。
在这里插入图片描述

当然我们也可以设置如下四舍五入的精度丢失方式,这样就会把超出精度的数字舍弃,而不会抛出异常。
在这里插入图片描述
在这里插入图片描述

除法结果精度匹配的解决方案

BigDecimal 做除法时会出现除不尽的情况。

代码如下:

// 30 / 7 是除不尽的
System.out.println(new BigDecimal("30").divide(new BigDecimal(7 )));

在这里插入图片描述


在数学运算中除不尽是很正常的,我们通常的解决方案就是设置一个有效数位,即确定精度。

实现代码如下:
在这里插入图片描述
在这里插入图片描述

比较中,精度问题导致结果和预期不一致的解决方案

如下代码所言,运行结果的显示指 0 和 0.0 是不相等的。
在这里插入图片描述
所以在使用 BigDecimal 做数值比较时,不要使用 equals 方法,而应该使用 compareTo 方法,这个方法返回的是 -1、0、1 这三个数值来指代大小。

4、lombok 工具使用上的两个坑

变量名的第二个字母是大写

其实第二个字母不能是大写是 JavaBean 的编码规范,如果我们没有遵守这个规范,在使用 lombok 时,可能会出现给变量赋值不上去的情况。例如:有一个变量名为 aFiled 而且其对应的 json 名也是 aFiled,但是我们会发现在使用 Jackson 反序列化数据的时候 aFiled 变量是不能被正确赋值的,即打印输出的仍然是 null。又因为远程调用组件 Feign 默认是采用 Jackson 反序列化数据,所以第二个字母不能是大写的规范务必要遵守。

Jackson 默认是根据 JavaBean 规范找到对应属性后再赋值,也就是说 Jackson 并没有在这个对象找到 aFiled 属性。JavaBean 属性名称跟变量名称是不一定相同的。JavaBean 是通过对象的 get、set 方法来确定对象属性,其属性名称是由其对象变量来决定的,通常的逻辑是:将属性首字母转成大写。但也有例外,就是前两个字母有大写的情况,如下是整理出来的对于变量前两个字母出现大写时候的 JavaBean 规范:
在这里插入图片描述
从上图可以得出的结论就是:如果变量名称的前两个字母存在大写,那么依据 JavaBean 规范生成的 get、set 方法不用改变变量名称(即首字母不用再大写了)。我们项目上使用的是 lombok,其生成的 get、set 方法是不遵循 JavaBean 规范的,只是将变量名的首字母大写而已,所以它生成 aFiled 的方法还是会把首字母大写 getAFiled。所以,Jackson 在接收到 aFiled 属性值,它依据 JavaBean 规范会到对象找 setaFiled 方法,自然这个对象是没有这个方法的,所以就没映射到 aFiled 字段上。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值