java 8 新特性

  1. lambda 语法

表达方式对比

Lambda 表达式(lambda expression)是一个匿名函数,简化我们调用匿名函数的过程
 @Test
    public void test1() {
        Runnable r1 = new Runnable() {
            @Override
            public void run() {
                System.out.println("匿名内部类执行");
            }
        };

        r1.run();

        Runnable r2 = () -> System.out.println("lambda语法执行!");
        r2.run();
    }
从上面可以看出,真正执行的只有这么一句话有用,但是为了实现匿名内部内,必须写这么多无用代码

使用Lambda表达式依赖于函数接口

(x,y) -> {}   lambda 表达式分为左边和右边,中间用一个 ->连接起来 ,左边代表的是需要传入抽象方法的入参,右边为抽象方法的实现
1. 在接口中只能够允许有一个抽象方法
2. 在函数接口中定义object类中方法
3. 使用默认或者静态方法
4. @FunctionalInterface 表示该接口为函数接口
Java中使用Lambda表达式的规范,必须是为函数接口

java 系统内置函数
 
消费型接口: 
   Conusmer<T>  
              void accept(T t);
    BiConusmer<T,U> 
                 void accept(T t,U u);//增加一种入参类型
   
供给型接口:
    Supplier<T> 
          void get()
函数型接口
    Function<T ,R>
           R apply(T t);
    UnaryOperator<T>
           T apply(T t);//入参与返回值类型一致
    BiFunction <T ,U,R>
           R apply(T t,U u);//增加一个参数类型
    BinaryOperator<T>
           T apply(T t1,T t2);//l两个相同类型入参与同类型返回值
    ToIntFunction<T> //限定返回int
    ToLongFunction<T>//限定返回long
    ToDoubleFunction<T>//限定返回double
    IntFunction<R>//限定入参int,返回泛型R
    LongFunction<R>//限定入参long,返回泛型R
    DoubleFunction<R>//限定入参double,返回泛型R

断言型接口
    Predicate<T>
       boolean test(T t);
  

使用语法

       ()    // 参数列表
        ->    // 连接符
        {}     // 方法体
/**
 * .........................................
 * .  Getting rid of the fetters of fame   .
 * .  one can concentrate on his technique .
 * . .......................................
 *
 * @Author: LQ
 * @Date: 20 Feb 2023  21:47
 * @DAY_NAME_FULL: Monday
 * @Description:
 *  一、lambda 表达式基础语法:引入新的操作符 -> 该操作符称为箭头操作符 或 lambda 操作符
 *   箭头操作符将lambda 表达式拆分为两部分
 *
 * 左侧:lambda 表达式参数列表
 * 右侧: lambda 表达式所需执行的功能,即lambda 体
 *
 * 语法一:无参数,无返回值
 *   () -> {System.out.println("hello lambda ")}
 *
 * 语法格式二:有一个参数,无返回值
 *   (e) -> {System.out.println(e)}
 *
 *   若只有一个参数,小括号可以不写
 *    e -> {System.out.println(e)}
 *
 * 语法三:有两个参数,有返回值,并且lambda 体中有多条语句
 *   (x,y) -> return x
 *   Comparator<Integer> com = (x,y) ->{
 *             System.out.println("lambda 函数式接口");
 *             return Integer.compare(x,y);
 *         };
 *   若lambda 体中只有一条语句,大括号和return 可以省略
 *
 *
 *   左右遇单括号省
 *
 *
 *   二:lambda  表达式需要 函数式接口 支持
 *   函数式接口:接口中只有一个实现抽象方法 可以用注解 @FunctionInterface 来检查接口
 */
public class TestLambda2 {


    // 需求对一个数进行运算
    @Test
    public void test4() {
        Integer operator = operator(10, x -> x * 10);
        System.out.println(operator);

        Integer operator1 = operator(10, x -> x + 10);
        System.out.println(operator1);
    }


    public Integer operator(Integer num,MyFun<Integer> myFun) {
        return myFun.getValue(num);
    }

    @Test
    public void test3() {
        Comparator<Integer> com = (x,y) ->{
            System.out.println("lambda 函数式接口");
            return Integer.compare(x,y);
        };

        Comparator<Integer> com1 = (x,y) ->Integer.compare(x,y);

        Comparator<Integer> com2 = Integer::compare;
    }

    @Test
    public void test1() {
        // 默认还是final
        int num = 0;

        Runnable ru = new Runnable() {
            @Override
            public void run() {
                System.out.println("hello world " + num);
            }
        };
        ru.run();
        System.out.println("===============");

        Runnable ru1 = () -> System.out.print("hello lambda "+ num);
        ru1.run();
    }

    @Test
    public void test2() {
        Consumer<String> con = (x) -> System.out.print(x);
        con.accept("奉眠武力高升");

        Consumer<String> con1 = x -> System.out.print(x);
        con1.accept("奉眠武力高升");
    }

内置函数使用

*   Consumer<T>  消费型接口
 *       void accept(T t)
 *   Supplier<T>   供给型接口
 *        T get();
 *   Function(T,R)  函数型接口
 *        R apply(T t)
 *
 *   Predication<T> 断言型接口
 *        boolean test(T t)
 *
 *
 */
public class TestLambda3 {

    // predicate<T> 断言型接口
    @Test
    public void test4() {
        List<String> list = Arrays.asList("张三","李四","王五","赵六","田七");
        List<String> list1 = predicateHandler(list, (str) -> str.length() > 3);
        list1.forEach(System.out::println);
    }

    // 将满足条件的字符串放入到集合中
    public List<String> predicateHandler(List<String> list, Predicate<String> pre) {
        List<String> resList = new ArrayList<>();
        for (String str : list) {
            if (pre.test(str)) {
                resList.add(str);
            }
        }
        return resList;
    }


    // function<T,R> 函数式接口  传进一个值,返回另外一个值
    @Test
    public void test3() {
        Integer functionHandler = functionHandler("小白鞋", (str) -> str.length());
        System.out.println(functionHandler);
    }
    // 用于处理字符串,返回字符串长度
    public Integer functionHandler(String str, Function<String,Integer> fun) {
        return fun.apply(str);
    }


    // 供给型接口
    // Supplier <T>
    @Test
    public void test2() {
        List<Integer> integerList = supplierHandler(10,() -> (int) (Math.random() * 100));
        integerList.forEach(System.out::println);
    }

    // 产生多少个数到集合中去
    public List<Integer> supplierHandler(int num, Supplier<Integer> sup) {
        List<Integer> list = new ArrayList<>(num);
        for (int i = 0;i < num; i ++) {
            Integer n = sup.get();
            list.add(n);
        }
        return list;
    }


    // consumer<T> 接口
    @Test
    public void test1() {
        consumerHandler(1000,(x) -> System.out.println("公司聚餐花费:"+x));
    }
    public void consumerHandler(double money, Consumer<Double> cn){
         cn.accept(money);
    }

方法引用

* 一、方法引用
 * 若 lambda 体中的内容有方法已经实现,我们可以使用方法引用
 *     lambda 表达式另外一种表达形式
 *
 *   三种语法格式
 *      方法传入的参数与返回的参数要保持一致
 *      1、lambda 体中调用方法的参数列表与返回值类型,
 *        要与函数式接口中的抽象方法函数的列表和返回值类型保持一致
 *      2、若 lambda 参数列表中第一参数是实列方法的调用者,而第二个参数是实列方法的参数是,可以使用className::method
 *   对象::实列方法名
 *
 *   类::静态方法名
 *
 *   类:: 实列方法名(注意事项)
 *
 *
 * 二、构造器引用
 *    格式:
 *      className::new
 *     注意:需要调用的构造器参数列表要与函数式接口抽象方法参数列表保持一致
 *
 *
 *  三、数组引用
 *   Type:new
 */
public class TestMethodRef {

    // 数组引用
    @Test
    public void test7() {
        Function<Integer,String[]> fu1 = (l) -> new String[l];
        String[] arr1 = fu1.apply(10);
        System.out.println(arr1.length);

        Function<Integer,String[]> fu2 = String[]::new;
        String[] arr2 = fu2.apply(10);
        System.out.println(arr2.length);
    }


    // 构造器
    @Test
    public void test6() {
        Function<Integer,Employee> fun = (x) -> new Employee(x);
        Employee e1 = fun.apply(16);
        System.out.println(e1);

        Function<Integer,Employee> fn1 = Employee::new;
        Employee e2 = fn1.apply(22);
        System.out.println(e2);

        BiFunction<String,Integer,Employee> fn2 = (x,y) -> new Employee(x,y);
        BiFunction<String,Integer,Employee> fn3 = Employee::new;
        Employee employee = fn3.apply("张天翼", 24);
        System.out.println(employee);
    }

    @Test
    public void test5() {
        Supplier<Employee> spu = () -> new Employee();

        // 构造器引用
        Supplier<Employee> spu1 = Employee::new;
        Employee employee = spu1.get();
        System.out.println(employee);
    }



    // 类::实列方法
    @Test
    public void test4() {
        BiPredicate<String,String> bp = (s1,s2) -> s1.equals(s2);
        boolean result1 = bp.test("张三", "李四");
        System.out.println(result1);

        BiPredicate<String,String> bp1 = String::equals;
        boolean result2 = bp.test("张三","张三");
        System.out.println(result2);
    }


    // 类::静态方法名
    @Test
    public void test3() {
        Comparator<Integer> com = (x,y) -> Integer.compare(x,y);

        // 方法引用,静态方法
        Comparator<Integer> com1 = Integer::compare;

        Set<Integer> set = new TreeSet<>(com1);
        set.add(5);
        set.add(1);
        set.add(3);
        set.add(2);
        set.add(4);

        set.forEach(System.out::println);
    }



    @Test
    public void test1() {
        Consumer<String> com = (x) -> System.out.println(x);
        com.accept("2023年2月21");
        // 方法引用
        PrintStream ps = System.out;
        Consumer<String> com1 = ps::println;
        com1.accept("2023年2月21");

        Consumer<String> com2 = System.out::println;
        com2.accept("2023年2月21");
    }


    @Test
    public void test2() {
        Employee employee = new Employee();
        employee.setName("奉眠");
        employee.setAge(33);
        Supplier<String> sup = () -> employee.getName();
        String name = sup.get();
        System.out.println(name);

        // 方法引用  对象::方法名
        Supplier<Integer> sup1 = employee::getAge;
        Integer age = sup1.get();
        System.out.println(age);
    }
}
  1. stream 使用

什么是stream 流 :是数据渠道,用于操作数据源(集合、数组等) 所生成的元素序列。“集合讲的是数据,流讲的是算!”
注意:
1、Stream自己不会存储元素
2、Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
3、Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

stream使用步骤

1、创建stream:一个数据源(如集合,数组),获取到一个流

2、中间操作:一个中间操作链,对数据源的数据进行处理

3、终止操作(终端操作):执行中间操作链,并产品结果

创建集合

// 创建stream
    @Test
    public void test1() {
        // 1、通过Collection 系列集合提供的是太热爱 或者 paraselStream
        List<String> list = new ArrayList<>();
        Stream<String> stream1 = list.stream();

        // 2、通过arrays 中的静态方法 stream() 获取数组流
        Employee[] employees = new Employee[10];
        Stream<Employee> stream2 = Arrays.stream(employees);

        // 3、通过stream 类中的静态方法 of()
        Stream<String> stream3 = Stream.of("aa", "hello", "good");

        // 4、创建无限流  迭代   从0 开始一直迭代
        Stream.iterate(0,(x) -> x + 2)
                .limit(10)
                .forEach(System.out::println);


        // 生成
        Stream.generate(() -> Math.random())
                .limit(5)
                .forEach(System.out::println);
    }

中间操作

* @Description: 中间操作
 *
 *   筛选与切片
 *   filter - 接收 lambda ,从流中排除某些元素
 *   limit  - 截断流,使其元素不超过给定数量
 *   skip(n) 跳过元素,返回一个丢弃到前面的n个元素流,若元素不足n个,则返回一个空流,与limit(n)互补
 *   distinct - 筛选,通过流所生成的元素的hashcode 和 equals 去掉重复元素
 *
 *
 *      多个中间操作可以链接起来形成一个流水线,除非流水线出发终止操作,否则中间操作不会执行
 *     任何处理,而在终止操作是一次性全部处理,称为 惰性求值
 */
public class TestStreamApi2 {

    List<Employee> employees = Arrays.asList(
            new Employee("唐三",18,8888.21)
            ,new Employee("小舞",18,7778.11)
            ,new Employee("宁蓉蓉",16,9999.22)
            ,new Employee("奉眠",23,18888.21)
            ,new Employee("屋南",66,68888.66)
            ,new Employee("敖无虚",55,48888.66)
            ,new Employee("敖无虚",55,48888.66)
    );

    // 排序
    // sorted --自然排序 Comparable
    // sorted(comparator) - 定制排序
    @Test
    public void test7() {
        List<String> list = Arrays.asList("eeee", "bbb", "ccc", "ddd","aaaa");

        // 自然排序
        list.stream()
                .sorted()
                .forEach(System.out::println);

        System.out.println("-----------------");
        // 定制排序
        employees.stream()
                .sorted((o1,o2) -> {
                    if (o1.getAge() == o2.getAge()) {
                        return o1.getName().compareTo(o2.getName());
                    }
                    return Integer.compare(o1.getAge(),o2.getAge());
                })
                .forEach(System.out::println);
    }

    /**
     *  映射
     *   map - 接受lambda ,将元素转换为其他形式或提取信息。接受一个函数作为参数,
     *   该函数会被应用到每个元素上,并将其映射成一个新的元素
     *   flatMap  接受一个函数作为参数,将流中的每个值都换成另外一个流,然后把所有的流连接成一个流
     *
     */
    @Test
    public void test6() {
        List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd");

        list.stream()
                //.map(String::toUpperCase)
                .map((str) -> str.toUpperCase())
                .forEach(System.out::println);
        System.out.println("----------------");
        employees.stream()
                .map(Employee::getName)
                .forEach(System.out::println);

        System.out.println("----------------");
        Stream<Stream<Character>> streamStream = list.stream()
                .map(TestStreamApi2::filterCharacter);

        System.out.println("----------------");
        streamStream.forEach(
                (stream) ->
                        stream.forEach(System.out::println)
        );
        System.out.println("----------------");
        list.stream()
                .flatMap(TestStreamApi2::filterCharacter)
                .forEach(System.out::println);
    }

    public static Stream<Character> filterCharacter(String str) {
        List<Character> list = new ArrayList<>();

        for (Character ch : str.toCharArray()) {
            list.add(ch);
        }
        return list.stream();
    }

    // 出重 distinct  需要重写 equals 和hashcode 方法
    @Test
    public void test5(){
        employees.stream()
                .filter((e) -> e.getSalary() > 8888)
                .distinct()
                .forEach(System.out::println);
    }

    @Test
    public void test4() {
        employees.stream()
                .filter((employee -> employee.getSalary() > 7777))
                .skip(2)
                .forEach(System.out::println);
    }

    // limit
    @Test
    public void test3() {
        employees.stream()
                .filter((e) -> {
                    System.out.println("短路");
                    return e.getSalary() > 7777;
                })
                .limit(2)
                .forEach(System.out::println);
    }

    // 内部迭代,迭代操作由 stream api 完成
    @Test
    public void test1() {
        Stream<Employee> stream = employees.stream()
                .filter(e -> {
                    System.out.println("stream api 中间操作");
                    return e.getAge() > 18;
                });

        // 终止操作,一次性执行全部内容, 惰性求值
        stream.forEach(System.out::println);

    }

    // 外部迭代
    @Test
    public void test2() {
        Iterator<Employee> iterator = employees.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

终止操作

 /**
     *  查找与匹配
     *   allMatch - 检查是否匹配所有元素
     *   anyMatch - 检查是否至少匹配一个元素
     *   noneMatch - 检查是否没有匹配所有元素
     *   findFirst - 返回第一个元素
     *   findAny  - 返回当前流中任意元素
     *   count - 返回六中元素的总个数
     *   max - 返回流中最大值
     *   min - 返回流中最小值
     */
    @Test
    public void test1() {
        boolean b = employees.stream()
                //.filter((e) -> e.getStatus().equals(EmployeeExt.Status.BUSY))
                .allMatch((e) -> e.getStatus().equals(EmployeeExt.Status.BUSY));
        System.out.println(b);

        boolean b1 = employees.stream()
                .anyMatch((e) -> e.getStatus().equals(EmployeeExt.Status.BUSY));
        System.out.println(b1);

        boolean b2 = employees.stream()
                .noneMatch((e) -> e.getStatus().equals(EmployeeExt.Status.BUSY));
        System.out.println(b2);

        Optional<EmployeeExt> optional = employees.stream()
                .sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))
                .findFirst();

        System.out.println(optional.get());

        Optional<EmployeeExt> optional1 = employees.stream()
                .filter((e) -> e.getStatus().equals(EmployeeExt.Status.FREE))
                .findAny();
        System.out.println(optional1.get());
    }
    // 执行结果:
        false
        true
        false
        EmployeeExt(name=奉眠, age=23, salary=18888.21, status=BUSY)
        EmployeeExt(name=屋南, age=66, salary=68888.66, status=FREE)

    @Test
    public void test2() {
        long count = employees.stream()
                .count();
        System.out.println(count);

        Optional<EmployeeExt> optional = employees.stream()
                .max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
        System.out.println(optional.get());

        Optional<Double> optional2 = employees.stream()
                .map(EmployeeExt::getSalary)
                .min(Double::compare);
        System.out.println(optional2.get());
    }
 // 执行结果:
        5
        EmployeeExt(name=澜风, age=100, salary=2248888.66, status=VOCATION)
        18888.21

   /**
     *  规约 reduce BinaryOperator<T> accumulator 可以将流中元素反复结合  map reduce 
     */
    @Test
    public void test3() {
        List<Integer> list = Arrays.asList(100, 20, 30, 50, 1000);

        Integer sum = list.stream()
                .reduce(0, (x, y) -> x + y);
        Integer sum1 = list.stream()
                .reduce(0, Integer::sum);
        System.out.println(sum);
        System.out.println(sum1);


        Optional<Double> optional = employees.stream()
                .map(EmployeeExt::getSalary)
                .reduce((x, y) -> Double.sum(x, y));
        System.out.println(optional.get());
    }
// 执行结果:
   1200
   1200
   4634442.85

收集

 /**
     *  收集
     *  collect - 将流转换为其他形式,接受一个Collector 接口的实现,用于给stream 元素做汇总
     *  Collectors
     *  collector 接口中方法实现决定了如何对流执行收集操作(如 收集 List
     *  Set , Map )。 但是 collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例
     *
     */
    @Test
    public void test4() {
        // 将名字收集添加到一个新集合中
        List<String> listNames = employees.stream()
                .map(EmployeeExt::getName)
                .collect(Collectors.toList());
        listNames.forEach(System.out::println);

        System.out.println("--------");
        Set<String> setNames = employees.stream()
                .map(EmployeeExt::getName)
                .collect(Collectors.toSet());
        setNames.forEach(System.out::println);

        System.out.println("--------");
        HashSet<String> hs = employees.stream()
                .map(EmployeeExt::getName)
                .collect(Collectors.toCollection(HashSet::new));
        hs.stream().forEach(System.out::println);
    }
// 执行结果:
奉眠
屋南
敖无虚
澜风
澜风
--------
屋南
敖无虚
奉眠
澜风
--------
屋南
敖无虚
奉眠
澜风
 /**
     *  收集
     */
    @Test
    public void test5() {
        // 总数
        long count = employees.stream()
                .collect(Collectors.counting());
        System.out.println(count);

        System.out.println("---------------------");

        //平均值
        double ave = employees.stream()
                .collect(Collectors.averagingDouble(EmployeeExt::getSalary));
        System.out.println(ave);

        // 最大值
        Optional<EmployeeExt> optional1 = employees.stream()
                .collect(Collectors.maxBy((e1,e2) -> Double.compare(e1.getSalary(),e2.getSalary())));
        System.out.println(optional1.get());

        // 最小值
        Optional<EmployeeExt> optional2 = employees.stream()
                .collect(Collectors.minBy((e1,e2) -> Double.compare(e1.getSalary(),e2.getSalary())));
        System.out.println(optional2.get());

        Optional<Double> minD = employees.stream()
                .map(EmployeeExt::getSalary)
                .collect(Collectors.minBy(Double::compareTo));
        System.out.println(minD.get());
    }

  // 收集
    @Test
    public void test8() {
        DoubleSummaryStatistics dss = employees.stream()
                .collect(Collectors.summarizingDouble(EmployeeExt::getSalary));

        System.out.println(dss.getMax());
        System.out.println(dss.getCount());
        System.out.println(dss.getSum());
    }
// 结果:
2248888.66
5
4634442.85

分组

@Test
    public void test6() {
        Map<EmployeeExt.Status,List<EmployeeExt>> map = employees.stream()
                .collect(Collectors.groupingBy((e) -> e.getStatus()));
        System.out.println(map);

        Map<EmployeeExt.Status,List<EmployeeExt>> map1 = employees.stream()
                .collect(Collectors.groupingBy(EmployeeExt::getStatus));
        System.out.println(map1);
    }
// 结果
{VOCATION=[EmployeeExt(name=澜风, age=100, salary=2248888.66, status=VOCATION), EmployeeExt(name=澜风, age=1001, salary=2248888.66, status=VOCATION)], FREE=[EmployeeExt(name=屋南, age=66, salary=68888.66, status=FREE)], BUSY=[EmployeeExt(name=奉眠, age=23, salary=18888.21, status=BUSY), EmployeeExt(name=敖无虚, age=55, salary=48888.66, status=BUSY)]}
{VOCATION=[EmployeeExt(name=澜风, age=100, salary=2248888.66, status=VOCATION), EmployeeExt(name=澜风, age=1001, salary=2248888.66, status=VOCATION)], FREE=[EmployeeExt(name=屋南, age=66, salary=68888.66, status=FREE)], BUSY=[EmployeeExt(name=奉眠, age=23, salary=18888.21, status=BUSY), EmployeeExt(name=敖无虚, age=55, salary=48888.66, status=BUSY)]}

 // 多级分组
    @Test
    public void test7() {
        Map<EmployeeExt.Status,Map<String,List<EmployeeExt>>> map = employees.stream()
                .collect(Collectors.groupingBy(EmployeeExt::getStatus,Collectors.groupingBy((e) -> {
                    EmployeeExt ext = (EmployeeExt) e;
                    if (ext.getAge() < 30) {
                        return "青年";
                    }
                    if (ext.getAge() < 100) {
                        return "中年";
                    }
                    return "老顽固";
                })));

        System.out.println(map);
    }
// 执行结果
{BUSY={青年=[EmployeeExt(name=奉眠, age=23, salary=18888.21, status=BUSY)], 中年=[EmployeeExt(name=敖无虚, age=55, salary=48888.66, status=BUSY)]}, VOCATION={老顽固=[EmployeeExt(name=澜风, age=100, salary=2248888.66, status=VOCATION), EmployeeExt(name=澜风, age=1001, salary=2248888.66, status=VOCATION)]}, FREE={中年=[EmployeeExt(name=屋南, age=66, salary=68888.66, status=FREE)]}}

3、日期

Java8 中加入了对时区的支持,带时区的时间为分别为:ZonedDate、ZonedTime、ZonedDateTime其中每个时区都对应着ID,地区ID都为“[区域]/城市)”的格式例如:Asia/Shanghai等
Zoneld: 该类中包含了所有的时区信息

getAvailableZonelds():可以获取所有时区时区信息of(id):用指定的时区信息获取 Zoneld 对象
LocalDate、LocalTime、 LocalDateTime
LocalDate、LocalTime、LocalDateTime 类的实例是不可变的对象,分别表示使用ISO-8601日历系统的日期、时间、日期和时间。它们提供了简单的日期或时间,并不包含当前的时间信息。也不包含与时区相关的信息。

LocalDate、LocalTime、 LocalDateTime

/**
     *  LocalDate  LocalTime  LocalDateTime
     */
    @Test
    public void test1() {
        LocalDateTime now = LocalDateTime.now();
        System.out.println(now);//2023-02-23T22:21:09.454

        // - 1 天
        LocalDateTime ldt1 = now.minusDays(1);
        System.out.println(ldt1);//2023-02-22T22:21:09.454

        // +1 天
        LocalDateTime ldt2 = now.plusDays(1);
        System.out.println(ldt2);//2023-02-24T22:21:09.454

        System.out.println(now.getYear());//2023
        System.out.println(now.getMonthValue());//2
        System.out.println(now.getDayOfMonth());//23
        System.out.println(now.getHour());//22
        System.out.println(now.getMinute());//21
        System.out.println(now.getSecond());//9

        System.out.println(LocalDate.now());//2023-02-23
        System.out.println(LocalTime.now());//22:21:09.455
    }

instant

时间戳(以 unix 元年:1970年1月1日00:00:00 到某个时间之间的毫秒值
 @Test
    public void test2() {
        Instant ist = Instant.now();
        System.out.println(ist);//2023-02-23T14:25:21.209Z


        OffsetDateTime offsetDateTime = ist.atOffset(ZoneOffset.ofHours(8));
        System.out.println(offsetDateTime);//2023-02-23T22:25:21.209+08:00
        System.out.println(ist.getNano());//209000000

         // 元年 + 1秒
        Instant instant = Instant.ofEpochSecond(1);
        System.out.println(instant);//1970-01-01T00:00:01Z
    }

duration/Period

duration: 计算两个 时间之间的间隔
Period: 计算两个 日期之间的间隔
 @Test
    public void test3() throws Exception {
        Instant ist1 = Instant.now();
        Thread.sleep(1000);

        Instant inst2 = Instant.now();
        Duration du1 = Duration.between(ist1,inst2);
        System.out.println("间隔:"+du1.toMillis());//1006

        LocalDate localDate = LocalDate.of(2022,1,22);
        LocalDate ld2 = LocalDate.now();
        
        Period per = Period.between(localDate,ld2);
        System.out.println(per.getYears());//1
        System.out.println(per.getMonths());//1
        System.out.println(per.getDays());//1
    }

4、Optional

Optional<T>类(java.util.Optional) 是一个容器类,代表一个值存在或不存在原来用 nul1 表示一个值不存在,现在 Optional 可以更好的表达这个概念。并且可以避免空指针异常
/**
* Optional 容器类的常用方法:
* Optional.of(T t) : 创建一个 Optional 实例
* Optional.empty() : 创建一个空的 Optional 实例
* Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例
* isPresent() : 判断是否包含值
* orElse(T t) : 如果调用对象包含值,返回该值,否则返回 t
* orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回 s 获取的值
* map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回 Optional,empty()
* flatMap(Function mapper):与 map 类似,要求返回值必须是Optional
*/
    // orElse  如果调用对象包含值,返回该值,否则返回 t
    @Test
    public void test1() {
        Optional<EmployeeExt> optional = Optional.of(new EmployeeExt("周世才",55,80000, EmployeeExt.Status.BUSY));
        System.out.println(optional.get());
// 结果:EmployeeExt(name=周世才, age=55, salary=80000.0, status=BUSY)

        EmployeeExt employee = optional.orElse(new EmployeeExt());
        System.out.println(employee);
// 结果:EmployeeExt(name=周世才, age=55, salary=80000.0, status=BUSY)

        Optional<EmployeeExt> optional2 = optional.ofNullable(new EmployeeExt());
        System.out.println(optional2.get());
// 结果:EmployeeExt(name=null, age=0, salary=0.0, status=null)

       // Optional<EmployeeExt> optional2 = Optional.of(null);
       // System.out.println(optional2.get());
    }

//isPresent()  判断是否包含值
    @Test
    public void test2() {
        Optional<EmployeeExt> optional  = Optional.empty();
        if (optional.isPresent()) {
            System.out.println(optional.get());
        }

//        Optional<EmployeeExt> optional2 = optional.ofNullable(new EmployeeExt());
//        System.out.println(optional2.get());

        EmployeeExt employee = optional.orElse(new EmployeeExt());
        System.out.println(employee);
    }
// 结果:EmployeeExt(name=null, age=0, salary=0.0, status=null)

 //orElseGet()  :如果调用对象包含值,返回该值,否则返回 s 获取的值
     @Test
    public void test3() {
        Optional<EmployeeExt> optional = Optional.of(new EmployeeExt("周世才",55,80000, EmployeeExt.Status.BUSY));
        EmployeeExt ext = optional.orElseGet(EmployeeExt::new);
        System.out.println(ext);
//EmployeeExt(name=周世才, age=55, salary=80000.0, status=BUSY)
    }
flatMap (Function mapper):与 map 类似,要求返回值必须是Optional
返回一个Optional 对象,使用 Optional.of()
     @Test
    public void test4() {
        Optional<EmployeeExt> optional = Optional.ofNullable((new EmployeeExt("周世才",55,80000, EmployeeExt.Status.BUSY)));
        //Optional<EmployeeExt> optional = Optional.of(new EmployeeExt());
        Optional<String> optional1 = optional.map(EmployeeExt::getName);
        System.out.println(optional1.get());//周世才

        Optional<EmployeeExt> optional2 = optional.flatMap((e) -> Optional.of(new EmployeeExt()));
        System.out.println(optional2.get());
//EmployeeExt(name=null, age=0, salary=0.0, status=null)
    }

4、接口

java8中增加了default 方法,如果一个接口中与一个类中有相同的方法名称,那么实现类调用的时候已那个为准呢?
// 接口定义default 方法
public interface Fun1 {
    default String getName() {
        return "我是fun1的getName方法";
    }
     static void showName() {
        System.out.println("我是fun接口showName方法");
    }
}
// 类中定义 getName()方法
public class MyClass {

    public String getName() {
        return "我是MyClass的getName方法";
    }
}

// 实现
public class SubClass extends MyClass implements Fun1 {
}

// 测试 
public static void main(String[] args) {
        SubClass subClass = new SubClass();
        System.out.println(subClass.getName());

        subClass.getName();
        Fun2.showName();
 }
猜猜看,是 class中的方法优先还是接口中的方法优先呢?
执行结果:我是MyClass的getName方法

问题2:再定义一个接口fun2 同样的抽象方法,那么这个时候那个优先呢
public class SubClass /*extends MyClass*/ implements Fun1,Fun2 {
    @Override
    public String getName() {
        return Fun2.super.getName();
    }
}
结果,编译不通过,必须重写getName()方法,否则编译不过
总结:
接口默认方法的”类优先”原则
1、若一个接口中定义了一个默认方法,而另外一个父类或接口中又定义了一个同名的方法时选择父类中的方法。如果一个父类提供了具体的实现,那么接口中具有相同名称和参数的默认方法会被忽略。
2、接口冲突。如果一个接口提供一个默认方法,而另一个接口也提供了一个具有相同名称和参数列表的方法 (不管方法是否是默认方法),那么必须覆盖该方法来解决冲突
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值