刚上手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()方法

相关推荐
HackKong1 分钟前
高校网络安全_网络安全之道
java·网络·c++·python·学习·web安全·黑客技术
半夏知半秋15 分钟前
lua debug相关方法详解
开发语言·学习·单元测试·lua
Andy01_18 分钟前
Java八股汇总【MySQL】
java·开发语言·mysql
唐 城26 分钟前
Solon v3.0.5 发布!(Spring 可以退休了吗?)
java·spring·log4j
V+zmm1013434 分钟前
社区二手物品交易小程序ssm+论文源码调试讲解
java·微信小程序·小程序·毕业设计·ssm
坊钰37 分钟前
【Java 数据结构】合并两个有序链表
java·开发语言·数据结构·学习·链表
教语文的小灰灰38 分钟前
免费线上签字小程序,开启便捷电子签名
经验分享
秋天下着雨44 分钟前
apifox调用jar程序
java·python·jar
m0_748251081 小时前
docker安装nginx,docker部署vue前端,以及docker部署java的jar部署
java·前端·docker
A22741 小时前
Redis——缓存雪崩
java·redis·缓存