Java开发人员五大致命错误

Java开发人员五大致命错误

Java是一种广泛使用的编程语言,它具有跨平台、面向对象、高性能等特点。但即使对于经验丰富的开发人员,也常常会犯一些致命的错误。这些错误可能导致代码质量下降、性能问题或安全漏洞。本文将揭示Java开发人员常犯的五大致命错误,并提供了宝贵的建议,助您避免陷入这些错误,提升代码质量和开发效率。

使用Objects.equals比较对象

​Objects.equals​​是Java 7提供的一个静态方法,它可以用来比较两个对象是否相等,同时避免空指针异常。这个方法看起来很方便,但是如果使用不当,可能会导致意想不到的结果。例如,下面的代码中,使用​​Objects.equals​​比较一个​Long​类型的变量和一个​int​类型的常量,结果却是​false​。

Long longValue = 123L;
System.out.println(longValue == 123); // true
System.out.println(Objects.equals(longValue, 123)); // false

​​Objects.equals​​方法内部会先判断两个参数是否为同一对象,如果不是,再调用第一个参数的​​equals​​方法比较第二个参数。而​Long​类的​​equals​​方法会先判断参数是否为Long类型,如果不是,直接返回​false​。所以,当我们使用​​Objects.equals​​比较一个​Long​类型的变量和一个int类型的常量时,实际上是调用了​Long​类的​​equals​​方法,而这个方法会认为两个参数类型不同,所以返回​false​。要避免这个错误,我们需要注意以下几点:

  • 当比较基本类型和包装类型时,尽量使用​==​运算符,因为它会自动进行拆箱和类型转换,而不会出现类型不匹配的问题。
  • 当比较两个包装类型时,尽量保证它们的类型一致,或者使用相应的​parse​方法将它们转换为基本类型再比较。
  • 当比较自定义类型时,尽量重写​​equals​​方法和​​hashCode​​方法,以实现合理的相等判断逻辑。

日期格式错误

在Java中,我们经常需要对日期进行格式化,以便在不同的场景中显示或存储。为了实现日期格式化,我们通常会使用​​DateTimeFormatte​r​类,它可以根据指定的模式将日期转换为字符串,或者将字符串转换为日期。然而,如果我们使用错误的模式,可能会导致日期格式化出现错误。例如,下面的代码中,使用YYYY-MM-dd模式格式化一个Instant对象,结果却得到了错误的年份。

Instant instant = Instant.parse("2021-12-31T00:00:00.00Z");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("YYYY-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault());
System.out.println(formatter.format(instant)); // 2022-12-31 08:00:00

​DateTimeFormatter​​类中的模式字母YYYY和yyyy有细微的差别。它们都表示年份,但是yyyy表示日历年,而YYYY表示周年。日历年是按照公历的规则划分的,而周年是按照ISO 8601标准划分的,它的第一周是包含1月4日的那一周,而最后一周是包含12月28日的那一周。所以,当我们使用YYYY-MM-dd模式格式化一个Instant对象时,实际上是使用了周年的年份,而不是日历年的年份。而12月31日属于下一年的第一周,所以得到了错误的年份。要避免这个错误,我们需要注意以下几点:

  • 当使用​​DateTimeFormatter​​类格式化日期时,尽量使用yyyy表示年份,而不是YYYY,除非我们确实需要使用周年的概念。
  • 当使用​​DateTimeFormatter​​类解析字符串时,尽量保证字符串的格式和模式的格式一致,否则可能会出现解析异常或错误的日期。
  • 当使用​​DateTimeFormatter​​类进行日期转换时,尽量指定时区,否则可能会出现时差的问题。

在ThreadPool中使用ThreadLocal

​ThreadLocal​​是一种特殊的变量,它可以为每个线程提供一个独立的副本,从而实现线程间的隔离。使用​​ThreadLocal​​可以避免一些线程安全的问题,也可以提高一些性能。然而,如果我们在使用线程池的情况下使用​​ThreadLocal​​,就要小心了,因为这可能会导致一些意想不到的结果。例如,下面的代码中,使用​ThreadLocal​保存用户信息,然后在线程池中执行一个任务,发送邮件给用户。

private ThreadLocal<User> currentUser = ThreadLocal.withInitial(() -> null);
private ExecutorService executorService = Executors.newFixedThreadPool(4);public void executor() {executorService.submit(() -> {User user = currentUser.get();Integer userId = user.getId();sendEmail(userId);});
}

这段代码看起来没有什么问题,但是实际上有一个隐藏的bug。因为我们使用了线程池,线程是可以复用的,所以在使用​​ThreadLocal​​获取用户信息的时候,很可能会误获取到别人的信息。这是因为​​ThreadLocal​​的副本是绑定在线程上的,而不是绑定在任务上的,所以当一个线程执行完一个任务后,它的​​ThreadLocal​​的副本并不会被清除,而是会被下一个任务使用。这样就可能导致数据混乱或安全漏洞。要避免这个错误,我们需要注意以下几点:

  • 当使用​​ThreadLocal​​时,尽量在每次使用完后调用​​remove​​方法,以清除线程的副本,避免对下一个任务造成影响。
  • 当使用线程池时,尽量不要使用​​ThreadLocal​​,而是使用其他的方式来传递数据,例如使用参数或返回值。
  • 当使用线程池时,尽量使用自定义的线程工厂,以便在创建线程时设置一些初始化的操作,或者在回收线程时设置一些清理的操作。

使用HashSet去除重复数据

在编程的时候,我们经常会遇到去重的需求,即从一个集合中去除重复的元素,只保留唯一的元素。为了实现去重,我们通常会使用​HashSet​,它是一种基于哈希表的集合,它可以保证元素的唯一性,同时具有较高的查询效率。然而,如果我们使用​HashSet​去重时不注意一些细节,可能会导致去重失败。例如,下面的代码中,使用​HashSet​去重一个​User​对象的列表,结果却没有去除重复的对象。

User user1 = new User();
user1.setUsername("test");
User user2 = new User();
user2.setUsername("test");
List<User> users = Arrays.asList(user1, user2);
HashSet<User> sets = new HashSet<>(users);
System.out.println(sets.size()); // the size is 2

​HashSet​的去重机制是基于对象的​​hashCode​​方法和​​equals​​方法的。当我们向​HashSet​中添加一个对象时,它会先计算对象的哈希码,然后根据哈希码找到对应的桶,再在桶中遍历元素,使用​​equals​​方法判断是否有相同

在List中循环删除元素

这是一个很常见的错误,很多开发人员都会在使用​​List​​的​​foreach​​循环时,试图在循环体中删除元素,这样做会导致​​ConcurrentModificationException​​异常,因为在迭代过程中修改了集合的结构。如果要在循环中删除元素,应该使用迭代器的​r​emove​​方法,或者使用Java 8提供的​​removeIf​​方法,或者使用一个临时的集合来存储要删除的元素,然后在循环结束后再进行删除。例如:

List<String> list = new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");// 错误的做法,使用foreach循环删除元素
for (String s : list) {if (s.equals("b")) {list.remove(s); // 抛出ConcurrentModificationException异常
}
}// 正确的做法,使用迭代器删除元素
Iterator<String> it = list.iterator();
while (it.hasNext()) {String s = it.next();if (s.equals("b")) {it.remove(); // 安全的删除元素}
}// 正确的做法,使用Java 8的removeIf方法删除元素
list.removeIf(s -> s.equals("b")); // 使用lambda表达式删除元素// 正确的做法,使用临时集合删除元素
List<String> temp = new ArrayList<String>();
for (String s : list) {if (s.equals("b")) {temp.add(s); // 将要删除的元素添加到临时集合中}
}// 一次性删除所有元素
list.removeAll(temp); 

总结

在Java开发中,避免常见错误是提高代码质量和开发效率的关键。本文揭示了Java开发人员常犯的五大致命错误,并提供了宝贵的建议。遵循良好的命名和代码风格,您将能够更好地避免这些错误,提升代码质量并取得更高的开发效率。

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

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

相关文章

web学习笔记(三十三)

目录 1.严格模式 1.1严格模式的概念&#xff1a; 1.2严格模式在语义上更改的地方&#xff1a; 1.3如何开启严格模式 1.4严格模式应用上的变化 2.原型链 1.严格模式 1.1严格模式的概念&#xff1a; 严格模式有点像es5向es6过渡而产生的一种模式&#xff0c;因为es6的语法…

Spring项目问题—前后端交互:Method Not Allowed

问题 前后端交互时出现Method Not Allowed问题 Ajax中使用的是get&#xff0c;方法仍然出现post方法报错 Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method POST not supported] 浏览器中没有报错&#xff0c;只是接收不到后端返…

redis的安装,启动和关闭

linux环境下redis的安装 # 安装redis 默认安装的是3.2.12版本 yum install redis# 安装如果出现错误&#xff0c;可以输入以下命令&#xff0c;然后再次尝试安装 yum install epel-releaseredis的启动 #启动redis #首先启动redis服务 redis-server#然后启动redis客户端&#…

C++:类与对象(中)

一、构造函数 1.1特性 构造函数是特殊的成员函数&#xff0c;需要注意的是&#xff0c;构造函数的虽然名称叫构造&#xff0c;但是需要注意的是构造函数的主要任务并不是开空间创建对象&#xff0c;而是初始化对象。 1. 函数名与类名相同。 2. 无返回值。 3. 对象实例化时编…

面试 Java 并发编程八股文十问十答第九期

面试 Java 并发编程八股文十问十答第九期 作者&#xff1a;程序员小白条&#xff0c;个人博客 相信看了本文后&#xff0c;对你的面试是有一定帮助的&#xff01;关注专栏后就能收到持续更新&#xff01; ⭐点赞⭐收藏⭐不迷路&#xff01;⭐ 1&#xff09;ThreadLocal造成内…

RPC通信原理(一)

RPC通信原理 RPC的概念 如果现在我有一个电商项目&#xff0c;用户要查询订单&#xff0c;自然而然是通过Service接口来调用订单的实现类。 我们把用户模块和订单模块都放在一起&#xff0c;打包成一个war包&#xff0c;然后再tomcat上运行&#xff0c;tomcat占有一个进程&am…

Learn OpenGL 13 模板测试

模板测试 当片段着色器处理完一个片段之后&#xff0c;模板测试(Stencil Test)会开始执行&#xff0c;和深度测试一样&#xff0c;它也可能会丢弃片段。接下来&#xff0c;被保留的片段会进入深度测试&#xff0c;它可能会丢弃更多的片段。模板测试是根据又一个缓冲来进行的&a…

python爬虫-AES.CBS加密案例(mmz批量爬取)

下载mmz本页数据 批量下载请看主页&#xff01;&#xff01;&#xff01; 代码&#xff1a; import requests from Crypto.Cipher import AES import base64cookies {PHPSESSID: 48nu182kdlsmgfo2g7hl6eufsa,Hm_lvt_6cd598ca665714ffcd8aca3aafc5e0dc: 1710568549,SECKEY_A…

MySql入门教程--MySQL数据库基础操作

꒰˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好&#xff0c;我是xiaoxie.希望你看完之后,有不足之处请多多谅解&#xff0c;让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN …

Typora设置文本颜色

目录 总共分为三种方法 1.使用markdown语法的内联公式 2.使用HTML语法 3.借助第三方软件&#xff08;不建议&#xff0c;操作没那么顺滑&#xff09; 总共分为三种方法 1.使用markdown语法的内联公式 <1>首先需要在设置中勾选Markdown扩展语法下的内联公式&#xff…

【计算机系统结构】重叠方式

&#x1f4dd;本文介绍 本文主要内容位计算机系统结构的重叠方式 &#x1f44b;作者简介&#xff1a;一个正在积极探索的本科生 &#x1f4f1;联系方式&#xff1a;943641266(QQ) &#x1f6aa;Github地址&#xff1a;https://github.com/sankexilianhua &#x1f511;Gitee地址…

Python JSON 序列化以及反序列化 文件读写

Python JSON 序列化以及反序列化 JSON (JavaScript Object Notation) 是一种轻量级的文本数据存储格式。JSON 数据通常存储在字符串中&#xff0c;即JSON字符串&#xff0c;其实就是一字符串&#xff0c;只是带有一定的格式&#xff0c;可以被解析。本文使用的 Python 版本为3…

深入浅出落地应用分析:AI数字人「微软小冰」

hi,各位,今天要聊的是AI小冰,机缘巧合,投递了这家公司的产品,正好最近在看数字人相关的,就详细剖析下这款产品! 前言 小冰,全称为北京红棉小冰科技有限公司,前身为微软(亚洲)互联网工程院人工智能小冰团队,是微软全球最大的人工智能独立产品研发团队。作为微软全…

Redis中的缓存设计

缓存穿透 缓存穿透是指查询一个根本不存在的数据&#xff0c;缓存层和存储层都不会命中&#xff0c;通常处于容错的考虑&#xff0c;如果从存储层查不到数据则不写入缓存层。缓存穿透将导致不存在的数据每次请求都要到存储层去查询&#xff0c;失去了缓存保护后端存储的意义。…

mysql5.7离线安装 windows

windows上离线安装mysql5.7 下载安装包 去官网下载对应版本的mysql官网 点击archives,接着选择自己要下载的版本&#xff0c;选择windows系统&#xff0c;并根据自己电脑的位数选择相应的版本【找到“此电脑”&#xff0c;鼠标右击&#xff0c;出来下拉框&#xff0c;选择“属性…

力扣爆刷第95天之hot100五连刷61-65

力扣爆刷第95天之hot100五连刷61-65 文章目录 力扣爆刷第95天之hot100五连刷61-65一、131. 分割回文串二、51. N 皇后三、35. 搜索插入位置四、74. 搜索二维矩阵五、34. 在排序数组中查找元素的第一个和最后一个位置 一、131. 分割回文串 题目链接&#xff1a;https://leetcod…

工业制造企业能耗是怎么一回事

1.1 环境信息感知设备 当前&#xff0c;工业制造企业能耗监控使用的传感装置包含电量传感器、测温传感器、ESR型燃气传感器、温度隔离变送器以及水位计&#xff0c;用于多源环境信息的感知、采集与处理分析[1]。而射频识别&#xff08;RadioFrequencyIDentification&#xff…

【django framework】ModelSerializer+GenericAPIView接口数据流

GenericAPIView数据从序列化到最终返回响应的数据流 // 以ModelSerializergenerics.CreateAPIView为例 程序终归是为了处理数据&#xff0c;怎么处理&#xff0c;以怎样的顺序和方法去处理&#xff0c;就涉及到了具体的业务流程。当我们是用了一个牛掰的框架&#xff0c;发现原…

考察c语言关键字

C语言——关键字 1.问题&#xff1a;简述goto语句的作用 答&#xff1a;无条件跳转 具体来说&#xff0c;其作用在于允许程序在执行时无条件地跳转到指定的标签位置&#xff0c;并从该标签位置继续执行。通过goto语句&#xff0c;可以实现程序流程的无条件转移&#xff0c;使得…

使用PWM实现呼吸灯功能

CC表示的意思位捕获比较&#xff0c;CCR表示的是捕获比较寄存器 占空比等效于PWM模拟出来的电压的多少&#xff0c;占空比越大等效出的模拟电压越趋近于高电平&#xff0c;占空比越小等效出来的模拟电压越趋近于低电平&#xff0c;分辨率表示的是占空比变化的精细程度&#xf…