- 用==号比较的坑
对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方法的判断逻辑如下:
-
该方法先判断对象a和b的引用是否相等,如果相等则直接返回true。
-
如果引用不相等,则判断a是否为空,如果a为空则返回false。
-
如果a不为空,调用对象的equals方法进一步判断值是否相等。
-
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));
- 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());
}
其根本原因是:过滤后的集合中,保存的是对象的引用,该引用只有一份数据。
也就是说,只要有一个地方,把该引用对象的成员变量
的值,做修改了,其他地方也会同步修改。
- 自动拆箱
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
异常。
- 字符串的replace() 和 replaeAll()
我们在使用字符串时,想把字符串中一些指定的字符替换成我们希望的字符。
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")
使用正则表达替换(将数字替换成A):str.replaceAll("\\d", "A")
只想替换第一个匹配的字符串,使用replaceFirst()
方法