BigDecimal
精度丢失
private static void scaleProblem() {
BigDecimal decimal = new BigDecimal("12.222");
BigDecimal result = decimal.setScale(2);
System.out.println(result);
}
执行以上代码将会抛出异常,因为指定的精度不符合要求,如需要舍弃精度,应调用以下方法
BigDecimal result = decimal.setScale(2, BigDecimal.ROUND_HALF_UP);
除不尽
private static void divideProblem() {
System.out.println(new BigDecimal(30).divide(new BigDecimal(7)));
}
总所周知,上面结果是除不尽的,因此也会抛出异常,同样舍弃精度即可
System.out.println(new BigDecimal(30).divide(new BigDecimal(7), 2, BigDecimal.ROUND_HALF_UP));
精度导致比较结果错误
private static void equalProblem() {
BigDecimal bd1 = new BigDecimal("0");
BigDecimal bd2 = new BigDecimal("0.0");
System.out.println(bd1.equals(bd2));
System.out.println(bd1.compareTo(bd2) == 0);
}
第一个方法返回结果为:假,因为如果精度不同将会返回假
@Override
public boolean equals(Object x) {
...
if (scale != xDec.scale)
return false;
...
}
第二个方法返回结果为:真,因为数值相等
SimpleDateFormat
时间精度
private static void formatPrecision() throws Exception {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String time_x = "2020-03-01 10:00:00";
String time = "2020-03";
System.out.println(sdf.parse(time_x));
System.out.println(sdf.parse(time));
}
第一个字符串解析成功,第二个字符串解析失败,因此能够解析大于等于它定义的时间精度
线程不安全
private static void threadSafety() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MINUTES, new LinkedBlockingDeque<>(1000));
while (true) {
threadPoolExecutor.execute(() -> {
String dateString = "2020-03-01 10:00:00";
try {
Date parseDate = sdf.parse(dateString);
String dateString2 = sdf.format(parseDate);
System.out.println(dateString.equals(dateString2));
} catch (ParseException ex) {
ex.printStackTrace();
}
});
}
}
多线程场景下将会导致异常的抛出,原因是不论解析还是格式化方法,都离不开下面的全局变量
protected Calendar calendar;
由于对象引用被共享,并且其内部没有实现线程安全机制,因此它并不是线程安全的对象,解决线程安全的方式有三种:方法局部变量、线程局部变量、同步锁
For
for (Iterator<Integer> l = left.iterator(); l.hasNext(); ) {
for (Iterator<Integer> r = right.iterator(); r.hasNext(); ) {
System.out.println(l.next() * r.next());
}
}
以上代码较传统循环少了迭代索引,但存在外层迭代过早耗尽的问题,改成如下代码即可
for (Iterator<Integer> l = left.iterator(); l.hasNext(); ) {
Integer tmp = l.next();
for (Iterator<Integer> r = right.iterator(); r.hasNext(); ) {
System.out.println(tmp * r.next());
}
}
但以上代码迭代复杂度还是有点高,我们有更加简单的迭代方法
for (Integer l : left) {
for (Integer r : right) {
System.out.println(l * r);
}
}
Object
默认 Equals 比较内存地址,默认 HashCode 根据对象地址生成整数数值
若需相同的对象在 Set 和 Map 中只存在一个,必须重写 HashCode 方法,并尽量让属性参与到计算中
List
List # indexOf 方法基于 Equals 方法实现比较
Collections.binarySearch 方法基于 CompareTo 方法实现比较
因此上述两个方法的实现应该要同步,否则排序与索引位置可能不一致
Lombok
单字母驼峰
@Data
public class Personal {
private String iPhone;
private String name;
private String userName;
}
序列化字段名称变化
ObjectMapper mapper = new ObjectMapper();
Personal personal = new Personal();
personal.setIPhone("?");
System.out.println(mapper.writeValueAsString(personal));
输出结果
{"name":null,"userName":null,"iphone":"?"}
如果将上述结果修改为以下字符串再解析
{"name":null,"userName":null,"iPhone":"?"}
输出结果
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "iPhone"
父类属性
@Data 注解包含 @EqualsAndHashCode(callSuper = false)注解
因此需要注意子类 Equals 方法默认只会比较当前子类的属性,否则需要手动加上以下注解
@EqualsAndHashCode(callSuper = true)
未完待续....