美文网首页
为啥放着Java16不用,都在用Java8?看完Java8的新特

为啥放着Java16不用,都在用Java8?看完Java8的新特

作者: Java架构大仙 | 来源:发表于2021-03-24 21:04 被阅读0次

    函数式接口

    java内置四大核心函数式接口


    image.png

    核心接口子接口


    image.png
    //Consumer<T>消费型接口
        public static void test1(){
            cost(8888, (m) -> System.out.println("共消费:" + m + "元"));
        }
    
        public static void cost(double money,Consumer<Double> con){
            con.accept(money);
        }
        
       //Supplier<T> 供给型接口
        public static void test2(){
            List<Integer> list = getNumList(8, () -> (int)(Math.random() * 100));
            for (Integer integer : list) {
                System.out.println(integer);
            }
        }
    
        //产生指定数量的整数,放入集合中
        public static List<Integer> getNumList(int num,Supplier<Integer> sup){
            List<Integer> list = new ArrayList<>();
    
            for (int i = 0; i < num; i++) {
                Integer n = sup.get();
                list.add(n);
            }
    
            return list;
        }
        
        //Function<T,R> 函数型接口
        public static void test3(){
            String string = strHandler("函数型接口测试 ", (str) -> str.trim().substring(0, 5));
            System.out.println(string);
        }
    
        //用于处理字符串
        public static String strHandler(String str,Function<String, String> fun){
            return fun.apply(str);
        }
        
      //Predicate<T> 断言型接口
        public static void test4(){
            List<String> list = Arrays.asList("hello","Lambda","ok");
            List<String> strList = filterStr(list, (s) -> s.length() > 3);
            for (String string : strList) {
                System.out.println(string);
            }
        }
    
        //将满足条件的字符串,放入集合中
        public static List<String> filterStr(List<String> list, Predicate<String> pre){
            List<String> strList = new ArrayList<>();
    
            for (String str : list) {
                if (pre.test(str)) {
                    strList.add(str);
                }
            }
            return strList;
        }
    

    方法引用与构造器引用

    当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!(实现抽象方法的参数列表,必须与方法引用方法的参数列表保持一致!)方法引用:使用操作符 “::” 将方法名和对象或类的名字分隔开来。
    如下三种主要使用情况:

    • 对象::实例方法
    • 类::静态方法
    • 类::实例方法

    使用注意事项:

    1.Lambda 体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的函数列表和返回值类型保持一致。
    2.若Lambda 参数列表中第一个参数是实例方法调用者,第二个参数是实例方法的参数 可以使用 ClassName :: method

    //对象的引用 :: 实例方法名    
        @Test
        public void test1(){
            PrintStream ps = System.out;
            Consumer<String> con = (str) -> ps.println(str);
            con.accept("Hello World!");
            
            Consumer<String> con2 = ps::println;
            con2.accept("Hello World!");
            
            Consumer<String> con3 = System.out::println;
        }
    
    //类名 :: 静态方法名
        @Test
        public void test2(){
            Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
            Comparator<Integer> com2 = Integer::compare;
        }
    //类名 :: 实例方法名
        @Test
        public void test3(){
            BiPredicate<String, String> bp = (x, y) -> x.equals(y);
            System.out.println(bp.test("abcde", "abcde"));
            
            BiPredicate<String, String> bp2 = String::equals;
            System.out.println(bp2.test("abc", "abc"));
            
            Function<Employee, String> fun = (e) -> e.show();
            System.out.println(fun.apply(new Employee()));
            
            Function<Employee, String> fun2 = Employee::show;
            System.out.println(fun2.apply(new Employee()));
        }
    
    

    构造器引用:

    • 构造器参数列表要与接口中抽象方法的参数列表一致,格式为 类名::new
    • 与函数式接口相结合,自动与函数式接口中方法兼容
    public void test1(){
            Supplier<Employee> sup = () -> new Employee();
            System.out.println(sup.get());
            
            Supplier<Employee> sup1 = Employee::new;
            System.out.println(sup1.get());
        }
    

    数组引用

    • 格式:类型[] :: new
    public void test1(){
            Function<Integer, String[]> fun = (args) -> new String[args];
            String[] strs = fun.apply(10);
            System.out.println(strs.length);
            
            Function<Integer, String[]> fun1 = String[] :: new;
            String[] strs = fun1.apply(20);
            System.out.println(strs.length);
        }
    

    Stream API

    Stream 是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列Stream 自己不会存储元素,不会改变源对象且返回一个持有结果的新Stream,操作是延迟执行的Stream API 提供了一种高效且易于使用的处理数据的方式

    Stream API 的操作步骤:

    1.创建Stream数据源
    2.中间操作
    3.终止操作(终端操作)

    创建Stream

    • 方式一:Java8中的Collection接口被扩展.提供两个获取流的方法

    default Stream stream() : 返回一个顺序流

    default Stream parallelStream() : 返回一个并行流

    注:Collection接口下的所有实现类或者子接口都可以通过 对象.stream() 的方法返回一个流给Stream对象

    • 方式二:Java8中的Arrays的静态方法 stream() 可以获取数组流

    static Stream stream(T[] array)

    注:从数组中获取流可以使用 Arrays.stream(数组名) 来进行获取

    • 方式三:Stream类的静态方法 Stream.of() 通过显示值创建一个流,可接收任意数量的参数

    public static Stream of(T… values) : 返回一个流

    使用 Stream stream = Stream.of(“a”,“b”,“c”) 获取流

    • 方式四:静态方法 Stream.iterate() 和 Stream.generate() 创建无限流

    迭代 public static Stream iterate(final T seed, final UnaryOperator f)

    生成 public static Stream generate(Supplier s)

    public void test1(){
            //1.可以通过Collection系列集合提供的stream() 或parallelStream()
            List<String> list = new ArrayList<>();
            Stream<String> stream = list.stream();
    
            //2.通过Arrays中静态方法 stream() 获取数组流
            Person[] persons = new Person[10];
            Stream<Person> stream2 = Arrays.stream(persons);
    
            //3.通过Stream类中的静态方法 of()
            Stream<String> stream3 = Stream.of("a","b","c");
    
            //4.创建无限流
            //迭代
            Stream<Integer> stream4 = Stream.iterate(0, (x) -> x + 2);
            stream4.limit(8).forEach(System.out :: println);
    
            //生成
            Stream.generate(() -> Math.random()).limit(6)
                .forEach(System.out :: println);
        }    
    

    中间操作

    筛选与切片方法

    • filter(Perticate p) — 接收 Lambda , 从流中排除某些元素
    • distinct() — 筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
    • limit(Long n) — 截断流,使其元素不超过给定数量
    • skip(Long n) —— 跳过元素,返回一个扔掉了前 n 个元素的流,若流中元素不足 n 个,则返回一个空流,与 limit(n) 互补

    映射方法

    • map(Function f) — 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
    • flatMap(Function f) — 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
    • mapToDouble(ToDoubleFunction f) — 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 DoubleStream
    • mapToInt(ToIntFunction f) — 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的IntStream
    • mapToLong(ToLongFunction f) — 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的LongStream

    排序方法

    • sorted() — 产生一个新流,按自然顺序排序
    • sorted(Comparator com) — 产生一个新流,按比较器顺序定制排序
    /**
         * Stream API的中间操作
         */
        public class TestSteamAPI2 {
    
            List<Person> persons = Arrays.asList(
                    new Person(2, "钱四", 24),
                    new Person(1, "张三", 33),
                    new Person(2, "李四", 24),
                    new Person(3, "王五", 65),
                    new Person(4, "赵六", 26),
                    new Person(4, "赵六", 26),
                    new Person(5, "陈七", 27)
            );
    
            //内部迭代,由Stream API完成
            @Test
            public void test1(){
                //中间操作,不会执行任何操作
                Stream<Person> stream = persons.stream()
                                            .filter((e) -> {
                                                System.out.println("Stream的中间操作");
                                                return e.getAge() > 25;
                                            });
                //终止操作,一次性执行全部内容,即"惰性求值"
                stream.forEach(System.out :: println);
            }
    
            //外部迭代
            @Test
            public void test2(){
                Iterator<Person> iterator = persons.iterator();
                while (iterator.hasNext()) {
                    System.out.println(iterator.next());
                }
            }
    
            //limit,截断
            @Test
            public void test3(){
                persons.stream()
                    .filter((e) -> {
                        System.out.println("迭代操作"); //短路
                        return e.getAge() > 24;
                    })
                    .limit(2)
                    .forEach(System.out :: println);
            }
    
            //跳过skip,distinct去重(要重写equals和hashcode)
            @Test
            public void test4(){
                persons.stream()
                        .filter((e) -> e.getAge() > 23)
                        .skip(2)
                        .distinct()
                        .forEach(System.out :: println);
            }
    
            //映射
            @Test
            public void test5(){
                List<String> list = Arrays.asList("a","bb","c","d","e");
    
                list.stream().map((str) -> str.toUpperCase())
                    .forEach(System.out :: println);
                System.out.println("---------------");
    
                persons.stream().map((Person :: getName)).forEach(System.out :: println);
                System.out.println("---------------");
    
                Stream<Stream<Character>> stream = list.stream()
                    .map(TestSteamAPI2 :: filterCharacter);
    
                stream.forEach((s) -> {
                    s.forEach(System.out :: println);
                });
                System.out.println("-----------------");
    
                //flatMap
                Stream<Character> stream2 = list.stream()
                    .flatMap(TestSteamAPI2 :: filterCharacter);
                stream2.forEach(System.out :: println);
            }
    
            //处理字符串
            public static Stream<Character> filterCharacter(String str){
                List<Character> list = new ArrayList<>();
    
                for (Character character : str.toCharArray()) {
                    list.add(character);
                }
                return list.stream();
            }
    
            //排序
            @Test
            public void test6(){
                List<String> list = Arrays.asList("bb","c","aa","ee","ddd");
    
                list.stream()
                    .sorted() //自然排序
                    .forEach(System.out :: println);
                System.out.println("------------");
    
                persons.stream()
                        .sorted((p1,p2) -> {
                            if (p1.getAge() == p2.getAge()) {
                                return p1.getName().compareTo(p2.getName());
                            } else {
                                return p1.getAge() - p2.getAge();
                            }
                        }).forEach(System.out :: println);
    
            }
    
        }
    

    终止操作

    查找与匹配方法

    • allMatch(Perticate p) — 检查是否匹配所有元素
    • anyMatch(Perticate p) — 检查是否至少匹配一个元素
    • noneMatch(Perticate p) — 检查是否没有匹配的元素
    • findFirst() — 返回第一个元素
    • findAny() — 返回当前流中的任意元素
    • count() — 返回流中元素的总个数
    • max(Comparator c) — 返回流中最大值
    • min(Comparator c) — 返回流中最小值
    • forEach(Consumer c) — 内部迭代(使用Collection接口需用户做迭代成为外部迭代)

    归约方法

    • reduce(T identity, BinaryOperator b) — 可以将流中元素反复结合起来,得到一个值返回T
    • reduce(BinaryOperator b) — 可以将流中元素反复结合起来,得到一个值,返回Optional

    收集方法

    collect(Collector c)——将流转换为其他形式,接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法

    /**
         * Stream API的终止操作
         */
        public class TestSteamAPI3 {
    
            List<Person> persons = Arrays.asList(
                    new Person(2, "钱四", 24,Status.YOUNG),
                    new Person(1, "张三", 23,Status.YOUNG),
                    new Person(2, "李四", 24,Status.YOUNG),
                    new Person(3, "王五", 65,Status.OLD),
                    new Person(4, "赵六", 26,Status.MIDDLE),
                    new Person(4, "赵六", 56,Status.OLD),
                    new Person(5, "陈七", 27,Status.MIDDLE)
            );
    
            //查找与匹配
            @Test
            public void test1(){
                boolean b = persons.stream()
                                    .allMatch((e) -> e.getStatus().equals(Status.YOUNG));
                System.out.println(b);
    
                boolean b2 = persons.stream()
                        .anyMatch((e) -> e.getStatus().equals(Status.YOUNG));
                System.out.println(b2);
    
                boolean b3 = persons.stream()
                        .noneMatch((e) -> e.getStatus().equals(Status.MIDDLE));
                System.out.println(b3);
    
                Optional<Person> op = persons.stream()
                        .sorted((e1,e2) -> Integer.compare(e1.getAge(), e2.getAge()))
                        .findFirst();
                System.out.println(op.get());
    
                Optional<Person> optional = persons.stream()
                        .filter((e) -> e.getStatus().equals(Status.OLD))
                        .findAny();
                System.out.println(optional.get());
            }
    
            //最大,最小
            @Test
            public void test2(){
                long count = persons.stream()
                        .count();
                System.out.println(count);
    
                Optional<Person> optional = persons.stream()
                        .max((e1,e2) -> Integer.compare(e1.getId(), e2.getId()));
                System.out.println(optional.get());
    
                Optional<Integer> op = persons.stream()
                        .map(Person :: getAge)
                        .min(Integer :: compare);
                System.out.println(op.get());
            }
    
            //归约
            @Test
            public void test3(){
                List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8);
    
                Integer sum = list.stream()
                    .reduce(0, (x,y) -> x + y);
                System.out.println(sum);
                System.out.println("------------");
    
                Optional<Integer> optional = persons.stream()
                        .map(Person :: getAge)
                        .reduce(Integer :: sum);
                System.out.println(optional.get());
            }
    
            //收集
            @Test
            public void test4(){
                List<String> list = persons.stream()
                        .map(Person :: getName)
                        .collect(Collectors.toList());
                list.forEach(System.out :: println);
                System.out.println("------------");
    
                Set<String> set = persons.stream()
                        .map(Person :: getName)
                        .collect(Collectors.toSet());
                set.forEach(System.out :: println);
                System.out.println("------------");
    
                HashSet<String> hashSet = persons.stream()
                        .map(Person :: getName)
                        .collect(Collectors.toCollection(HashSet :: new));
                hashSet.forEach(System.out :: println);
            }
    
            @Test
            public void test5(){
                Long count = persons.stream()
                        .collect(Collectors.counting());
                System.out.println("总人数="+count);
                System.out.println("----------------");
    
                //平均值
                Double avg = persons.stream()
                        .collect(Collectors.averagingInt(Person :: getAge));
                System.out.println("平均年龄="+avg);
                System.out.println("---------------");
    
                //总和
                Integer sum = persons.stream()
                        .collect(Collectors.summingInt(Person :: getAge));
                System.out.println("年龄总和="+sum);
                System.out.println("----------------");
    
                //最大值
                Optional<Person> max = persons.stream()
                        .collect(Collectors.maxBy((e1,e2) -> Integer.compare(e1.getAge(), e2.getAge())));
                System.out.println("最大年龄是"+max.get());
                System.out.println("----------------");
    
                //最小值
                Optional<Person> min = persons.stream()
                        .collect(Collectors.minBy((e1,e2) -> Integer.compare(e1.getAge(), e2.getAge())));
                System.out.println("最小年龄是"+min.get());
            }
    
            //分组
            @Test
            public void test6(){
                Map<Status, List<Person>> map = persons.stream()
                        .collect(Collectors.groupingBy(Person :: getStatus));//根据年龄层分组
                System.out.println(map);
            }
    
            //多级分组
            @Test
            public void test7(){
                Map<Status, Map<String, List<Person>>> map = persons.stream()
                        .collect(Collectors.groupingBy(Person :: getStatus ,Collectors.groupingBy((e) -> {
                            if (e.getId()%2 == 1) {
                                return "单号";
                            } else {
                                return "双号";
                            } 
                        })));
                System.out.println(map);
            }
    
            //分区
            @Test
            public void test8(){
                Map<Boolean, List<Person>> map = persons.stream()
                        .collect(Collectors.partitioningBy((e) -> e.getAge() > 30));
                System.out.println(map);
            }
    
            //IntSummaryStatistics
            @Test
            public void test9(){
                IntSummaryStatistics iss = persons.stream()
                        .collect(Collectors.summarizingInt(Person :: getAge));
                System.out.println(iss.getSum());
                System.out.println(iss.getAverage());
                System.out.println(iss.getMax());
            }
    
            @Test
            public void test10(){
                String str = persons.stream()
                        .map(Person :: getName)
                        .collect(Collectors.joining(",","人员名单:","等"));
                System.out.println(str);
            }
        }
    

    并行流与串行

    为了适应目前多核机器的时代,提高系统CPU、内存的利用率,在jdk1.8新的stream包中针对集合的操作也提供了并行操作流和串行操作流。并行流就是把内容切割成多个数据块,并且使用多个线程分别处理每个数据块的内容。Stream api中声明可以通过parallel()与sequential()方法在并行流和串行流之间进行切换,jdk1.8并行流使用的是fork/join框架进行并行操作
    注:使用并行流并不是一定会提高效率,因为jvm对数据进行切片和切换线程也是需要时间的。所以数据量越小,串行操作越快;数据量越大,并行操作效果越好

    /* FrokJoin框架
         */
        public class ForkJoinCalculate extends RecursiveTask<Long>{
            private static final long serialVersionUID = 1L;
    
            private long start;
            private long end;
    
            private static final long THRESHOLD = 10000;
    
            public ForkJoinCalculate() {
    
            }
    
            public ForkJoinCalculate(long start, long end) {
                this.start = start;
                this.end = end;
            }
    
            @Override
            protected Long compute() {
                long length = end - start ;
                if (length <= THRESHOLD) {
                    long sum = 0;
                    for (long i = start; i <= end; i++) {
                        sum += i;
                    }
                    return sum;
                }else {
                    long middle = (start + end) / 2; 
                    ForkJoinCalculate left = new ForkJoinCalculate();
                    left.fork();//拆分子任务,同时压入线程队列
    
                    ForkJoinCalculate right = new ForkJoinCalculate();
                    right.fork();
                    return left.join() + right.join();
                }
            }
    
        }
    
    public class TestForkJoin {
    
            /**
             * FrokJoin框架
             */
            @Test
            public void test1(){
                Instant start = Instant.now();
    
                ForkJoinPool pool = new ForkJoinPool();
                ForkJoinTask<Long> task = new ForkJoinCalculate(0,10000000000L);
                Long sum = pool.invoke(task);
                System.out.println(sum);
    
                Instant end = Instant.now();
                System.out.println(Duration.between(start,end).toMillis());
            }
    
            /**
             * for循环
             */
            @Test
            public void test2(){
                Instant start = Instant.now();
                long sum = 0L;
    
                for (long i = 0; i <= 10000000000L; i++) {
                    sum += i;
                }
                System.out.println(sum);
    
                Instant end = Instant.now();
                System.out.println(Duration.between(start, end).toMillis());
            }
    
            /**
             * Java8并行流
             */
            @Test
            public void test3(){
                Instant start = Instant.now();
                LongStream.rangeClosed(0, 10000000000L)
                            .parallel()
                            .reduce(0,Long :: sum);
                Instant end = Instant.now();
                System.out.println(Duration.between(start, end).toMillis());
            }
        }
    

    接口中的默认方法与静态方法

    //jdk1.8以前接口中的变量必须是public static final的,方法也必须是public的,所以下面的定义是等价的
    public interface MyService {
        public static final String KEY = "hello world";
        String key = "hello world";
        
        public abstract void sayHello();
        void sayHi();
    }
    //但是从jdk1.8开始,这种现象有了改变,jdk添加了接口的默认方法和静态方法,使用如下方式定义
    public interface MyService {
    
        /* 静态方法 */
        static void method1(){
            System.out.println("这个是静态方法,调用方式为:MyService.method1()");
        }
        /* 默认方法 */
        default void method2(){
            System.out.println("这个是默认方法,调用方式为MyService实例.method2()");
        }
    }
    
    

    注:由于Java支持一个实现类可以实现多个接口,如果多个接口中存在同样的static和default方法会怎么样呢?
    如果有两个接口中的静态方法一模一样,并且一个实现类同时实现了这两个接口,此时并不会产生错误,因为jdk8只能通过接口类调用接口中的静态方法,所以对编译器来说是可以区分的。但是如果两个接口中定义了一模一样的默认方法,并且一个实现类同时实现了这两个接口,那么必须在实现类中重写默认方法,否则编译失败

    新时间日期API

    原有日期api的缺点

    • 从jdk1.1开始创建,日期处理没有规范,处于多个包中比如:java.util.Date,java.text.java.text.DateFormat等
    • 现有的日期api存在多线程的线程安全问题(可通过比如ThreadLocal等方式规避)

    新日期api简介

    优势新日期api是线程安全的,统一放在java.time及其子包中,关注点分离,对于机器使用的时间戳和人可读的日期进行了类的分类

    java.time及其子包说明

    • java.time包:这是新的Java日期/时间API的基础包,所有的主要基础类都是这个包的一部分,如:LocalDate, LocalTime, LocalDateTime, Instant, Period, Duration等等。所有这些类都是不可变的和线程安全的,在绝大多数情况下,这些类能够有效地处理一些公共的需求
    • java.time.chrono包:这个包为非ISO的日历系统定义了一些泛化的API,我们可以扩展AbstractChronology类来创建自己的日历系统
    • java.time.format包:这个包包含能够格式化和解析日期时间对象的类,在绝大多数情况下,我们不应该直接使用它们,因为java.time包中相应的类已经提供了格式化和解析的方法
    • java.time.temporal包:这个包包含一些时态对象,我们可以用其找出关于日期/时间对象的某个特定日期或时间,比如说,可以找到某月的第一天或最后一天。你可以非常容易地认出这些方法,因为它们都具有“withXXX”的格式
    • java.time.zone包:这个包包含支持不同时区以及相关规则的类
    public class LocalDateTimeTest {
        /* localDate/localtime/localdateTime */
        @Test
        public void test1(){
            //获取当前日期时间
            LocalDateTime ldt = LocalDateTime.now();
            System.out.println(ldt);
            //按照指定时间生成日期
            LocalDateTime ldt1 = LocalDateTime.of(2020,12,30,1,2,3);
            System.out.println(ldt1);
            //指定时间+2年
            System.out.println(ldt.plusYears(2));
            //指定时间-3月
            LocalDateTime ldt2 = ldt.minusMonths(3);
            System.out.println(ldt2);
            System.out.println(ldt.getYear());//获取年份
    
            System.out.println(LocalDate.now());//获取日期
        }
    
        /* 时间戳 (使用Unix元年 1970年1月1日 00:00:00到现在的毫秒数 ) */
        @Test
        public void test2(){
            Instant ins = Instant.now();  //默认使用UTC时区
            System.out.println(ins+",,,"+ins.getEpochSecond());
    
            OffsetDateTime odt = ins.atOffset(ZoneOffset.ofHours(8));//中国在东八区
            System.out.println(odt);
    
            Instant ins1 = Instant.ofEpochSecond(5);
            System.out.println(ins1);  //1970-01-01T00:00:05Z 从Unix元年偏移5s
        }
    
        /**
         * Duration : 用于计算两个“时间”间隔
         * Period : 用于计算两个“日期”间隔
        * */
        @Test
        public void test3() throws InterruptedException {
            Instant ins1 = Instant.now();
            Thread.sleep(1000);
            Instant ins2 = Instant.now();
            System.out.println("两个时间的间隔为--》"+Duration.between(ins1,ins2)); //两个时间的间隔为--》PT1S
    
            LocalDate date1 = LocalDate.of(2011,3,5);
            LocalDate date2 = LocalDate.now();
            Period pe = Period.between(date1,date2);
            System.out.println("两个日期的间隔为--》"+ pe+",,间隔的年为--》"+pe.getYears()); //两个日期的间隔为--》P6Y18D,,间隔的年为--》6
        }
    
        /* 时间校正器   TemporalAdjuster       */
        @Test
        public void test4(){
            LocalDateTime ldt = LocalDateTime.now();
            System.out.println("今天几号--> "+ldt.getDayOfMonth()); //今天几号--> 23
            System.out.println("下个星期天是几号--》"+ ldt.with(TemporalAdjusters.next(DayOfWeek.SUNDAY))); //下个星期天是几号--》2017-03-26T18:36:30.477
    
            // 自定义下一个工作日
            LocalDateTime dateTime = ldt.with((temporal)->{
                LocalDateTime lt = (LocalDateTime)temporal;
                DayOfWeek dow = lt.getDayOfWeek();
                if(DayOfWeek.FRIDAY.equals(dow)){
                    return lt.plusDays(3);
                }else if(DayOfWeek.SATURDAY.equals(dow)){
                    return lt.plusDays(2);
                }else{
                    return lt.plusDays(1);
                }
            });
            System.out.println("下个工作日是--》"+dateTime);  //下个工作日是--》2017-03-24T22:42:31.789
        }
    
        /* 格式化日期 */
        @Test
        public void test5(){
            // 自定义格式,当然也可以使用默认指定的格式
            DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            LocalDateTime ldt = LocalDateTime.now();
            System.out.println(format.format(ldt));  //2017-03-23 22:49:37
    
            //字符串转日期
            LocalDateTime ldt2 = LocalDateTime.parse("2017-11-12 23:10:05",format);
            System.out.println(ldt2); //2017-11-12T23:10:05
        }
    
        /* 带时区的日期  ZonedDate、ZonedTime、ZonedDateTime */
        @Test
        public void test6(){
            LocalDateTime ldt1 = LocalDateTime.now(ZoneId.of("Asia/Shanghai")); //Asia/shanghai time ->2017-03-23T22:57:21.084
            System.out.println("Asia/shanghai time ->"+ldt1);
    
            ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("America/Marigot"));
            System.out.println(zdt); //2017-03-23T10:59:43.708-04:00[America/Marigot]
            System.out.println(zdt.toLocalDateTime());//2017-03-23T11:00:49.177 转换为当前时区时间
    
            System.out.println("------------------------------------------------");
            //获取时区ID列表
            //ZoneId.getAvailableZoneIds().stream().forEach(System.out::println);
        }
    }
    

    Optional

    最大化减少空指针异常,Java 8引入了一个新的Optional类
    Optional类是一个容器类,它可以保存类型T的值,代表这个值存在,或者保存为null,代表这个值不存在,
    这是一个可以为null的容器对象,如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象

    创造Optional类对象的API

    • Optional.of(T t):

    • 为非null的值创建一个Optional实例,t不能为空

    //调用工厂方法创建Optional实例
    Optional<String> name = Optional.of("tom");
    //传入参数为null,抛出NullPointerException.
    Optional<String> someNull = Optional.of(null);
    

    Optional.ofNullable(T t):较常用

    • 创建一个Optional实例,t可为空
    //下面创建了一个不包含任何值的Optional实例
    Optional empty = Optional.ofNullable(null);
    

    Optional.empty():

    • 创建一个空的Optional实例

    判断Optional容器是否包含对象

    • boolean isPresent():

    • 非常容易理解,如果值存在返回true,否则返回false

    void ifPresent(Consumer<? super T> ):

    • 如果有值就执行Consumer接口的实现代码,并且该值会作为参数传给它
    //ifPresent方法接受lambda表达式作为参数。
    //lambda表达式对Optional的值调用consumer进行处理。
    name.ifPresent((value) -> {
        System.out.println("The length of the value is: " + value.length());
    });
    

    T orElse(T other):较常用

    • 如果有值则将其返回,否则返回指定的其它值

    T orElseGet(Suppliper<? entend X> other):

    • 如果有值则将其返回,否则返回由Supplier接口实现提供的对象
    //orElseGet与orElse方法类似,区别在于orElse传入的是默认值,
    //orElseGet可以接受一个lambda表达式生成默认值。
    System.out.println(empty.orElseGet(() -> "Default Value"));
    System.out.println(name.orElseGet(() -> "Default Value"));
    

    T orElseThrow(Suppliper<? entend X> exceptionSuppliper):

    • 如果有值则将其返回,否则抛出由Supplier接口实现提供的异常
    try {
            //orElseThrow与orElse方法类似。与返回默认值不同,
            //orElseThrow会抛出lambda表达式或方法生成的异常 
            empty.orElseThrow(ValueAbsentException::new);
    } catch (Throwable ex) {
            //输出: No value present in the Optional instance
            System.out.println(ex.getMessage());
    }
    

    总结

    篇幅有限!篇幅有限!关于Java8新特性,就聊到这儿啦..啦..啦..

    相关文章

      网友评论

          本文标题:为啥放着Java16不用,都在用Java8?看完Java8的新特

          本文链接:https://www.haomeiwen.com/subject/zunhhltx.html