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

相关推荐
Abladol-aj31 分钟前
并发和并行的基础知识
java·linux·windows
清水白石00831 分钟前
从一个“支付状态不一致“的bug,看大型分布式系统的“隐藏杀机“
java·数据库·bug
Elihuss1 小时前
ONVIF协议操作摄像头方法
开发语言·php
小民子1 小时前
DDR3脚位解析,class分类
经验分享
Swift社区5 小时前
在 Swift 中实现字符串分割问题:以字典中的单词构造句子
开发语言·ios·swift
没头脑的ht5 小时前
Swift内存访问冲突
开发语言·ios·swift
没头脑的ht5 小时前
Swift闭包的本质
开发语言·ios·swift
wjs20245 小时前
Swift 数组
开发语言
吾日三省吾码6 小时前
JVM 性能调优
java
stm 学习ing6 小时前
FPGA 第十讲 避免latch的产生
c语言·开发语言·单片机·嵌入式硬件·fpga开发·fpga