这7个坑,99%的Java程序员会踩!
最近我们通过sonar静态代码检测,同时配合人工代码review,发现了项目中很多代码问题。除了常规的bug和安全漏洞之外,还有几处方法用法错误,引起了我极大的兴趣。我为什么会对这几个方法这么感兴趣呢?因为它们极具迷惑性,可能会让我们傻傻分不清楚。
很多时候我们在使用字符串时,想把字符串比如:ATYSDFA*Y中的字符A替换成字符B,第一个想到的可能是使用replace方法。
如果想把所有的A都替换成B,很显然可以用replaceAll方法,因为非常直观,光从方法名就能猜出它的用途。
那么问题来了:replace方法会替换所有匹配字符吗?
jdk的官方给出了答案。
该方法会替换每一个匹配的字符串。
既然replace和replaceAll都能替换所有匹配字符,那么他们有啥区别呢?
- replace有两个重载的方法。
其中一个方法的参数:char oldChar 和 char newChar,支持字符的替换。
另一个方法的参数是:CharSequence target 和 CharSequence replacement,支持字符串的替换。
2. replaceAll方法的参数是:String regex 和 String replacement,基于正则表达式的替换。普通字符串替换:
正则表达替换(将*替换成C):
顺便说一下,将*替换成C使用replace方法也可以实现:
无需对特殊字符进行转义。
不过,千万注意,切勿使用如下写法:
这种写法会导致字符串无法替换。
还有个小问题,如果我只想替换第一个匹配的字符串该怎么办?
这时可以使用replaceFirst方法:
不知道你在项目中有没有见过,有些同事对Integer类型的两个参数使用==比较是否相等?
反正我见过的,那么这种用法对吗?
我的回答是看具体场景,不能说一定对,或不对。
有些状态字段,比如:orderStatus有:-1(未下单),0(已下单),1(已支付),2(已完成),3(取消),5种状态。
这时如果用==判断是否相等:
返回结果会是true吗?
答案:是false。
有些同学可能会反驳,Integer中不是有范围是:-128-127的缓存吗?
为什么是false?
先看看Integer的构造方法:
它其实并没有用到缓存。
那么缓存是在哪里用的?
答案在valueOf方法中:
如果上面的判断改成这样:
返回结果会是true吗?
答案:还真是true。
我们要养成良好编码习惯,尽量少用==判断两个Integer类型数据是否相等,只有在上述非常特殊的场景下才相等。
而应该改成使用equals方法判断:
通常我们会把一些小数类型的字段(比如:金额),定义成BigDecimal,而不是Double,避免丢失精度问题。
使用Double时可能会有这种场景:
正常情况下预计amount2 – amount1应该等于0.01
但是执行结果,却为:
实际结果小于预计结果。
Double类型的两个参数相减会转换成二进制,因为Double有效位数为16位这就会出现存储小数位数不够的情况,这种情况下就会出现误差。
常识告诉我们使用BigDecimal能避免丢失精度。
但是使用BigDecimal能避免丢失精度吗?
答案是否定的。
为什么?
这个例子中定义了两个BigDecimal类型参数,使用构造函数初始化数据,然后打印两个参数相减后的值。
结果:
不科学呀,为啥还是丢失精度了?
jdk中BigDecimal的构造方法上有这样一段描述:
大致的意思是此构造函数的结果可能不可预测,可能会出现创建时为0.1,但实际是0.1000000000000000055511151231257827021181583404541015625的情况。
由此可见,使用BigDecimal构造函数初始化对象,也会丢失精度。
那么,如何才能不丢失精度呢?
使用Double.toString方法对double类型的小数进行转换,这样能保证精度不丢失。
其实,还有更好的办法:
使用BigDecimal.valueOf方法初始化BigDecimal类型参数,也能保证精度不丢失。在新版的阿里巴巴开发手册中,也推荐使用这种方式创建BigDecimal参数。
String类型的字符串被称为不可变序列,也就是说该对象的数据被定义好后就不能修改了,如果要修改则需要创建新对象。
在大量字符串拼接的场景中,如果对象被定义成String类型,会产生很多无用的中间对象,浪费内存空间,效率低。
这时,我们可以用更高效的可变字符序列:StringBuilder和StringBuffer,来定义对象。
那么,StringBuilder和StringBuffer有啥区别?
StringBuffer对各主要方法加了synchronized关键字,而StringBuilder没有。所以,StringBuffer是线程安全的,而StringBuilder不是。
其实,我们很少会出现需要在多线程下拼接字符串的场景,所以StringBuffer实际上用得非常少。一般情况下,拼接字符串时我们推荐使用StringBuilder,通过它的append方法追加字符串,它只会产生一个对象,而且没有加锁,效率较高。
接下来,关键问题来了:字符串拼接时使用String类型的对象,效率一定比StringBuilder类型的对象低?
答案是否定的。
为什么?
使用javap -c StringTest命令反编译:
从图中能看出定义了两个String类型的参数,又定义了一个StringBuilder类的参数,然后两次使用append方法追加字符串。
如果代码是这样的:
使用javap -c StringTest命令反编译的结果会怎样呢?
我们会惊讶的发现,同样定义了两个String类型的参数,又定义了一个StringBuilder类的参数,然后两次使用append方法追加字符串。跟上面的结果是一样的。
其实从jdk5开始,java就对String类型的字符串的+操作做了优化,该操作编译成字节码文件后会被优化为StringBuilder的append操作。
最近就业形势比较困难,为了感谢各位小伙伴对苏三一直以来的支持,我特地创建了一些工作内推群, 看看能不能帮助到大家。
你可以在群里发布招聘信息,也可以内推工作,也可以在群里投递简历找工作,也可以在群里交流面试或者工作的话题。
我们在对字符串进行操作的时候,需要经常判断该字符串是否为空。如果没有借助任何工具,我们一般是这样判断的:
但是如果每次都这样判断,会有些麻烦,所以很多jar包都对字符串判空做了封装。目前市面上主流的工具有:
- spring中的StringUtils
- jdbc中的StringUtils
- apache common3中的StringUtils
不过spring中的StringUtils类只有isEmpty方法,没有isNotEmpty方法。
jdbc中的StringUtils类只有isNullOrEmpty方法,也没有isNotNullOrEmpty方法。
所以在这里强烈推荐一下apache common3中的StringUtils类,它里面包含了很多实用的判空方法:isEmpty、isBlank、isNotEmpty、isNotBlank等,还有其他字符串处理方法。
问题来了,isEmpty和isBlank有啥区别?
使用isEmpty方法判断:
使用isBlank方法判断:
两个方法关键的区别在于这种\” \”空字符串的情况,isNotEmpty返回false,而isBlank返回true。
有次代码review的时候,当时有个同事说这里的判空可以去掉,让我记忆犹新:
因为按常理,一般调用方法查询出来的集合,可能为null,需要判空的。但是,这里比较特殊,我查了一下mybatis的源码,这个判空的代码还真的可以去掉。
怎么回事呢?
mybatis的查询方法最终都会调到DefaultResultSetHandler类的handleResultSets方法:
该方法会返回一个multipleResultsList集合对象,在方法刚开始就new出来了,肯定是不会为空。
所以,如果你在项目的代码中看到有人直接使用查询出的结果,不判空也不要惊讶:
因为mapper底层已经处理过的,它不会出现空指针异常。
有次在review别人代码的时候,看到有个地方indexOf使用了这种写法,让我印象比较深刻:
你们说这段代码会打印出do something吗?
答案是否定的。
为什么呢?
jdk官方说了不存在的情况会返回-1
indexOf方法返回的是指定元素在字符串中的位置,从0开始。而上面的例子#在字符串的第一个位置,所以调用indexOf方法后的值其实是0。所以,条件是false,不会打印do something。
如果想通过indexOf判断某个元素是否存在时,要用:
其实,还有更优雅的contains方法:
经典书单 ,最受程序员推荐的Java书籍,值得阅读
点击上方☝,轻松关注!及时获取有趣有料的技术文章
书籍绝对是一种很好的学习方式,将它们和文章、教程和视频结合使用,你一定会有一个事半功倍的效果
Java是最重要的编程语言之一,关于Java编程的书籍并不少见,不仅有关于各种Java概念概述,还有更深入的具体到各个Java主题内容的书籍。
近日,hackr.io编程社区,评选出11本优秀的Java书籍来帮助读者学习Java。
1、《Java核心技术·卷 I》
这一本Java参考书,它详细解释了Java核心的各种特性,包括异常处理、接口和lambda表达式。这本书的主要亮点在于内容详实,语言简洁,示例讲解详细
Java核心技术·卷 I的最新版本(第11版本)全面更新,涵盖了Java SE 9、10和11。这本书帮助Java程序员开发编写高度可读和可维护代码的能力,被认为是面向高级程序员的经典教程和参考书。
2、《Effective Java》
本书也是每个Java程序员必读的一本书,《Effective java》可以作为其他Java书籍的一个很好的补充,这本书提供了90个条目,每个条目中的规则都反映了最有经验的优秀程序员在实践中常用的一些有益的做法。
《Effective Java》将所有提到的最佳实践分为11章,例如并发性、泛型和方法,从而使读者更容易掌握所有的这些内容。
本书是Joshua Bloch编写的,他也是许多关键Java类和API的作者。包括Java.lang和Java Collection 框架。该书的最新版本内容主要围绕Java 7、8和9构建的。
3、《Java: A Beginner’s Guide》
不要被这本书的标题误导了,事实上,它是Java最全面的书籍之一。任何编程水平的人都能从这本指南中学到东西,里面涵盖了与 Core Java相关的所有概念本书的最新版经过全面修订,还包括Java 11 SE。除此之外,为了让读者在阅读后能有个自我检测,本书的每章末尾都会提供几个练习题。
4、《Java: The Complete Reference》
这是一本超过1000页的大小适中的Java参考书。它包含读者需要掌握的Java的每个方面。除了检查Java API库的重要部分之外,本书还包括基本的编程原则,Java语言语法和关键字。本书还有许多恰到好处的示例帮助你更好地学习Java
5、《Head First Java》
本书最重要的卖点在于它的简单,以及把Java编程概念形象具体化,书中几乎涵盖所有OOPS概念,并以非常有趣的方式解释它们。
尽管一些读者认为这是一本过时的书,因为它只涵盖Java 5.0以下的内容,但是Head First Java仍然可以在许多Java老手的书架上找到。因此,把它当成是Java开发人员的必备书籍也不为过。
Head First Java所涵盖的一些值得注意的主题包括常见的OO错误、线程、网络与分布式程序等项目。此外,这本书还涵盖了42个难解的试题,来帮助你更好地理解Java。
6、《Java并发编程实战》
本书深入浅出地介绍了Java线程和并发,是最佳Java编程书籍之一。不要被本书对Java 5.0的介绍所误解了,因为它对于任何Java开发人员来说仍然是相关且必不可少的。
本书唯一问题是一些部分最初可能很难理解。但是,你也应该知道并发和多线程本身就是很难的主题。但是当你读完本书的时候,你会发现一切都是值得的。
7、《测试驱动开发的艺术》
这是一本学习如何编写优秀自动化测试程序的好书。对于那些优先考虑代码质量以及编写单元、集成和自动化测试技巧的Java开发人员来说,这是一本必备的书。
书中提供了大量实例来解释TDD。此外,本书还介绍了验收测试驱动开发(ATDD)、Fit框架和测试Java EE组件(jsp、servlet和Spring控制器)。
8、《深入浅出面向对象分析与设计》
Head First是用Java编程语言编写的最好的书籍系列之一,它和《Head First Java》、《深入浅出设计模式》被并成为Head First Java三部曲。
本书详细介绍了面向对象编程和设计中所使用的不同技术,诸如接口编码以及如何封装更改等。《深入浅出面向对象分析与设计》是一本能够帮你写出更好的Java代码的好书。
9、《Java性能权威指南》
垃圾收集,JVM和性能调优是Java编程语言最大的有点。本书用一个简单而有效的方式涵盖了所有这三大Java主题,帮助你最大化Java线程和同步性能特性,改进Java驱动的数据库应用程序性能,解决Java EE和Java SE API中的性能问题等等。
10、《Head First 设计模式》
想要编写出完美的Java应用程序,掌握OOP和设计模式是必不可少的,书中每章都介绍了几个设计模式,提供了许多关于Java常见问题的解决方案,诸如为什么组合比继承好,本书的最新版本针对Java 8进行了更新,与其他书籍不同的是本书旨在用一些丰富的场景让原本枯燥的学习变得有趣。
11、《代码整洁之道》
《代码整洁之道》也是一本经典的Java编程书籍,本书作者给出了一系列行之有效的整洁代码操作实践。这些实践在本书中体现为一条条规则(或称“启示”),并辅以来自现实项目的正、反两面的范例。只要遵循这些规则,就能编写出干净的代码,从而有效提升代码质量。
其他
- 《Core Java 》豆瓣评分 8.7
- 《Extreme Java – Concurrency Performance for Java 8》
- 《Java How to Program》豆瓣评分 8.0
- 《Java 8实战 》豆瓣评分 9.2
- 《Java in a Nutshell》豆瓣评分 9.3
- 《爱上Python》豆瓣评分 7.2
- 《Java编程规范》豆瓣评分 8.5
- 《像计算机科学家一样思考Python (第2版)》 豆瓣评分 8.6
- 《21天学通Java》
- 《 Spring实战(第4版)》豆瓣评分 8.3
私信回复 书籍,获取电子版书籍!
Java程序员需要具备哪些专业技能?
我们都知道,Java程序员是一个技术岗位,从技术上和业务上都需要不断地提升自我。
经常有小伙伴疑惑:一个合格的Java程序员需要会哪些东西?今天,就来和大家好好聊一聊,超多干货,快快收藏哦!
Java程序员需要掌握哪些东西
一、扎实的理论基础
理论知识不扎实遇到问题请教别人,虽然也能把问题解决,但需要花比别人多的多的时间才能把问题解决,且大部分情况下还不能很完美的解决。如何才能使自己有扎实的理论基础呢?建议多看看别人的代码多进行总结。
二、要有较强的自学能力
许多企业非常看重个人的自学能力。IT行业技术更新太快,只有通过不断地学习才跟得上社会的进步个人的自学能力对于企业的发展非常的重要。
三、编码规范
IT行业离职率较高,让新来的员工看懂以往的代码也是企业非常关注的。有良好的编码习惯注重代码的注释都是一个程序员必不可少的能力。
四、注重团队精神和较好的沟通能力
对于一个项目来说独立开发的项目几乎不存在,都是由多人协作开发的特别是产品化的项目,具备较好的团队精神和较好的沟通能力非常重要。
五、较好的文档能力
Java程序员不仅要掌握一定的技术能力,还需要具有一定的文档编写能力。良好的文档能力能帮助我们更好地进行开发。一般来说,软件项目的发展需要经过需求调研,概要设计,详细设计等一系列的步骤,这些都是编码前的准备工作,一般项目特别是大项目会把大部分时间都花在文档整理上。
六、Java程序员专业技能:
1、熟练的使用Java语言进行面向对象程序设计,有良好的编程习惯,熟悉常用的JavaAPI,包括集合框架、多线程(并发编程)、I/O(NIO)、Socket、JDBC、XML、反射等。
2、熟悉基于JSP和Servlet的JavaWeb开发,对Servlet和JSP的工作原理和生命周期有深入了解,熟练的使用JSTL和EL编写无脚本动态页面,有使用监听器、过滤器等Web组件以及MVC架构模式进行JavaWeb项目开发的经验。
3、对Spring的IoC容器和AOP原理有深入了解,熟练的运用Spring框架管理各种Web组件及其依赖关系,熟练的使用Spring进行事务、日志、安全性等的管理,有使用SpringMVC作为表示层技术以及使用Spring提供的持久化支持进行Web项目开发的经验,熟悉Spring对其他框架的整合。
4、熟练的使用Hibernate、MyBatis等ORM框架,熟悉Hibernate和MyBatis的核心API,对Hibernate的关联映射、继承映射、组件映射、缓存机制、事务管理以及性能调优等有深入的理解。
5、熟练的使用HTML、CSS和JavaScript进行Web前端开发,熟悉jQuery和Bootstrap,对Ajax技术在Web项目中的应用有深入理解,有使用前端MVC框架(AngularJS)和JavaScript模板引擎(HandleBars)进行项目开发的经验。
6、熟悉常用的关系型数据库产品(MySQL、Oracle),熟练的使用SQL和PL/SQL进行数据库编程。
7、熟悉面向对象的设计原则,对GoF设计模式和企业应用架构模式有深入的了解和实际开发的相关经验,熟练的使用UML进行面向对象的分析和设计,有TDD(测试驱动开发)和DDD(领域驱动设计)的经验。
8、熟悉Apache、NginX、Tomcat、WildFly、Weblogic等Web服务器和应用服务器的使用,熟悉多种服务器整合、集群和负载均衡的配置。
9、熟练的使用产品原型工具Axure,熟练的使用设计建模工具PowerDesigner和EnterpriseArchitect,熟练的使用Java开发环境Eclipse和IntelliJ,熟练的使用前端开发环境WebStorm,熟练的使用软件版本控制工具SVN和Git,熟练的使用项目构建和管理工具Maven和Gradle。
Java程序员如果不学习很容易被淘汰,Java 程序员如果想安身立命必须不断跟进新的技术学习新的技能。善于学习对于Java程序员而言都是前进所必需的动力。希望大家一直在路上,加油!
本文作者及来源:Renderbus瑞云渲染农场https://www.renderbus.com
文章为作者独立观点不代本网立场,未经允许不得转载。