《Java8 实战》笔记——5.JDK8日期类&新增API补充

//1.4 ArraysSS

**//1.5 String**

为什么需要新的API?

在Java8之前,由于JDK本身设计的问题,导致了存在的时间日期API使用起来不是很好用(Date类:赋值的语义不直观、toString的返回值包含JVM的默认时区CETCalendar类:月份依旧从0计算、与Date共存难以选择最大的问题是:本身可变难以维护、格式化时间DateFormat不是线程安全的),其语义也不是很好,比如Date表示的是时间以及日期,为了使得时间日期相关的API操作起来比较方便,语义更好,Java8中加入了新的时间以及日期操作,位于java.time包中

在java.time包中有许多的类,不过我们关心的主要有以下几个:

  • LocalDate,日期操作类
  • LocalTime,时间操作类
  • LocalDateTime,日期时间
  • Duration,时间间隔
  • Period,日期间隔

1. LocalDate和LocalTime类

他们都是不可变的;LocalDate包含年、月、日、星期的相关属性;LocalTime包含时分秒的相关属性;

使用方法包括:取当前时间日期、赋值、取某个属性、判断属性、通过字符串转换来赋值、合并为日期+时间LocalDateTime类;

    @Test
    public void func_01() {
        //正如其名,LocalDate表示的是本地的日期,根据OS的设置来获取对应的时区等信息,其用法也非常简单
        //初始化赋值-获取某个时间的对象
        LocalDate date = LocalDate.of(2016, 9, 11);
        System.out.println(date);
        //通过LocalDate对象可以获取年月日等信息,其API比较见名知义,就不展开介绍了
        int year = date.getYear();
        System.out.println(year);
        Month month = date.getMonth();//返回月份 SEPTEMBER
        System.out.println(month);
        int day = date.getDayOfMonth();
        System.out.println(day);

        DayOfWeek dow = date.getDayOfWeek();
        System.out.println(dow);//返回星期三 WEDNESDAY

        int len = date.lengthOfMonth();//这个月9月 一共30天
        System.out.println(len);

        boolean leap = date.isLeapYear();//是否闰年 2016 是闰年
        System.out.println(leap);
        //获取当前日期
        LocalDate today = LocalDate.now();
        System.out.println(today);
        //解析日期字符串,通过字符串赋值
        LocalDate date1 = LocalDate.parse("2019-09-04");//这里单数的数字必须前面+0,如2019.9.4->"2019-09-04",否则DateTimeParseException;
        System.out.println(date1);

    }

    @Test
    public void func_02() {//LocalTime表示的是当前的时间,其主要用法如下
        //获取当前时间
        LocalTime time = LocalTime.now();
        System.out.println(time);
        System.out.println(time.getHour());
        System.out.println(time.getMinute());
        System.out.println(time.getSecond());
        System.out.println(time.getNano());//精确到 纳秒
        //解析时间字符串,通过字符串赋值
        LocalTime time1 = LocalTime.parse("13:45:20");这里单数的数字必须前面+0,如2019.9.4->"2019-09-04",否则DateTimeParseException;
    }

    @Test
    public void func_03() {//LocalDateTime表示的是日期以及时间LocalDate+LocalTime,大致等于以前的Date对象
        LocalDateTime dt1 = LocalDateTime.of(LocalDate.now(), LocalTime.now());//通过两个对象LocalDate+LocalTime合并为LocalDateTime;
        System.out.println(dt1);
        LocalDateTime dt2 = LocalDateTime.of(2018, Month.JULY, 24, 9, 32, 20);
        //几种赋值修改的方式,指定LocalDate或LocalTime
        LocalDateTime dt3 = LocalDate.now().atTime(13, 45, 20);
        LocalDateTime dt4 = LocalDate.now().atTime(LocalTime.now());
        LocalDateTime dt5 = LocalTime.now().atDate(LocalDate.now());
        //拆分成LocalDate和LocalTime
        LocalDate date = dt1.toLocalDate();
        LocalTime time = dt2.toLocalTime();
    }

2. Instant类

   @Test
   public void func_04() { //Instant的设计初衷是为了机器使用,即仅包含秒-纳秒级的单位
       System.out.println(Instant.ofEpochSecond(2));//从1970-1-1 00:00:00 加上2秒 即1970-1-1 00:02:00
       System.out.println(Instant.ofEpochSecond(2, 2000000000L));//从1970-1-1 00:00:00 加上2秒和2亿纳秒 即1970-1-1 00:04:00
       System.out.println(Instant.now());//也可以打印当前时间戳
   }

3. Duration和Period类

    @Test
    public void func_05() throws InterruptedException {
        //Duration表示的是两个"时间"的间隔,注意 不能 用于表示两个"日期"间隔;可以比较LocalTime与Instant,也可以定义一个时间间隔
        LocalTime lt0 = LocalTime.now();
        Thread.sleep(2000);
        Duration d1 = Duration.between(LocalTime.now(), lt0);//传入两个可以比较LocalTime
        System.out.println(d1);
        Instant t0 = Instant.now();
        Thread.sleep(1000);
        Duration d3 = Duration.between(Instant.now(), t0);//传入两个Instant
        System.out.println(Duration.between(t0, Instant.now()));//后者减去前者
        System.out.println(d3);
        //定义时间间隔
        Duration threeMinutes = Duration.ofMinutes(3);
        System.out.println(threeMinutes);
        Duration twoMinutess = Duration.of(2, ChronoUnit.MINUTES);
        System.out.println(twoMinutess);
    }

    @Test
    public void func_06() {
        //与Duration对应,Period表示的是两个日期的间隔,注意不能用来表示两个时间间隔
        LocalDate ld0 = LocalDate.of(2018, 8, 5);//2018,8,3 2018,8,4
        Period p1 = Period.between(ld0, LocalDate.now());
        System.out.println(p1);
        //定义日期间隔
        Period tenDays = Period.ofDays(10);
        System.out.println(tenDays);
        Period threeWeeks = Period.ofWeeks(3);
        System.out.println(threeWeeks);
    }

4.修改时间的属性

@Test
    public void func_07() {
        //对于LocalDate/LocalTime,相对于get取出属性,也可以使用with修改属性,注意修改后的为一个新对象,不会改变原有的LocalDate/LocalTime对象
        //with直观操作,注意这里每一步都有个date = ...的赋值操作;
        LocalDate date = LocalDate.now();
        System.out.println(date);
        date = date.withDayOfMonth(10);//日期修改为:这个月的第10天
        System.out.println(date);
        date = date.withDayOfYear(5);//日期修改为:这一年的第5天
        System.out.println(date);
        date = date.withYear(2018);//日期修改为:年份2018
        System.out.println(date);
        date = date.withMonth(8);//日期修改为:月份8
        System.out.println(date);
        date = date.with(ChronoField.MONTH_OF_YEAR, 10);//日期修改为:月份10
        System.out.println(date);
        //语义式的修改操作
        date = date.plusDays(11);//日期修改为:加11天
        System.out.println(date);
        date = date.minusWeeks(1);//日期修改为:减1周
        System.out.println(date);
        date = date.plus(6, ChronoUnit.MONTHS);//日期修改为:月份加6
        System.out.println(date);
        //测试会不会修改以前的值
        date.plus(3, ChronoUnit.YEARS);//日期修改为:年份加6-但是没有赋值,因此结果没变
        System.out.println(date);
    }

    @Test
    public void func_01() {
//正如其名,LocalDate表示的是本地的日期,根据OS的设置来获取对应的时区等信息,其用法也非常简单
//初始化赋值-获取某个时间的对象

        LocalDate date = LocalDate.of(2016, 9, 11);
        System.out.println(date);
//通过LocalDate对象可以获取年月日等信息,其API比较见名知义,就不展开介绍了
        int year = date.getYear();
        System.out.println(year);
        Month month = date.getMonth();//返回月份 SEPTEMBER
        System.out.println(month);
        int day = date.getDayOfMonth();
        System.out.println(day);

        DayOfWeek dow = date.getDayOfWeek();
        System.out.println(dow);//返回星期三 WEDNESDAY

        int len = date.lengthOfMonth();//这个月9月 一共30天
        System.out.println(len);

        boolean leap = date.isLeapYear();//是否闰年 2016 是闰年
        System.out.println(leap);
//获取当前日期
        LocalDate today = LocalDate.now();
        System.out.println(today);
//解析日期字符串,通过字符串赋值
        LocalDate date1 = LocalDate.parse("2019-09-04");//这里单数的数字必须前面+0,如2019.9.4->"2019-09-04",否则DateTimeParseException;
        System.out.println(date1);

    }

    @Test
    public void func_02() {//LocalTime表示的是当前的时间,其主要用法如下
//获取当前时间
        LocalTime time = LocalTime.now();
        System.out.println(time);
        System.out.println(time.getHour());
        System.out.println(time.getMinute());
        System.out.println(time.getSecond());
        System.out.println(time.getNano());//精确到 纳秒
//解析时间字符串,通过字符串赋值
        LocalTime time1 = LocalTime.parse("13:45:20");这里单数的数字必须前面+0,如2019.9.4->"2019-09-04",否则DateTimeParseException;
    }

    @Test
    public void func_03() {//LocalDateTime表示的是日期以及时间LocalDate+LocalTime,大致等于以前的Date对象
        LocalDateTime dt1 = LocalDateTime.of(LocalDate.now(), LocalTime.now());//通过两个对象LocalDate+LocalTime合并为LocalDateTime;
        System.out.println(dt1);
        LocalDateTime dt2 = LocalDateTime.of(2018, Month.JULY, 24, 9, 32, 20);

//几种赋值修改的方式,指定LocalDate或LocalTime
        LocalDateTime dt3 = LocalDate.now().atTime(13, 45, 20);
        LocalDateTime dt4 = LocalDate.now().atTime(LocalTime.now());
        LocalDateTime dt5 = LocalTime.now().atDate(LocalDate.now());

//拆分成LocalDate和LocalTime
        LocalDate date = dt1.toLocalDate();
        LocalTime time = dt2.toLocalTime();
    }

5.复杂操作(带有语义的,"如本周的最后一天"...)

    @Test
    public void func_08() {
        //with传入对象(他是一个方法工厂),语义式的修改日期/时间,更加灵活和直观
        LocalDate date = LocalDate.now();
        System.out.println(date);
        date = date.with(TemporalAdjusters.next(DayOfWeek.MONDAY));//得到下一个最近的"周一"的日期
        System.out.println(date);
        date = date.with(TemporalAdjusters.lastDayOfMonth());//得到这个月最后一天的日期
        System.out.println(date);
    }

6.打印输出/解析时间

    @Test
    public void func_09() {
        //date.format格式化时间的输出形式,注意,他是线程安全的
        LocalDate date = LocalDate.now();
        System.out.println(date);
        System.out.println(date.format(DateTimeFormatter.BASIC_ISO_DATE));
        System.out.println(date.format(DateTimeFormatter.ISO_LOCAL_DATE));//default格式
        System.out.println(date.format(DateTimeFormatter.ofPattern("dd/MM/yyyy")));//yyyy表示显示4位的年份,若是yy则显示后两位数
        System.out.println(date.format(DateTimeFormatter.ofPattern("dd MMMM yyyy", Locale.ENGLISH)));//带国际化的日期
    }

7.处理时区

    @Test
    public void func_10() {
        //时区相关:时区时间类ZoneDateTime类,时区名ZoneId类
        ZoneId zomeZone = ZoneId.of("Europe/Rome");//这个"Europe/Rome"需要查,不匹配则会抛异常
        ZoneId zomeZone1 = ZoneId.of("America/New_York");
        System.out.println(TimeZone.getDefault().toZoneId());//默认在 亚洲/上海 Asia/Shanghai
        LocalDateTime ldt = LocalDateTime.now();
        System.out.println(ldt);
        ZonedDateTime zdt = ldt.atZone(zomeZone);
        System.out.println(zdt);
        System.out.println(ldt.atZone(zomeZone1));
    }

总结:本小节主要简单地介绍了Java8中新的日期以及时间操作API,由于新的API语义性非常好,所以也没有过多地展开,在需要的时候查一下文档就足够了;

( Java8中时间日期库的20个常用使用示例 Java8中时间日期库的20个常用使用示例_Java我人生的博客-CSDN博客_java8中日期 )

最后补充一下JDK8 API中新增的一些方法

JDK8 API的更新

  • Map接口本身没有可用的stream()方法但是你可以在键key-值value上创建专门的流或者通过map.keySet().stream(),map.values().stream()和map.entrySet().stream();

Map类型不支持streams,不过Map提供了一些新的有用的方法来处理一些日常任务(对key-value的操作),如下:
//1.1 Map

    //1.1 Map
    @Test
    public void func_01() {
        Map<Integer, String> map = new HashMap<>();
        // map.stream();//Map没有.stream方法,但是更新了一些方便的API
        map.put(0, "init val-0");
        for (int i = 0; i < 10; i++) {
            map.putIfAbsent(i, "val-" + i);//putIfAbsent()//1.初始化Map,给key-value赋值,当key不存在/或者值为null时,才插入value
        }
        System.out.println(map);
        //
        map.forEach((id, val) -> System.out.println(id + " ^" + val));//2.forEach遍历 forEach(): val0 val1 val2 val3 val4 val5 val6 val7 val8 val9
        //
        map.computeIfPresent(3, (num, val) -> val + num);//3.第二个参数为BiFunction,通过key和value来计算value,并且把新value的计算结果put进去,当key不存在/或者值为null时才计算
        System.out.println(map.get(3));             // “val-3”+3 = "val-33"
        map.computeIfPresent(9, (num, val) -> null);
        System.out.println(map.containsKey(9));     // 上一步key=9对应的value被置为null,返回false
        map.computeIfPresent(11, (num, val) -> num + val);
        System.out.println(map.containsKey(11));     // 不存在该key,返回false
        //
        map.computeIfAbsent(23, num -> "val" + num);//4.与上面类似,当key/value存在才计算;
        System.out.println(map.containsKey(23));    // true
        map.computeIfAbsent(3, num -> "33333");//IfAbsent为false,因此value不变
        System.out.println(map.get(3));             // val-33
        //接下来展示如何在Map里删除一个键值K V 全都匹配的项
        System.out.println(map.remove(3, "val-3"));//5.删除完全匹配的k/v,没匹配成功,返回false
        System.out.println(map.remove(3, "val-33"));//匹配成功,删除,返回true
        System.out.println(map.get(3));//null
        System.out.println(map.getOrDefault(33, "not found"));//6.取value值,返回原值或者默认值(如归原value为空),这一步只取值没有put操作,不修改map!
        System.out.println(map.get(33));//null,上一步getOrDefault()的操作没有对map进行put操作,仅返回值
        //对Map的元素做合并也变得很容易了:7.Merge和前面的compute类似,不传入key但是多了个初始值,做的事情是如果键名不存在则插入,否则则对原键对应的值和初始值做合并操作并重新插入到map中;
        System.out.println(map.get(9)); //之前的状态:<9,null>
        map.merge(9, "val-9", (value, newValue) -> value.concat(newValue));//不存在键名key,插入
        System.out.println(map.get(9));             // val9
        map.merge(9, "-concat", (value, newValue) -> value.concat(newValue));//存在key,执行后面的操作,把结果作为新value给put进去;
        System.out.println(map.get(9));
    }

//1.2 列表 List

    //1.2 列表 List
    @Test
    public void func_02() {
        List<Integer> list = Arrays.asList(1, 3, 5, 7, 9);
        list.replaceAll((i) -> i + 1);//1.replaceAll,传入一个Function,相当于对Array做了流里面的map操作
        System.out.println(list);
//        list.removeIf(i -> i > 5);//注意这里会报错UnsupportedOperationException,因为list没有重写remove方法,需要转成ArrayList
        List<String> al = new ArrayList<>();
        al.add("1");
        al.add("3");
        al.add("5");
        al.add("7");
        al.add("9");
        al.removeIf(i -> Integer.parseInt(i) > 5);//2.removeIf,传入一个Predicate,删除满足要求的list元素,需要注意该list必须重写了remove方法;
        System.out.println(al);
    }

//1.3 比较器 Comparator 配合流的sorted/集合类的sort

    //1.3 比较器 Comparator 配合流的sorted/集合类的sort
    @Test
    public void func_03() {
        //1.定义自己的Comparator,comparing方法传入一个Function,即对i处理后,在做compareTo比较
        System.out.println(Stream.of(1, 3, 5, 7, 9, 2, 4, 6, 8, 10).sorted(Comparator.comparing(i -> Math.abs(5 - i))).collect(Collectors.toList()));//按照与5的距离排序;
        //2.将比较器-逆序,comparing传入第二个参数reverseOrder/或者后面直接.reversed,注意:不能在传入lambda的Comparator后面直接加.reverse,会编译报错,需要显示的加上lambda的参数类型;
        System.out.println(Stream.of(1, 3, 5, 7, 9, 2, 4, 6, 8, 10)
                .sorted(Comparator.comparing(i -> Math.abs(5 - i), Comparator.reverseOrder()))
                .collect(Collectors.toList()));//将比较器-逆序;
        System.out.println(Stream.of(1, 3, 5, 7, 9, 2, 4, 6, 8, 10)
                .sorted(Comparator.comparing((Integer i) -> Math.abs(5 - i)).reversed())
                .collect(Collectors.toList()));//将比较器-逆序;
        //3.如果比较结果相等,则继续比较,否则不触发thenComparing
        System.out.println(Stream.of(1, 3, 5, 7, 9, 2, 4, 6, 8, 10)
                .sorted(Comparator.comparing((Integer i) -> Math.abs(5 - i)).thenComparing(Comparator.reverseOrder()))
                .collect(Collectors.toList()));//将比较器-逆序;
    }

//1.4 Arrays

    //1.4 Arrays
    @Test
    public void func_04() {
        //1.setAll
        int[] array0 = new int[1000000];
        //  Arrays.fill(array0,1);//只能指定值填充;
        // System.out.println(Arrays.toString(array0));
        Random r = new Random();
        Arrays.setAll(array0, i -> i);//会打印出0-数组长度的自然数
        Arrays.setAll(array0, i -> i * r.nextInt(5));//可以使用lambda
        //System.out.println(Arrays.toString(array0));
        //2.parallelSort
        long start = System.nanoTime();
        Arrays.sort(array0.clone());
        System.out.println((System.nanoTime() - start) / 1000000 + " ms");
        start = System.nanoTime();
        Arrays.parallelSort(array0.clone());//parallelSort比sort速度提升很多
        System.out.println((System.nanoTime() - start) / 1000000 + " ms");
        //3.并行累积(前n项)累积运算
        int[] array1 = new int[]{1, 3, 5, 7, 9, 2, 4, 6, 8, 10};
        Arrays.parallelPrefix(array1, (a, b) -> a * b);//每一项为从当前索引的前n项累积两两运算的结果;
        System.out.println(Arrays.toString(array1));
    }

**//1.5 String**


    //1.5 String
    @Test
    public void func_05() {//将列表或数组的每个String元素以指定的符号连接成一个String
        //对List
        List<String> list = new ArrayList<>();
        list.add("Mxy");
        list.add("String");
        list.add("join");
        String join = String.join("-", list);//传入String类型的List集合,使用"-"号拼接
        System.out.println(join);
        //对Array
        String[] s = new String[]{"Hao", "Ming"};//传入String类型的数组,使用"-"号拼接
        String join2 = String.join("-", s);
        System.out.println(join2);
        //Stream
        String res = list.stream().collect(Collectors.joining(", "));
        System.out.println(res);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值