返回顶部
首页 > 资讯 > 精选 >Java中那些分不清的小细节有哪些
  • 648
分享到

Java中那些分不清的小细节有哪些

2023-06-15 17:06:55 648人浏览 独家记忆
摘要

本篇内容主要讲解“Java中那些分不清的小细节有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java中那些分不清的小细节有哪些”吧! 前言最近我们通过sonar静态代码检测,同时

本篇内容主要讲解“Java中那些分不清的小细节有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java中那些分不清的小细节有哪些”吧!

 前言

最近我们通过sonar静态代码检测,同时配合人工代码review,发现了项目中很多代码问题。除了常规的bug和安全漏洞之外,还有几处方法用法错误,引起了我极大的兴趣。我为什么会对这几个方法这么感兴趣呢?因为它们极具迷惑性,可能会让我们傻傻分不清楚。

1.  replace会替换所有字符?

很多时候我们在使用字符串时,想把字符串比如:ATYSDFA*Y中的字符A替换成字符B,第一个想到的可能是使用replace方法。

如果想把所有的A都替换成B,很显然可以用replaceAll方法,因为非常直观,光从方法名就能猜出它的用途。

那么问题来了:replace方法会替换所有匹配字符吗?

jdk的官方给出了答案。

Java中那些分不清的小细节有哪些

该方法会替换每一个匹配的字符串。

既然replace和replaceAll都能替换所有匹配字符,那么他们有啥区别呢?

replace有两个重载的方法。

其中一个方法的参数:char oldChar 和 char newChar,支持字符的替换。

source.replace('A', 'B')

另一个方法的参数是:CharSequence target 和 CharSequence replacement,支持字符串的替换。

source.replace("A", "B")

replaceAll方法的参数是:String regex 和 String replacement,基于正则表达式的替换。普通字符串替换:

source.replaceAll("A", "B")

正则表达替换(将*替换成C):

source.replaceAll("\\*", "C")

顺便说一下,将*替换成C使用replace方法也可以实现:

source.replace("*", "C")

无需对特殊字符进行转义。

不过,千万注意,切勿使用如下写法:

source.replace("\\*", "C")

这种写法会导致字符串无法替换。

还有个小问题,如果我只想替换第一个匹配的字符串该怎么办?

这时可以使用replaceFirst方法:

source.replaceFirst("A", "B")

2. Integer不能用==判断相等?

不知道你在项目中有没有见过,有些同事对Integer类型的两个参数使用==比较是否相等?

反正我见过的,那么这种用法对吗?

我的回答是看具体场景,不能说一定对,或不对。

有些状态字段,比如:orderStatus有:-1(未下单),0(已下单),1(已支付),2(已完成),3(取消),5种状态。

这时如果用==判断是否相等:

Integer orderStatus1 = new Integer(1);  Integer orderStatus2 = new Integer(1);  System.out.println(orderStatus1 == orderStatus2);

返回结果会是true吗?

答案:是false。

有些同学可能会反驳,Integer中不是有范围是:-128-127的缓存吗?

为什么是false?

先看看Integer的构造方法:

Java中那些分不清的小细节有哪些

它其实并没有用到缓存。

那么缓存是在哪里用的?

答案在valueOf方法中:

Java中那些分不清的小细节有哪些

如果上面的判断改成这样:

String orderStatus1 = new String("1"); String orderStatus2 = new String("1"); System.out.println(Integer.valueOf(orderStatus1) == Integer.valueOf(orderStatus2));

返回结果会是true吗?

答案:还真是true。

我们要养成良好编码习惯,尽量少用==判断两个Integer类型数据是否相等,只有在上述非常特殊的场景下才相等。

而应该改成使用equals方法判断:

Integer orderStatus1 = new Integer(1); Integer orderStatus2 = new Integer(1); System.out.println(orderStatus1.equals(orderStatus2));

3.  使用BigDecimal就不丢失精度?

通常我们会把一些小数类型的字段(比如:金额),定义成BigDecimal,而不是Double,避免丢失精度问题。

使用Double时可能会有这种场景:

double amount1 = 0.02; double amount2 = 0.03; System.out.println(amount2 - amount1);

正常情况下预计amount2 - amount1应该等于0.01

但是执行结果,却为:

0.009999999999999998

实际结果小于预计结果。

Double类型的两个参数相减会转换成二进制,因为Double有效位数为16位这就会出现存储小数位数不够的情况,这种情况下就会出现误差。

常识告诉我们使用BigDecimal能避免丢失精度。

但是使用BigDecimal能避免丢失精度吗?

答案是否定的。

为什么?

BigDecimal amount1 = new BigDecimal(0.02); BigDecimal amount2 = new BigDecimal(0.03); System.out.println(amount2.subtract(amount1));

这个例子中定义了两个BigDecimal类型参数,使用构造函数初始化数据,然后打印两个参数相减后的值。

结果:

0.0099999999999999984734433411404097569175064563751220703125

不科学呀,为啥还是丢失精度了?

jdk中BigDecimal的构造方法上有这样一段描述:

Java中那些分不清的小细节有哪些

大致的意思是此构造函数的结果可能不可预测,可能会出现创建时为0.1,但实际是0.1000000000000000055511151231257827021181583404541015625的情况。

由此可见,使用BigDecimal构造函数初始化对象,也会丢失精度。

那么,如何才能不丢失精度呢?

BigDecimal amount1 = new BigDecimal(Double.toString(0.02)); BigDecimal amount2 = new BigDecimal(Double.toString(0.03)); System.out.println(amount2.subtract(amount1));

使用Double.toString方法对double类型的小数进行转换,这样能保证精度不丢失。

其实,还有更好的办法:

BigDecimal amount1 = BigDecimal.valueOf(0.02); BigDecimal amount2 = BigDecimal.valueOf(0.03); System.out.println(amount2.subtract(amount1));

使用BigDecimal.valueOf方法初始化BigDecimal类型参数,也能保证精度不丢失。在新版的阿里巴巴开发手册中,也推荐使用这种方式创建BigDecimal参数。

 字符串拼接不能用String?

String类型的字符串被称为不可变序列,也就是说该对象的数据被定义好后就不能修改了,如果要修改则需要创建新对象。

String a = "123"; String b = "456"; String c = a + b; System.out.println(c);

在大量字符串拼接的场景中,如果对象被定义成String类型,会产生很多无用的中间对象,浪费内存空间,效率低。

这时,我们可以用更高效的可变字符序列:StringBuilder和StringBuffer,来定义对象。

那么,StringBuilder和StringBuffer有啥区别?

StringBuffer对各主要方法加了synchronized关键字,而StringBuilder没有。所以,StringBuffer是线程安全的,而StringBuilder不是。

其实,我们很少会出现需要在多线程下拼接字符串的场景,所以StringBuffer实际上用得非常少。一般情况下,拼接字符串时我们推荐使用StringBuilder,通过它的append方法追加字符串,它只会产生一个对象,而且没有加,效率较高。

String a = "123"; String b = "456"; StringBuilder c = new StringBuilder(); c.append(a).append(b); System.out.println(c);

接下来,关键问题来了:字符串拼接时使用String类型的对象,效率一定比StringBuilder类型的对象低?

答案是否定的。

为什么?

使用javap -c StringTest命令反编译:

Java中那些分不清的小细节有哪些

从图中能看出定义了两个String类型的参数,又定义了一个StringBuilder类的参数,然后两次使用append方法追加字符串。

如果代码是这样的:

String a = "123"; String b = "789"; String c = a + b; System.out.println(c);

使用javap -c StringTest命令反编译的结果会怎样呢?

Java中那些分不清的小细节有哪些

我们会惊讶的发现,同样定义了两个String类型的参数,又定义了一个StringBuilder类的参数,然后两次使用append方法追加字符串。跟上面的结果是一样的。

其实从jdk5开始,java就对String类型的字符串的+操作做了优化,该操作编译成字节码文件后会被优化为StringBuilder的append操作。

5. isEmpty和isBlank的区别

我们在对字符串进行操作的时候,需要经常判断该字符串是否为空。如果没有借助任何工具,我们一般是这样判断的:

if (null != source && !"".equals(source)) {     System.out.println("not empty"); }

但是如果每次都这样判断,会有些麻烦,所以很多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方法判断:

StringUtils.isNotEmpty(null)      = true  StringUtils.isNotEmpty("")        = true  StringUtils.isNotEmpty(" ")       = false  StringUtils.isNotEmpty("bob")     = false  StringUtils.isNotEmpty("  bob  ") = false

使用isBlank方法判断:

StringUtils.isBlank(null)      = true StringUtils.isBlank("")        = true StringUtils.isBlank(" ")       = true StringUtils.isBlank("bob")     = false StringUtils.isBlank("  bob  ") = false

两个方法关键的区别在于这种" "空字符串的情况,isNotEmpty返回false,而isBlank返回true。

6. mapper查询结果要判空?

有次代码review的时候,当时有个同事说这里的判空可以去掉,让我记忆犹新:

List<User> list = userMapper.query(search); if(CollectionUtils.isNotEmpty(list)) {     List<Long> idList = list.stream().map(User::getId).collect(Collectors.toList()); }

因为按常理,一般调用方法查询出来的集合,可能为null,需要判空的。但是,这里比较特殊,我查了一下mybatis源码,这个判空的代码还真的可以去掉。

怎么回事呢?

mybatis的查询方法最终都会调到DefaultResultSetHandler类的handleResultSets方法:

Java中那些分不清的小细节有哪些

Java中那些分不清的小细节有哪些

该方法会返回一个multipleResultsList集合对象,在方法刚开始就new出来了,肯定是不会为空。

所以,如果你在项目的代码中看到有人直接使用查询出的结果,不判空也不要惊讶:

List<User> list = userMapper.query(search); List<Long> idList = list.stream().map(User::getId).collect(Collectors.toList());

因为mapper底层已经处理过的,它不会出现空指针异常。

7. indexOf方法的正确用法

有次在review别人代码的时候,看到有个地方indexOf使用了这种写法,让我印象比较深刻:

String source = "#ATYSDFA*Y"; if(source.indexOf("#") > 0) {     System.out.println("do something"); }

你们说这段代码会打印出do something吗?

答案是否定的。

为什么呢?

jdk官方说了不存在的情况会返回-1

Java中那些分不清的小细节有哪些

indexOf方法返回的是指定元素在字符串中的位置,从0开始。而上面的例子#在字符串的第一个位置,所以调用indexOf方法后的值其实是0。所以,条件是false,不会打印do  something。

如果想通过indexOf判断某个元素是否存在时,要用:

if(source.indexOf("#") > -1) {     System.out.println("do something"); }

其实,还有更优雅的contains方法:

if(source.contains("#")) {    System.out.println("do something"); }

到此,相信大家对“Java中那些分不清的小细节有哪些”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

--结束END--

本文标题: Java中那些分不清的小细节有哪些

本文链接: https://lsjlt.com/news/281088.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Java中那些分不清的小细节有哪些
    本篇内容主要讲解“Java中那些分不清的小细节有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java中那些分不清的小细节有哪些”吧! 前言最近我们通过sonar静态代码检测,同时...
    99+
    2023-06-15
  • 使用Python小细节有哪些
    本篇内容介绍了“使用Python小细节有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!01、只要一行代码的列表生成器假如每次你想要生成个...
    99+
    2023-06-17
  • final关键字的小细节有哪些
    本篇内容主要讲解“final关键字的小细节有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“final关键字的小细节有哪些”吧!正文final关键字是一个常用的关键字,可以修饰变量、方法、类,...
    99+
    2023-06-15
  • Java性能优化的细节有哪些
    这篇文章主要介绍“Java性能优化的细节有哪些”,在日常操作中,相信很多人在Java性能优化的细节有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java性能优化的细节有哪些”的疑惑有所帮助!接下来,请跟...
    99+
    2023-06-16
  • Java的性能优化细节有哪些
    今天小编给大家分享一下Java的性能优化细节有哪些的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。1. 尽量在合适的场合使用单...
    99+
    2023-06-04
  • 提升Java代码运行效率的小细节有哪些
    这篇文章主要介绍“提升Java代码运行效率的小细节有哪些”,在日常操作中,相信很多人在提升Java代码运行效率的小细节有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”提升Java代码运行效率的小细节有哪些...
    99+
    2023-06-16
  • Java代码优化细节有哪些
    本篇内容介绍了“Java代码优化细节有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1、尽量指定类、方法的final修饰符带有final...
    99+
    2023-06-16
  • C#中数组的细节有哪些
    这篇文章主要讲解了“C#中数组的细节有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C#中数组的细节有哪些”吧!C# 数组细节在 C# 中,数组是非常重要的,且需要了解更多的细节。下面列...
    99+
    2023-06-17
  • CSS的细节都有哪些
    这期内容当中小编将会给大家带来有关CSS的细节都有哪些,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。如果说这些特性是CSS华丽的一面,那我们来看看它朴实的一面:很不起眼的...
    99+
    2024-04-02
  • Java同步框架API:有哪些你不知道的细节?
    Java中的同步是多线程编程的重要组成部分,Java的同步框架API提供了多种方式来实现线程同步。但是,在使用同步框架API时,有很多细节需要注意。本文将介绍Java同步框架API中的一些你可能不知道的细节,并通过演示代码来加深理解。 ...
    99+
    2023-09-05
    同步 框架 api
  • Java常见的误区与细节有哪些
    这篇文章主要讲解了“Java常见的误区与细节有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java常见的误区与细节有哪些”吧!在Java中,没有goto语句。因为大量使用goto语句会...
    99+
    2023-06-17
  • Java代码块的使用细节有哪些
    这篇文章主要讲解了“Java代码块的使用细节有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java代码块的使用细节有哪些”吧!1.基本介绍代码块又称为初始化块,属于类中的成员(类的一部...
    99+
    2023-06-30
  • 网页前端开发小细节有哪些
    这期内容当中小编将会给大家带来有关网页前端开发小细节有哪些,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。1 select标签必须闭合<select></select> 2 左右布局...
    99+
    2023-06-08
  • Python的py文件中有哪些细节
    本篇内容介绍了“Python的py文件中有哪些细节”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!模块是一种以.py为后缀的文件,我们可以在....
    99+
    2023-06-02
  • SEO中容易被忽视的细节分析有哪些
    这篇文章主要为大家展示了“SEO中容易被忽视的细节分析有哪些”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“SEO中容易被忽视的细节分析有哪些”这篇文章吧。第一,标签的应用,建设比较早的站容易出现...
    99+
    2023-06-13
  • WEB测试的细节有哪些
    这篇文章主要介绍“WEB测试的细节有哪些”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“WEB测试的细节有哪些”文章能帮助大家解决问题。什么是Web测试?“Web 测试”也称为声明性Web 测试,它由...
    99+
    2023-06-04
  • 高效率引流小程序的细节有哪些
    这篇文章主要讲解了“高效率引流小程序的细节有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“高效率引流小程序的细节有哪些”吧!1. 学会运用seo思维虽然说seo优化最早也是运用到电商以及...
    99+
    2023-06-27
  • 细数java for循环中的那些坑
    目录1、循环语句的几种语法2、循环中需要注意的点2.1 循环如果满足了查找的需求 break 直接跳出,不要浪费性能2.2 循环集合的时候能用for each 的尽量用for eac...
    99+
    2024-04-02
  • Android组件通信中有哪些不为人知的细节
    一、线程安全 在组件通信过程中,涉及到多线程操作时需要考虑线程安全。例如,如果多个线程同时修改共享数据,可能会引发竞态条件(RaceCondition)和数据不一致的问题。可以使用同步机制(如锁、信号量)或线程安全的数据结构来确保数据的正确...
    99+
    2023-10-29
    中有 不为人知 组件
  • JavaScript中分号的一些细节
    前言 JavaScript 中的分号是可选的,加不加分号主要是个代码风格问题。一种风格是使用分号明确结束语句,即便这些分号不是必需的;另一种风格是尽可能的不加分号,只在必要的情况才...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作