• Java8新特性


    一、Lambda表达式

    Lambda表达式是一个匿名函数,可以理解为一段可以传递的代码。

    new Thread(()->{
                System.out.println("线程Lambda表达式"+ Thread.currentThread().getName());
            }).start();
    
    • 1
    • 2
    • 3

    Lambda表达式的优点:简化了匿名内部类的使用,语法更加简单。
    匿名内部类语法冗余,体验了Lambda表达式后,发现Lambda表达式是简化匿名内部类的一种方式。

    1、语法规则

    Lambda省去了面向对象的条条框框,Lambda的标准格式由三个部分组成:

    	(参数类型:参数名称)->{
    		代码体;
    	}
    
    • 1
    • 2
    • 3

    格式说明:

    • (参数类型:参数名称):参数列表
    • (代码体;):方法体
    • ->:箭头,分割参数列表和方法体

    2、原理

    匿名内部类的本质是在编译时生成一个Class文件。xxx$1.class

    Lambda表达式在从程序运行的时候会形成一个类。
    1、在类中新增了一个方法,这个方法的方法体就是Lambda表达式中的代码。
    2、还会形成一个匿名内部类,实现接口,重写抽象方法。
    3、在接口汇总重写方法会调用新生成的方法。

    而写有Lambda表达式的class文件,无法通过反编译工具查看,需要通过jdk自带的一个工具:javap 对字节码进行反汇编操作。

    javap -c -p 文件名.class
    
    -c:表示对代码进行反汇编
    -p:显示所有的类和成员
    
    • 1
    • 2
    • 3
    • 4

    3、Lambda表达式的省略写法

    在lambda表达式的标准写法基础上,可以使用省略写法的规则为:
    1、小括号的参数类型可以省略
    2、如果小括号内有且仅有一个参数,则小括号可以省略
    3、如果大括号内有且仅有一个语句,可以同时省略大括号,return关键字及语句分号

    4、Lambda表达式的适用前提

    Lambda表达式的语法是非常简洁的,但是 Lambda表达式不是随便使用的,使用时有几个条件需要特别注意
    1、方法的参数或局部变量类型必须为接口才能使用Lambda
    2、接口中有且仅有一个抽象方法(@FunctionalInterface)

    5、Lambda和匿名内部类的对比

    Lambda和匿名内部类的对比

    • 所需类型不一样
      1、匿名内部类的类型可以是类、抽象类、接口
      2、Lambda表达式需要的类型必须是接口
    • 抽象方法的数量不一样
      1、匿名内部类所需要得接口中的抽象方法的数量是随意的
      2、Lambda表达式所需的接口中只能有一个抽象方法
    • 实现原理不一样
      1、匿名内部类是在编译后形成一个class
      2、Lambda表达式是在程序运行的时候动态生成calss

    二、函数式接口

    1、Supplier

    ​ 无参有返回值的接口

    @FunctionalInterface
    public interface Supplier<T> {
    
        /**
         * Gets a result.
         *
         * @return a result
         */
        T get();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2、Consumer

    ​ 有参无返回值的接口

    @FunctionalInterface
    public interface Consumer<T> {
    
        /**
         * Performs this operation on the given argument.
         *
         * @param t the input argument
         */
        void accept(T t);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3、Function

    ​ 有参有返回值的接口,Function接口是根据一个类型的数据得到另一个类型的数据,前者称为前置条件,后者称为后置条件。有参数有返回值。

    @FunctionalInterface
    public interface Function<T, R> {
    
        /**
         * Applies this function to the given argument.
         *
         * @param t the function argument
         * @return the function result
         */
        R apply(T t);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    4、Predicate

    ​ 有参,返回值为Boolean的接口

    public interface Predicate<T> {
    
        /**
         * Evaluates this predicate on the given argument.
         *
         * @param t the input argument
         * @return {@code true} if the input argument matches the predicate,
         * otherwise {@code false}
         */
        boolean test(T t);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    三、方法引用

    1、方法引用的格式

    符号表示:::

    符号说明:双冒号为方法引用运算符,而它所在的表达式被称为方法引用

    应用场景:如果Lambda表达式所要实现的方案,已经有其他方法存在相同的方案,那么则可以使用方法引用。

    2、常见的引用方式

    方法引用在JDK8中是相当灵活的,有以下几种方式:

    2.1对象名::方法名

    instanceNmae::methodName

    这是最常见的一种用法。如果一个类中已经存在了一个成员方法,则可以通过对象名引用成员方法。

    1. 被引用的方法,参数要和接口中的抽象方法的参数一样
    2. 当接口抽象方法有返回值时,被引用的方法也必须有返回值

    2.2类名::静态方法名

    ClassName::staticMethodName

    也是比较常用的方式。

    2.3类名::普通方法(引用实例方法)

    ClassName::methodNmae

    Java面向对象中,类名只能调用静态方法,类名引用实例方法是有前提的,实际上是拿第一个参数作为方法的调用者。

    2.4类名::构造器

    ClassName::new 类名::new 调用的构造器

    由于构造器的名称和类名完全一致,所以构造器引用使用::new

    的格式。

    2.5数组::构造器

    TypeName[]::new String[]::new 调用数组的构造器

    小结:方法引用是对Lambda表达式符合特定情况下的一种缩写形式,它使得我们的Lambda表达式更加的精简,也可以理解为Lambda表达式的缩写形式,不过要注意的是方法引用只能引用已经存在的方法。

    四、Stream API

    1、Stream流式思想概述

    注意:Stream和IO流(InputStream/OutputStream)没有任何关系。

    Stream流式思想类似于工厂车间的"生产流水线",Stream流不是一种数据结构,不保存数据,而是对数据进行加工处理。Stream可以看作是流水线上的一个工序。在流水线上,通过多个工序让一个原材料加工成一个商品。

    Stream API能让我们快速完成许多复杂的操作,如筛选、切片、映射、查找、去除重复、统计、匹配和归约。

    2、Stream流获取方式

    2.1 根据Collection获取

    ​ 首先,java.util.Collection接口中加入了default方法stream,也就是说collection接口下的所有的实现都可以通过Stream方法来获取Stream流。

    public static void main(String[] args) {
        List<string> list = new ArrayList<>();
        list.stream();
        Set<string> set = new Hashset<>();
        set.stream();
        vector vector = new vector();
        vector.stream();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    但是Map接口并没有实现Collection接口,这时我们可以根据Map获取对应的key value的集合。

    public static void main(String[] args) {
        HashMap<Object, Object> map = new HashMap<>();
        Stream<Object> stream = map.keySet().stream();//key
        Stream<Object> stream1 = map.values().stream();//value
        Stream<Map.Entry<Object, Object>> stream2 = map.entrySet().stream();//entry
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2.2 根据Stream的of方法

    ​ 在实际开发中我们不可避免的还是会操作到数组中的数据,由于数组对象不可能添加默认方法,所以Stream接口中提供了静态方法of。

    public static void main(String[] args) {
        Stream<String> a1 = Stream.of("a1", "a2", "a3");
        String[] arr1= {"aa","bb","cc"};
        Stream<String> arr11 = Stream.of(arr1);
        Integer[] arr2 = {1,2,3,4};
        Stream<Integer> arr21 = Stream.of(arr2);
        arr21.forEach(System.out::println);
    
        //注意,基本数据类型的数组是不行的
        int[] arr3 = {1,2,3,4};
        Stream.of(arr3).forEach(System.out::println);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    3、Stream常用方法介绍

    Stream常用方法

    Stream流模型的操作很丰富,这里介绍一些常用的API。这些方法可以被分成两种:

    方法名方法作用返回值类型方法种类
    count统计个数long终结
    forEach逐级处理void终结
    filter过滤Stream函数拼接
    limit取用前几个Stream函数拼接
    skip跳过前几个Stream函数拼接
    map映射Stream函数拼接
    concat组合Stream函数拼接

    终结方法: 返回值类型不再是Stream类型的方法,不再支持链式调用。本小节中,终结方法包括count和forEach方法。

    非终结方法: 返回值类型仍然是Stream类型的方法,支持链式调用。(除了终结方法外,区域方法均为非终结方法)

    Stream注意事项(重要)

    1. Stream只能操作一次
    2. Stream方法返回的是新的流
    3. Stream不调用终结方法,中间的操作不会执行

    3.1 forEach

    forEach用来遍历流中的数据的

    void forEach(Consumer<? super T> action);
    
    • 1

    该方法接受一个Consumer接口,会将每一个流元素交给函数处理

    public static void main(String[] args) {
        Stream.of("a1", "a2", "a3").forEach(System.out::println);;
    }
    
    • 1
    • 2
    • 3

    3.2 count

    Stream流中的count方法用来统计其中的元素个数

    long count();
    
    • 1

    该方法返回一个long值,代表元素的个数

    public static void main(String[] args) {
        System.out.println(Stream.of("a1", "a2", "a3").count());
    }
    
    • 1
    • 2
    • 3

    3.3 filter

    filter方法的作用是用来过滤数据的。返回符合条件的数据。可以通过filter方法将一个流转换成另一个子集流。

    Stream<T> filter(Predicate<? super T> predicate);
    
    • 1

    该接口接受一个Predicate函数式接口参数作为筛选条件

    public static void main(String[] args) {
        Stream.of("a1", "a2", "a3", "b1", "b2", "b3")
                .filter((s) -> s.contains("b"))
                .forEach(System.out::println);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    输出:

    b1
    b2
    b3
    
    • 1
    • 2
    • 3

    3.4 limit

    limit方法可以对流进行截取处理,只取前n个数据

    Stream<T> limit(long maxSize);
    
    • 1

    参数是一个long类型的数值,如果集合当前长度大于参数就进行截取,否则不操作:

    public static void main(String[] args) {
        Stream.of("a1", "a2", "a3", "b1", "b2", "b3")
                .limit(5)
                .forEach(System.out::println);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    输出:

    a1
    a2
    a3
    b1
    b2
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3.5 skip

    如果希望跳过前面几个元素,可以使用skip方法获取一个截取之后的新流。

    Stream<T> skip(long n);
    
    • 1

    操作:

    public static void main(String[] args) {
            Stream.of("a1", "a2", "a3", "b1", "b2", "b3")
                    .skip(3)
                    .forEach(System.out::println);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    输出:

    b1
    b2
    b3
    
    • 1
    • 2
    • 3

    3.6 map

    如果我们需要将流中的元素映射到另一个流中,可以使用map方法:

    <R> Stream<R> map(Function<? super T, ? extends R> mapper);
    
    • 1

    在这里插入图片描述

    该接口需要一个Function函数式接口参数,可以将当前流中的T类型数据转换为另一种R类型数据。

    public static void main(String[] args) {
            Stream.of("1", "2", "3", "4", "5", "6")
    //                .map(msg -> Integer.parseInt(msg))效果等同于下面
                    .map(Integer::parseInt)
                    .forEach(System.out::println);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.7 sorted

    如果需要将数据排序,可以使用sorted方法:

    Stream<T> sorted();
    
    • 1

    在使用的时候可以根据自然规则排序,也可以通过比较器来指定对应的排序规则

    public static void main(String[] args) {
            Stream.of("1", "22", "23", "2", "4", "6")
    //                .map(msg -> Integer.parseInt(msg))效果等同于下面
                    .map(Integer::parseInt)
    //                .sorted()//根据数据的自然顺序排序
                    .sorted((o1,o2) -> o2-o1)//根据比较器指定排序规则
                    .forEach(System.out::println);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3.8 distinct

    如果要去掉重复数据,可以使用distinct方法:

    Stream<T> distinct();
    
    • 1

    在这里插入图片描述

    Stream流中的distinct方法对于基本数据类型是可以直接去重的,对于自定义类型,我们需要去重写hasCode和equals方法来移除重复元素。

    public static void main(String[] args) {
            Stream.of("1", "22", "22", "2", "4", "6")
    //                .map(msg -> Integer.parseInt(msg))效果等同于下面
                    .map(Integer::parseInt)
    //                .sorted()//根据数据的自然顺序排序
                    .sorted((o1,o2) -> o2-o1)//根据比较器指定排序规则
                    .distinct()//去掉重复的记录
                    .forEach(System.out::println);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3.9 reduce方法

    如果需要将所有数据归纳得到一个数据,可以使用reduce方法

    T reduce(T identity, BinaryOperator<T> acumulator);
    
    • 1

    使用:

    public static void main(String[] args) {
            Integer sum = Stream.of(1, 2, 3, 4)
                    //identity默认值
                    //第一次的时候会将默认值赋给x
                    //之后每次会将上一次的操作结果赋给x y就是每次从数据中获取的元素
                    .reduce(0, (x, y) -> {
                        System.out.println("x=" + x + ",y=" + y);
                        return x + y;
                    });
            System.out.println(sum);
            //获取最大值
            Integer max = Stream.of(1, 2, 3, 4)
                    .reduce(0, (x, y) -> {
                        return x > y ? x : y;
                    });
            System.out.println("最大值:"+max);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    结果:

    x=0,y=1
    x=1,y=2
    x=3,y=3
    x=6,y=4
    10
    最大值:4
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.10 map和reduce的组合

    在实际开发中,我们会将map和reduce一块使用

    public static void main(String[] args) {
            Integer sumAge = Stream.of(
                            new Person("张三", 18),
                            new Person("李四", 19),
                            new Person("王五", 20),
                            new Person("赵六", 21)
    //        ).map(p->p.getAge)
                    ).map(Person::getAge)//实现数据类型转换,符合reduce对数据的要求
    //                .reduce(0,(x,y)->x+y);
                    .reduce(0, Integer::sum);//reduce实现数据的处理
            System.out.println(sumAge);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    3.11 mapTolnt

    如果需要将Stream中的Integer类型转换为int类型,可以使用mapToInt方法

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BW7JlAZq-1658798400699)(C:\Users\yfzheng.ARCVIDEO\AppData\Roaming\Typora\typora-user-images\image-20220726090439598.png)]

    使用:

    public static void main(String[] args) {
        //Integer比int占用的内存多很多,在Stream流操作中会自动装箱和拆箱操作
        Integer[] arr = {1,2,3,4,5,6,7,8};
        Stream.of(arr)
                .filter(i->i>0)
                .forEach(System.out::println);
        //为了提高代码的效率,我们可以先将流中Integer数据转换为int数据,然后再操作
        IntStream intStream = Stream.of(arr)
                .mapToInt(Integer::intValue);
        intStream.filter(i->i>3)
                .forEach(System.out::println);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    3.12 concat

    如果两个流,希望合并成为一个流,那么可以使用Stream接口的静态方法concat

    public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) {
        Objects.requireNonNull(a);
        Objects.requireNonNull(b);
    
        @SuppressWarnings("unchecked")
        Spliterator<T> split = new Streams.ConcatSpliterator.OfRef<>(
                (Spliterator<T>) a.spliterator(), (Spliterator<T>) b.spliterator());
        Stream<T> stream = StreamSupport.stream(split, a.isParallel() || b.isParallel());
        return stream.onClose(Streams.composedClose(a, b));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    使用:

    public static void main(String[] args) {
        Stream<String> stream1 = Stream.of("a", "b", "c");
        Stream<String> stream2 = Stream.of("x", "y", "z");
        //通过concat方法将两个流合并成为一个新的流
        Stream.concat(stream1,stream2).forEach(System.out::print);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    输出:

    abcxyz
    
    • 1

    4、例子

    统计个数:list.stream().count

    去重: .distinct()

    遍历: .forEach(a-> System.out.println(a))

    过滤: .filter

    限制个数: .limit

    跳过: .skip

    map映射: .map(a->a+" ")

    连接多个数组:Ints.concat()

    list转字符串:Joiner.on(“,”).join()

    map转字符串:Joiner.on(" , “).withKeyValueSeparator(” = ").join()

    list转string:跳过 null:Joiner.on(“,”).skipNulls().join()

    list转string:null变为其他值:Joiner.on(“,”).useForNull(“”).join()

    根据-切割,将string转为list:Splitter.on(“-”).trimResults().splitToList()

    string转为map:Splitter.on(“,”).withKeyValueSeparator(“=”).split()

    多个字符进行分割:Splitter.onPattern(“[.|,]”)

    每隔n字符进行分割:Splitter.fixedLength(n).splitToList()

    取两个集合的并集并去重:listAll.stream().distinct().collect(toList())

    List集合去重:list.stream().distinct().collect(toList())

    List集合去重:List.stream().collect(collectingAndThen(toCollection(() -> new TreeSet<>(Comparator.comparing(User::getName))), ArrayList::new))

    匹配: anyMatch(),只要有一个元素匹配传入的条件,就返回 true。
    allMatch(),只有有一个元素不匹配传入的条件,就返回 false;如果全部匹配,则返回 true。
    noneMatch(),只要有一个元素匹配传入的条件,就返回 false;如果全部不匹配,则返回 true。

    5、Stream结果收集

    5.1 结果收集到集合中

    操作:

    public static void main(String[] args) {
            /**
             * Stream结果收集
             * 收集到集合中
             */
            //收集到List集合中
    //        Stream stream = Stream.of("aa", "bb", "cc");
            List<String> list = Stream.of("aa", "bb", "cc", "aa")
                    .collect(Collectors.toList());
            System.out.println(list);
            //收集到Set集合中
            Set<String> set = Stream.of("aa", "bb", "cc", "aa")
                    .collect(Collectors.toSet());
            System.out.println(set);
    
            //如果需要获取的类型为具体的实现,比如:ArrayList HashSet
            ArrayList<String> arrayList = Stream.of("aa", "bb", "cc", "aa")
    //                .collect(Collectors.toCollection(() -> new ArrayList<>()));
            .collect(Collectors.toCollection(ArrayList::new));
            System.out.println(arrayList);
            HashSet<String> hashSet = Stream.of("aa", "bb", "cc", "aa")
                    .collect(Collectors.toCollection(HashSet::new));
            System.out.println(hashSet);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    输出:

    [aa, bb, cc, aa]
    [aa, bb, cc]
    [aa, bb, cc, aa]
    [aa, bb, cc]
    
    • 1
    • 2
    • 3
    • 4

    5.2 结果收集到数组中

    Stream中提供了toArray方法来将结果放到一个数组中,返回值类型是Object[],如果我们要指定返回的类型,那么可以使用另一个重载的toArry(IntFunction f)方法

    操作:

    public static void main(String[] args) {
        /**
         * Stream结果收集收集到数组中
         */
        Object[] objects = Stream.of("aa", "bb", "cc", "aa")
                .toArray();//返回的数组中的元素是Object类型
        System.out.println(Arrays.toString(objects));
        //如果我们需要指定返回的数组中的元素类型
        String[] strings = Stream.of("aa", "bb", "cc", "aa")
                .toArray(String[]::new);
        System.out.println(Arrays.toString(strings));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    输出:

    [aa, bb, cc, aa]
    [aa, bb, cc, aa]
    
    • 1
    • 2

    5.3 对流中的数据做分区操作

    Collectors.partitioningBy会根据值是否为true,把集合的数据分割为两个列表,一个true列表,一个false列表
    在这里插入图片描述

    5.4 对流中的数据做拼接

    Collector.joining会根据指定的连接符,将所有的元素连接成一个字符串

    6、 并行的Stream流

    6.1 串行的Stream流

    我们前面使用的Stream流都是串行,也就是在一个线程上面执行

    public static void main(String[] args) {
        Stream.of(5,4,1,2,5,5,8)
                .filter(s->{
                    System.out.println(Thread.currentThread()+""+s);
                    return s>3;
                }).count();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    输出:

    Thread[main,5,main]5
    Thread[main,5,main]4
    Thread[main,5,main]1
    Thread[main,5,main]2
    Thread[main,5,main]5
    Thread[main,5,main]5
    Thread[main,5,main]8
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    6.2 并行流

    parallelStream其实就是一个并行执行的流,它通过默认的ForkJoinPool,可以提高多线程任务的速度。

    获取并行流:

    public static void main(String[] args) {
        /**
         * 功能描述:获取并行流的两种方式
         */
        ArrayList<Integer> list = new ArrayList<>();
        //通过list接口直接获取并行流
        Stream<Integer> integerStream = list.parallelStream();
        //将已有的串行流转换为并行流
        Stream<Integer> parallel = Stream.of(1, 2, 3).parallel();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    并行流操作:

    public static void main(String[] args) {
            Stream.of(1, 2, 3, 4, 1)
                    .parallel()//将流转换为并发流,Stream处理的时候就会通过多线程处理
                    .filter(s -> {
                        System.out.println(Thread.currentThread() + "s=" + s);
                        return s > 2;
                    }).count();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    输出:

    Thread[main,5,main]s=3
    Thread[main,5,main]s=1
    Thread[main,5,main]s=4
    Thread[ForkJoinPool.commonPool-worker-1,5,main]s=2
    Thread[main,5,main]s=1
    
    • 1
    • 2
    • 3
    • 4
    • 5

    Stream并行处理的过程会分而治之,也就是将一个大的任务切分成了多个小任务,这表示每个任务都是线程操作。

    五、新日期时间API

    JDK 8中增加了一套全新的日期时间API,这套API设计合理,是线程安全的。新的日期及时间API位于java.time包中,下面是一些关键类。

    • LocalDate :表示日期,包含年月日,格式为2019-10-16
    • LocalTime:表示时间,包含时分秒,格式为16:38:54.158549300
    • LocalDateTime:表示日期时间,包含年月日,时分秒,格式为2018-09-06T15:33:56.750
    • DateTimeFormatter :日期时间格式化类。
    • Instant:时间戳,表示一个特定的时间瞬间。
    • Duration:用于计算2个时间(LocalITime, 时分秒)的距离
    • Period:用于计算2个日期(LocalDate,年月日)的距离
    • ZonedDateTime :包含时区的时间

    1、日期LocalDate

    public static void main(String[] args) {
    
            //创建指定的日期
            LocalDate date = LocalDate.of(2022, 2, 22);
            System.out.println("data1 = " + date);
    
            //得到当前的日期
            LocalDate now = LocalDate.now();
            System.out.println("date2 = " + now);
    
            //根据LocalData对象获取对应的日期信息
            System.out.println("年:"+ now.getYear());
            System.out.println("月:"+ now.getMonth());
            System.out.println("月:"+ now.getMonthValue());
            System.out.println("月:"+ now.getMonth().getValue());
            System.out.println("日:"+ now.getDayOfMonth());
            System.out.println("星期:"+ now.getDayOfWeek());
            System.out.println("星期:"+ now.getDayOfWeek().getValue());
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    输出:

    date = 2022-02-22
    now = 2022-07-26
    年:2022
    月:JULY
    月:7
    月:7
    日:26
    星期:TUESDAY
    星期:2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    2、时间LocalTime

    public static void main(String[] args) {
        //得到指定的时间
        LocalTime time = LocalTime.of(14,22,31,22222);
        System.out.println("time:"+time);
        //获取当前的时间
        LocalTime now = LocalTime.now();
        System.out.println("now:"+now);
        //获取时间信息
        System.out.println(now.getHour());
        System.out.println(now.getMinute());
        System.out.println(now.getSecond());
        System.out.println(now.getNano());
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    输出:

    time:14:22:31.000022222
    now:14:26:40.822
    14
    26
    40
    822000000
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3、日期时间LocalDateTime

    public static void main(String[] args) {
        //得到指定的日期时间
        LocalDateTime localDateTime =
                LocalDateTime.of(2022,
                        2,
                        22,
                        12,
                        12,
                        12,
                        2222);
        System.out.println("localDateTime:"+localDateTime);
        //获取当前的日期时间
        LocalDateTime now = LocalDateTime.now();
        System.out.println("now:"+now);
        //获取日期时间信息
        System.out.println(now.getYear());
        System.out.println(now.getMonthValue());
        System.out.println(now.getDayOfMonth());
        System.out.println(now.getDayOfWeek().getValue());
        System.out.println(now.getHour());
        System.out.println(now.getMinute());
        System.out.println(now.getSecond());
        System.out.println(now.getNano());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    输出:

    localDateTime:2022-02-22T12:12:12.000002222
    now:2022-07-26T14:34:56.084
    2022
    7
    26
    2
    14
    34
    56
    84000000
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    4、修改、比较

    now.with();//修改
    now.plus();//加上
    now.minus();//减去
    //比较
    now.isAfter();//是否在后
    now.isBefore();//是否在前
    now.isEqual();//相等
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    注意:在进行日期时间修改的时候,原来的LocalDate是不会被修改的,每次操作都是返回了一个新的LocalDate对象,所以在多线程场景下是数据安全的。

    5、格式化和解析操作

    在JDK8中我们可以通过java.time.format.DateTimeFormatter类进行日期的解析和格式化操作。

    public static void main(String[] args) {
        LocalDateTime now = LocalDateTime.now();
        //指定格式  使用系统默认的格式 
        DateTimeFormatter isoLocalDateTime = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
        //将日期时间转换为字符串
        String format = now.format(isoLocalDateTime);
        System.out.println("format = " + format);//2022-07-26T15:01:35.752
    
        //通过ofPattern 方法来指定特定的格式
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String format1 = now.format(dateTimeFormatter);
        System.out.println("format1 = " + format1);//2022-07-26 15:01:35
    
        //将字符串解析为一个  日期时间类型
        LocalDateTime parse = LocalDateTime.parse("1999-06-27 22:55:16", dateTimeFormatter);
        System.out.println("parse = " + parse);//1999-06-27T22:55:16
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    输出:

    format = 2022-07-26T15:01:35.752
    format1 = 2022-07-26 15:01:35
    parse = 1999-06-27T22:55:16
    
    • 1
    • 2
    • 3

    6、时区

     public static void main(String[] args) {
            //获取所有的时区id
    //        ZoneId.getAvailableZoneIds().forEach(System.out::println);
    
            //获取当前时间 中国使用的 东八区的时区,比标准时间早8个小时
            LocalDateTime now = LocalDateTime.now();
            System.out.println("now = " + now);//2022-07-26T15:56:27.623
            //获取标准时间
            ZonedDateTime bz = ZonedDateTime.now(Clock.systemUTC());
            System.out.println("bz = " + bz);//2022-07-26T07:56:27.624Z
            //使用计算机默认的时区,创建日期时间
            ZonedDateTime now1 = ZonedDateTime.now();
            System.out.println("now1 = " + now1);//2022-07-26T15:56:27.625+08:00[Asia/Shanghai]
    
            //使用指定的时区创建日期时间
            ZonedDateTime now2 = ZonedDateTime.now(ZoneId.of("America/Marigot"));
            System.out.println("now2 = " + now2);//2022-07-26T03:59:04.910-04:00[America/Marigot]
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    输出:

    now = 2022-07-26T15:59:04.895
    bz = 2022-07-26T07:59:04.909Z
    now1 = 2022-07-26T15:59:04.909+08:00[Asia/Shanghai]
    now2 = 2022-07-26T03:59:04.910-04:00[America/Marigot]
    
    • 1
    • 2
    • 3
    • 4
  • 相关阅读:
    Java队列相关面试题
    Python系列:彩色日志详解
    钉钉漏洞通知脚本dingtalkBot—配套Automated_bounty_Hunter
    Spring Boot项目开发实战:整合thymeleaf实现数据前端展示
    ICPC焦作站(E、F)+思维+树上dp
    yolov5部署到android studio
    vite+vue3.0 + TypeScript+element-plus环境搭建
    【Hack The Box】linux练习-- Paper
    金仓数据库兼容Oracle exp/imp的导出导入工具手册(2. 概述)
    C/C++/Python图像处理算法实战【3】彩色图像灰度化和二值化处理
  • 原文地址:https://blog.csdn.net/qq_44787933/article/details/125993068