这些 Java 8 官方挖的坑,你踩过几个?( 三 )


文章插图
 
如果你想体验这个实例 , 可关注公众号码大叔和笔者交流 。如果你下次遇到莫名的java.lang.ArrayStoreException: sun.reflect.annotation.TypeNotPresentExceptionProxy,请记得用这个方法定位具体问题 。
3、日期计算:我想留住时间 , 让1天像1年那么长Java8之前日期时间操作相当地麻烦 , 无论是Calendar还是SimpleDateFormat都让你觉得这个设计怎么如此地反人类 , 甚至还会出现多线程安全的问题 , 阿里巴巴开发手册中就曾禁用static修饰SimpleDateFormat 。好在千呼万唤之后 , 使出来了 , Java8带来了全新的日期和时间API , 还带来了Period和Duration用于时间日期计算的两个API 。

Duraction和Period , 都表示一段时间的间隔 , Duraction正常用来表示时、分、秒甚至纳秒之间的时间间隔 , Period正常用于年、月、日之间的时间间隔 。
网上的大部分文章也是这么描述的 , 于是计算两个日期间隔可以写成下面这样的代码:
// parseToDate方法作用是将String转为LocalDate , 略 。LocalDate date1 = parseToDate("2020-05-12");LocalDate date2 = parseToDate("2021-05-13");// 计算日期间隔int period = Period.between(date1,date2).getDays();一个是2020年 , 一个是2021年 , 你认为间隔是多少?1年? 恭喜你 , 和我一起跳进坑里了(画外音:里面的都挤一挤 , 动一动 , 又来新人了) 。
正确答案应该是:1天 。
这个单词的含义以及这个方法看起来确实是蛮误导人的 , 一不注意就会掉进坑里 。Period其实只能计算同月的天数、同年的月数 , 不能计算跨月的天数以及跨年的月数 。
正确写法1:
 long period = date2.toEpochDay()-date1.toEpochDay();toEpochDay():将日期转换成Epoch 天 , 也就是相对于1970-01-01(ISO)开始的天数 , 和时间戳是一个道理 , 时间戳是秒数 。显然 , 该方法是有一定的局限性的 。
正确写法2:
long period = date1.until(date2,ChronoUnit.DAYS);使用这个写法 , 一定要注意一下date1和date2前后顺序:date1 until date2 。
正确做法3(推荐):
 long period = ChronoUnit.DAYS.between(date1, date2);ChronoUnit:一组标准的日期时间单位 。这组单元提供基于单元的访问来操纵日期 , 时间或日期时间 。这些单元适用于多个日历系统 。这是一个最终的、不可变的和线程安全的枚举 。
看到”适用于多个日历系统“这句话 , 我一下子想起来历史上1582年神秘消失的10天 , 在JDK8上是什么效果呢?1582-10-15和1582-10-04你觉得会相隔几天呢?11天还是1天?有兴趣的小伙伴自己去写个代码试试吧 。
这些 Java 8 官方挖的坑,你踩过几个?

文章插图
 
打开你的手机 , 跳转到1582年10月 , 你就能看到这消失的10天了 。
4、List:一如你我初见 , 不增不减这个问题其实在JDK里存在很多年了 , JDK8中依然存在 , 也是很多人最容易跳的一个坑!直接上代马:
public List<String> allUser() {    // 省略    List<String> currentUserList = getUser();    currentUserList.add("码大叔");    // 省略}就是上面这样一段代码 , 往一个list里添加一条数据 , 你觉得结果是什么呢?“码大叔”成功地添加到了List里?天真 , 不报个错你怎么能意识到JDK存在呢 。
Exception in thread "main" java.lang.UnsupportedOperationException    at java.util.AbstractList.add(AbstractList.java:148)原因:因为在getUser方法里 , 返回的List使用的是Arrays.asList生成的 , 示例:
    private List<String> getUser(){        return Arrays.asList("剑圣","小九九");    }我们来看看Arrays.asList的源码
    @SafeVarargs    @SuppressWarnings("varargs")    public static <T> List<T> asList(T... a) {        return new ArrayList<>(a);    }


推荐阅读