刚上手Java会踩的坑

  1. 用==号比较的坑

Integer类型的两个参数使用==号比较是否相等,或者使用String类型的两个变量进行==比较,天真的认为他们是理所应当的。

其实==操作只适用于基本数据类型如int , byte, boolean, short, char, long, float, double这些基本数据类型。

其它的包装类型Integer, Byte, Boolean, Short, Character Long, Float, Double 这些是对基本数据类型的包装类型。我们做项目的时候,保存数据类型一般都使用Integer这类包装数据类型,因为它们的默认值为null,而不是基本数据类型例如int的默认值是0。使用包装数据类型不容易出错,与前端进行交互时也可以快速的定位错误(数据字段前端有没有发过来,而不会有默认值,直接就是null)。

像String,数组,类的实例对象或者基本数据类型的包装类这类进行比较是否相等要使用equals(),因为它们是引用类型的数据。

java 复制代码
        Integer integer = new Integer(1);
        Integer integer1 = new Integer(1);
        System.out.println(integer1 == integer); // false
        System.out.println(integer1.equals(integer)); // true

Integer中不是有范围是:-128-127的缓存吗?为什么是false?它其实并没有用到缓存

那么缓存是在哪里用的?答案在valueOf方法中:

java 复制代码
        String s1 = new String("1");
        String s2 = new String("1");
        System.out.println(Integer.valueOf(s1) == Integer.valueOf(s2)); // true

2.Object.equals()

equals方法的判断逻辑如下:

  1. 该方法先判断对象a和b的引用是否相等,如果相等则直接返回true。

  2. 如果引用不相等,则判断a是否为空,如果a为空则返回false。

  3. 如果a不为空,调用对象的equals方法进一步判断值是否相等。

  4. BigDecimal

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

a - b应该等于0.01

java 复制代码
        double a = 0.03;
        double b = 0.02;
        System.out.println(a - b);// 0.009999999999999998

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

我们使用BigDecimal能避免丢失精度。但也有坑在里面,我们可以使用Double.toString方法,对double类型的小数进行转换,这样能保证精度不丢失。

使用BigDecimal.valueOf方法初始化BigDecimal类型参数,也能保证精度不丢失。

java 复制代码
 BigDecimal c = new BigDecimal(0.02);
        BigDecimal d = new BigDecimal(0.03);
        System.out.println(d.subtract(c)); // 0.0099999999999999984734433411404097569175064563751220703125

        BigDecimal r = new BigDecimal(Double.toString(0.02));
        BigDecimal g = new BigDecimal(Double.toString(0.03));
        System.out.println(g.subtract(r));// 0.01

        BigDecimal v = BigDecimal.valueOf(0.02);
        BigDecimal b = BigDecimal.valueOf(0.03);
        System.out.println(b.subtract(v));
  1. Java8 filter

Java8中的Stream用法很强大,刚使用时很震撼。对集合Stream操作,可以实现:遍历集合、过滤数据、排序、判断、转换集合等等功能。

java 复制代码
public List<User> filterUser(List<User> userList) {
    if(CollectionUtils.isEmpty(userList)) {
        return Collections.emptyList();
    }
    
    return userList.stream()
    .filter(user -> user.getId() > 1000 && user.getAge() > 18)
    .collect(Collectors.toList());
}

如果你对过滤后的数据做修改将同时影响原本的数据

java 复制代码
List<User> userList = queryUser();
List<User> filterList = filterUser(userList);
for(User user: filterList) {
   user.setName(user.getName() + "测试");
}

for(User user: userList) {
   System.out.println(user.getName());
}

其根本原因是:过滤后的集合中,保存的是对象的引用,该引用只有一份数据。

也就是说,只要有一个地方,把该引用对象的成员变量的值,做修改了,其他地方也会同步修改。

  1. 自动拆箱

Java5之后,提供了自动装箱自动拆箱的功能。

自动装箱是指:JDK会把基本类型,自动变成包装类型。

java 复制代码
Integer integer = 66;
// 等同
Integer integer = new Integer(66);

而自动拆箱是指:JDK会把包装类型,自动转换成基本类型。

java 复制代码
Integer integer = new Integer(9);
int num= integer + 1;
// 等同于
Integer integer = new Integer(9);
int num= integer.intValue() + 1;

我们在使用自动拆箱时,往往忘记了判空,导致出现NullPointerException异常。

  1. 字符串的replace() 和 replaeAll()

我们在使用字符串时,想把字符串中一些指定的字符替换成我们希望的字符。

replace方法:

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

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

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

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

replaceAll方法的参数是:String regex 和 String replacement,即基于正则表达式的替换。

普通字符串进行替换: source.replaceAll("A", "B")

使用正则表达替换(将数字替换成A):str.replaceAll("\\d", "A")

只想替换第一个匹配的字符串,使用replaceFirst()方法

相关推荐
救救孩子把15 分钟前
深入理解 Java 对象的内存布局
java
落落落sss18 分钟前
MybatisPlus
android·java·开发语言·spring·tomcat·rabbitmq·mybatis
万物皆字节23 分钟前
maven指定模块快速打包idea插件Quick Maven Package
java
夜雨翦春韭30 分钟前
【代码随想录Day30】贪心算法Part04
java·数据结构·算法·leetcode·贪心算法
简单.is.good35 分钟前
【测试】接口测试与接口自动化
开发语言·python
我行我素,向往自由36 分钟前
速成java记录(上)
java·速成
一直学习永不止步42 分钟前
LeetCode题练习与总结:H 指数--274
java·数据结构·算法·leetcode·数组·排序·计数排序
邵泽明43 分钟前
面试知识储备-多线程
java·面试·职场和发展
Yvemil71 小时前
MQ 架构设计原理与消息中间件详解(二)
开发语言·后端·ruby
程序员是干活的1 小时前
私家车开车回家过节会发生什么事情
java·开发语言·软件构建·1024程序员节