Java# Java易错知识点:replaceindexOf数值包装类判断相等数值精度问题字符串拼接字符串判空mapper查询结果处理

Posted LRcoding

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java# Java易错知识点:replaceindexOf数值包装类判断相等数值精度问题字符串拼接字符串判空mapper查询结果处理相关的知识,希望对你有一定的参考价值。

1. replace 与 replaceAll

场景:想要将 ABCABB 的 A 替换为 B

一看到这个场景,我们首先想到的就是用 replace方法(会替换几个 A 呢?)

如果将所有的 A 都替换为 B,可以使用 replaceAll 方法(这个没有争议)

问题replace方法会替换几个 A 呢?

通过阅读源码,可以得知,replace方法会替换每一个匹配的字符串,那么它与 replaceAll 的区别在哪呢?

  • replace,拥有两个重载的方法

    • 字符 的替换

      public String replace(char oldChar, char newChar) 
      
      "ABCABB".replace('A', 'B');
      
    • 字符串 的替换

      public String replace(CharSequence target, CharSequence replacement) 
      
      "ABCABB".replace("A", "B");  // 注意,用的是字符串
      
  • replaceAll

    • 基于正则表达式 的替换(也可以用于普通字符串的替换)

      public String replaceAll(String regex, String replacement) 
      
      // 普通字符串的替换
      "ABCABB".replaceAll("A", "B");
      
      // 正则表达式替换
      "AB$C$ABB".replaceAll("\\\\$", "B");
      // 如果想直接写 $,可以用 replace
      "AB$C$ABB".replace("$", "B"); 
      

问题:如果只想替换第一个匹配的字符串呢? ----- replaceFirst()

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

2. indexOf 的使用

场景:如果字符串中包含 $ 字符,那么就打印出一句话

这个场景,我们可以使用两种方式进行解决,既然题目为 indexOf 的使用,那么先看如何用 indexOf 实现

if ("123dj$879ABC".indexOf("$") > -1) 
    System.out.println("Hello world!")

一定要注意:if 语句中的条件,是 > -1,不能写为 > 0 (如果想要查找的 $字符在第一位,那么就会返回 0,则虽然包含 $,但是条件不成立)

问题:更简单的方法?(底层还是 indexOf) ------ contains()

if ("123dj$879ABC".contains("$")) 
    System.out.println("Hello world!")

3. 数值包装类的相等问题

场景:判断两个 Integer 类型的数值是否相等

看到这个场景,如果代码中我们直接用 == 进行判断,结果是 true 还是 false呢

  • false 的结果 ----- new Integer(1);

    Integer num1 = new Integer(1);
    Integer num2 = new Integer(1);
    System.out.println(num1 == num2); 
    
    // 由于两个数是直接 new出来的,地址肯定不相同,所以直接使用 == ,返回 false
    
  • true 的结果 ----- Integer.valueOf(1);

    Integer num1 = Integer.valueOf(1);
    Integer num2 = Integer.valueOf(1);
    System.out.println(num1 == num2);
    
    // 通过阅读源码可以得知,使用 valueOf 方法时,数值在 -128 到 127范围内的值,是有缓存的,不会新 new一个
    

问题:涉及到数值类型的包装类如何进行相等判断

解决:应使用 equals 方法进行判断

Integer num1 = new Integer(1);
Integer num2 = new Integer(1);
System.out.println(num1.equals(num2));   // 结果为  true

4. 数值精度问题

场景:交易金额进行计算

涉及到金额的计算,我们一般需要将字段类型定义为 BigDecimal,避免定义为 Double 类型时,精度丢失的问题

例如如下操作:

double num1 = 0.03;
double num2 = 0.02;
System.out.println(num1 - num2);  // 使用 0.02 - 0.01 却不会损失精度

得到的结果是: 0.009999999999999998,与预计的 0.01 不相符

----> Double 类型的两个参数相减,会先将数字转为 二进制 再进行运算,而 Double的有效位数为 16位,所以可能会出现存储小数位数不够的情况,进而导致了误差的出现

问题:但是使用 BigDecimal 就一定能避免丢失精度嘛?

BigDecimal num1 = new BigDecimal(0.03);
BigDecimal num2 = new BigDecimal(0.02);
System.out.println(num1.subtract(num2));

得到的结果是:0.0099999999999999984734433411404097569175064563751220703125

通过阅读源码可知,构造方法的结果是不可预测的,例如想创建 0.1 的值,结果却是0.1000000000000000055511151231257827021181583404541015625的情况

解决:因此官方更推荐我们使用 valueOf 的方式

BigDecimal num1 = BigDecimal.valueOf(0.03);
BigDecimal num2 = BigDecimal.valueOf(0.02);
System.out.println(num1.subtract(num2));

如果在 IDEA上安装了 Alibaba的代码检查插件,也可以看到对应提示

5. 字符串拼接问题

场景:将两个字符串的值进行拼接

也许我们第一时间想到的就是用 “123” + “456” 的方式

但是 String 类型的字符串被称为不可变序列,也就是定义好之后,就不能被修改了(我们进行的修改,实际上是创建了新的对象)

可以看到底层使用的是 final 修饰的

问题:如何进行字符串的拼接呢?

使用可变字符序列 StringBuilderStringBuffer,来定义对象

  • StringBuilder(线程不安全,效率高)
  • StringBuffer(线程安全,效率低)
String a = "123";
StringBuilder builder = new StringBuilder();
builder.append(a).append("456");
System.out.println(builder);

问题:使用 + 拼接 String 类型的对象,效率一定比使用 append 拼接 StringBuilder 类型的对象低嘛?

public class StringDemo 
	public static void main(String[] args) 
		String a = "123";
		String b = "456";
		String c = a + b;
		System.out.println(c);
	

通过使用 javap -c StringDemo.class,可以发现,虽然代码中用的是 + 操作,但是编译为字节码文件之后,实际上是被优化为了 StringBuilder 的 append 操作(JDK1.5之后)

6. 字符串判空问题

场景:判断前台传过来的字段值是否为空

我们一般常规的写法:

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

每次都这么判断太不优雅了,可以使用主流的工具类

apache common 3中的 StringUtils

注意:isEmpty 和 isBlank 方法的区别

  • StringUtils.isEmpty(" ")        // false
    
  • StringUtils.isBlank(" ")        // true
    

7. mapper 查询结果的判空

场景:处理查询出来的结果

List<Student> list = studMapper.getList(params);
for (Student stu : list) 
    // todo

问题:这里是否要做判空处理,然后再进行操作呢?

这里是不用进行判空的,通过阅读源码可知,MyBatis 的查询方法最终都会调用到 org.apache.ibatis.executor.resultset 包下的 DefaultResultSetHandler类的 handleResultSets方法,该方法会返回一个 multipleResultList 集合对象,而该对象在一开始就 new 出来了,肯定是不会空的,不会出现 NullPointerException

以上是关于Java# Java易错知识点:replaceindexOf数值包装类判断相等数值精度问题字符串拼接字符串判空mapper查询结果处理的主要内容,如果未能解决你的问题,请参考以下文章

java预习易错点

java预习易错点

java基础中的易错点

java初级易错问题总结

[Java基础]String对象的特点(易错点)

Java代码实际应用中的易错点记录