深入浅出地了解java8

1.参考尚学堂课程

1.

  说明:

lambda 表达式有三种表现形式: ①带 -> 的,②方法引用 :: ③构造器引用::

1. 初体验

  List<Employee> employees = Arrays.asList(
                new Employee("张三", 16, Double.valueOf(90)),
                new Employee("李四", 19, Double.valueOf(120)),
                new Employee("王五", 25, Double.valueOf(220)),
                new Employee("赵六", 30, Double.valueOf(340))

        );
        employees.stream()
                .filter(e -> e.getSalary() < 100)
                .limit(1)
                .forEach(System.out::println);
        // 只取名字
        employees.stream()
                .map(Employee::getName)
                .forEach(System.out::println);

1. lambda 表达式:

    格式:

      ()->{ 方法体}

        这个格式是对某个接口的实现:()是函数式接口的参数列表;{ 方法体} 是函数式接口抽象方法的具体实现,如果方法体只有一行,则大括号和return都可以不写;

       参数类型是可以不写的,因为 编译器可以根据上下文推断出来,即“类型推断”

      如下:

   


// 因为 泛型 Integer,所以推断出 x,y的类型
Comparator<Integer> tComparator = (x, y) -> {
            System.out.println(x+"  "+y);
            return Integer.compare(x,y);
        };


  // List的元素是 String,所以推断 ArrayList的元素也是 String
        List<String> strings = new ArrayList<>();

左右遇一括号省:->  参数列表只有一个参数,()可以省略;-> 方法体只有一行代码,{}可以省,而且  return 也可以省略

Consumer consumer1 = (e)->System.out.println("lambda 有参数,无返回值,参数为:"+e) ;
        Consumer consumer2 = e->System.out.println("lambda 有参数,无返回值,参数为:"+e) ;

语法如下:

 // 语法: ①无参数,无返回值的接口
        Runnable runnable = new Runnable() {
            @Override
            public void run(){
                System.out.println("无参数,无返回值");
            }
        };
        runnable.run();
        // 改成lambda后
        Runnable runnable1 = () -> System.out.println("lambda 无参数,无返回值");
        runnable1.run();
        // 语法: ②一个参数,无返回值的接口
        Consumer consumer1 = (e)->System.out.println("lambda 有参数,无返回值,参数为:"+e) ;
        Consumer consumer2 = e->System.out.println("lambda 有参数,无返回值,参数为:"+e) ;
        consumer1.accept("hello");//hello 作为参数传给 e,最后  e到达方法体
        // 语法: ③多个参数,有返回值 接口  (假如有 多行代码 的实现)Comparator 接口
        Comparator<Integer> tComparator = (x, y) -> {
            System.out.println(x+"  "+y);
            return Integer.compare(x,y);
        };
        // -1
        System.out.println(tComparator.compare(2,3));

二: lambda 表达式是对函数式接口进行操作的,所以需要函数式接口的支持

       函数式接口:接口中只有一个抽象方法,用注解 

    @FunctionalInterface修饰的接口就是函数式接口,里面只可以有一个抽象方法

自定义函数式接口


@FunctionalInterface
public interface MyCustomFunctionInterface<Integer> {
    int getValue(Integer t);
}

public int getSum(Integer x,MyCustomFunctionInterface<Integer> myInterface){
        return x + myInterface.getValue(x);
    }


 // Integer 必须加上,不然推断不出 x的类型
        MyCustomFunctionInterface<Integer> fi = (x)->{
           return 1+x;
        };
        int value = fi.getValue(10);
        System.out.println(value);
        // 函数式接口最常见的作用是作为一个方法的参数
        int sum = getSum(1, i -> i + 1);
        // sum 3
        System.out.println(sum);

函数式接口练习:

// 1
  List<Employee> employees = Arrays.asList(
                new Employee("张三", 16, Double.valueOf(90)),
                new Employee("李四", 19, Double.valueOf(120)),
                new Employee("王五", 25, Double.valueOf(220)),
                new Employee("赵六", 30, Double.valueOf(340))

        );
        Collections.sort(employees,(x,y)->{
            if (x.getAge() - y.getAge() == 0) {
                //compareTo()用于比较字符串大小 0 为相等;负为  x < y
                return x.getName().compareTo(y.getName());
            }
            // 如果降序  return -(x.getAge() - y.getAge());
            return x.getAge() - y.getAge();
        });
        employees.stream()
                .forEach(System.out::println);

// 3
  // 不是很符合要求
        MyCustomFunctionInterface<Long,Long> fi1 = (x,y)->{
            Long a = x+y;
            return a;
        };
        System.out.println(fi1.getValue(1L,2L));

        MyCustomFunctionInterface<Long,Long> fi2 = (x,y)->{
            Long b = x*y;
            return b;
        };
        System.out.println(fi2.getValue(1L,2L));

        // 这个是最满足要求的
        System.out.println(getLongSum(1L,2L,(x,y)->x + y));
        System.out.println(getLongSum(1L,2L,(x,y)->x * y));


    public Long getLongSum(Long x,Long y,MyCustomFunctionInterface<Long,Long> fi){
        // 函数式接口 作为形参,接口抽象方法需要的实参通过getLongSum 这个方法传递
        return  fi.getValue(x,y);
    }

新特性:内置的四大核心函数式接口

  ① Consumer<T> ---> void accept(T t); 消费型

② Supplier<T>  --->  T get();   供给型(有返回值)

③ Function<T, R> ---> R apply(T t); 函数型(有返回值)

④ Predicate<T> ---> boolean test(T t);  断言型 (返回值是booleam)

简单例子:

 @Test
    public void testGetAcccountById() {
        consumerTest(10,e-> System.out.println(e));
        supplierTest(0,()->{
            return 1;
        });
        Integer integer = functionTest(10, e -> e + 10);
        predicateTest(10,e->10>20);

    }

    public void consumerTest(Integer a,Consumer<Integer> consumer){
        // 函数式接口接受参数,具体操作看lambda 方法体
        consumer.accept(a);
    }

    public Integer supplierTest(Integer x, Supplier<Integer> supplier){
       return supplier.get();
    }

    public Integer functionTest(Integer x, Function<Integer, Integer> functon){
        return functon.apply(x);
    }

    public boolean predicateTest(Integer x, Predicate<Integer> predicate){
        return predicate.test(x);
    }

使用:


    @Test
    public void returnTest()  {
        System.out.println(" returnTest main  thread ......"+Thread.currentThread().getName());

        Integer result = getReturn(() -> {
            System.out.println("aaaaa");
            System.out.println("hhhhhh");
            return 1;
        });
        System.out.println(result);
        System.out.println(result);
    }

    public <U> U getReturn(Supplier<U> supplier){


        return supplier.get();


    }


    @Test
    public void returnTest2()  {
        System.out.println(" returnTest2 main  thread ......"+Thread.currentThread().getName());

        // Consumer  的 accept 消费一个对象(业务逻辑)
        Consumer<Integer> consumer = new Consumer<Integer>() {
            // 不带有返回值
            @Override
            public void accept(Integer integer) {
                System.out.println(integer);
                System.out.println("aaaaa");
                System.out.println("hhhhhh");

            }
        };
        // 开始调用 目标方法
        consumer.accept(1);

    }

四:方法引用和构造器引用

      方法引用:如果lambda表达式方法体已经被实现了,那么可以用方法引用(lambda 表达式的另外一种表现形式,这种形式都不需要 ->)

                      ps:lambda 表达式表现形式:要么自己写方法体,要么引用已经被实现的方法

                       举例:

   Employee employee = new Employee("张三",10,Double.valueOf(10));
        Supplier supplier = () -> employee.getName();
        System.out.println(supplier.get());

        // 方法引用是lambda表达式的第二种 表现形式(这个时候 -> 没了)
        Supplier<String> supplier2 =  employee::getName;
        System.out.println(supplier2.get());

     语法主要三种:(因为语法规定了是 方法名,所以不需要加  括号)

      实例对象::实例方法名

      类::静态方法名

      类::实例方法名

     要求:

          要去引用的方法参数列表 和返回值类型要和 函数式接口的 抽象方法的参数列表和返回值类型一样

          如果lambda表达式第一个参数是实例方法调用者,第二个参数是实例方法参数,可以用  类::实例方法名

举例说明:

    Consumer consumer = x -> System.out.println(x);
        consumer.accept(10);

        // System 类里定义了  public final static PrintStream out = null;
        PrintStream ps = System.out;
        Consumer consumer2 = ps::println;
        consumer2.accept(10);

类::静态方法

  // lambda 表达式第一种形式   ->
        Comparator<Integer> comparator1 = (x, y) -> Integer.compare(x, y);
        comparator1.compare(1,2);

        //lambda 表达式第二种形式  类::静态方法名
        Comparator<Integer> comparator2 = Integer::compare;
        comparator2.compare(1,2);

类::实例方法名

如果lambda表达式第一个参数是实例方法调用者,第二个参数是实例方法参数,可以用  类::实例方法名

      // lambda 表达式第一种形式   ->
        BiPredicate<String,String> predicate = (x, y) -> x.equals(y);
        System.out.println(predicate.test("1","1"));;

        //lambda 表达式第二种形式  类::对象方法名
        BiPredicate<String,String> predicate2 = String::equals;
        System.out.println(predicate2.test("1","2"));

构造器引用:

语法:

类名::new

   // lambda 第一种表现方式
        Supplier  supplier = () -> new Employee();
        // 获取对象
        supplier.get();

        // lambda 第三种表现方式 类名::new
        Supplier  supplier2 = Employee::new;
        supplier2.get();

数组引用:

Type::new

四 强大的Stream

映射操作

map(Function) 参数是函数型接口,传一个参数,返回一个结果,将流中的每个元素都通过函数式接口的抽象方法处理,并返回一个新的元素,最终这些新的元素组成新的流,最终流里的元素类型就是刚刚返回的新元素类型

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

flatMap(Function) 参数是函数型接口,传一个T,返回的结果为子Stream:将流中的每一个元素换成另一个流,最后把所有的流连接成新的流

(ps:关键字连接 类似于 化零为整)

<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);

如下:

     //提供一个将 String 转化为  Stream<Charater> 的方法
  /**
    * @Description: 要求返回时 Stream流,则考虑 list.stream();Arrays.stream(包装类型的数组);Stream.of包装类型的数组)
     *
    */
    public static Stream<Character> getCharacterStream(String str){
        // 转成list,最后返回list.stream()
        List<Character> chars = new ArrayList<>();
        // 转成包装类型的数组,最后返回 Arrays.stream(包装类型的数组)or  Stream.of包装类型的数组)
        Character[] charcterArray = new Character[9];
        char[] charAyyar = str.toCharArray();
        for (int a = 0; a < charAyyar.length;a++) {
            // 将基本类型的转为 包装类型,这样才可以转成stream
            chars.add(charAyyar[a]);
            charcterArray[a] = charAyyar[a];
        }
          return chars.stream();
        //  stream 参数为数组,这个数组要求是 包装类型的,不可以 基本类型
        //  return Arrays.stream(charcterArray);
        // return Stream.of(charcterArray);
    }

// 以下是测试代码
 
   List<String>  strList = Arrays.asList("aaa","bbb","ccc");
        // a
        // a
        // a
        getCharacterStream("aaa").forEach(System.out::println);
  // java.util.stream.ReferencePipeline$Head@318ba8c8
        // java.util.stream.ReferencePipeline$Head@6dbb137d
        // java.util.stream.ReferencePipeline$Head@3c9d0b9d
        //  发现打印结果是个流对象,因为 map 将 "aaa" 转化为 Stream<Character>  (也就是 getCharacterStream(String str) 返回值)
        strList.stream()
                .map(CodeTest::getCharacterStream)
                .forEach(System.out::println);
        // 以上代码 可以这样理解
        Stream<Stream<Character>> strmap = strList.stream()
                .map(CodeTest::getCharacterStream);
        strmap.forEach(System.out::println);

      // 用 map 遍历出 a a a b b b c c c
        strList.stream()
                .map(CodeTest::getCharacterStream)
                // 经过map之后的所有元素都是 Stream,所以  e 就是个Stream
                .forEach(e -> e.forEach(System.out::println));

        // 说明 map 返回是Stream,getCharacterStream 对 strList 每个元素操作后,将这个元素转成了 Stream,这个Stream 里元素是 Character
        // 数据结构类似:{{a,a,a},{b,b,b},{c,c,c}}

       // 用 flatMap 遍历出 a a a b b b c c c
        strList.stream()
                .flatMap(CodeTest::getCharacterStream)
                .forEach(System.out::println);
// 以上代码等价于
        strList.stream()
                .flatMap(e->{
                    return getCharacterStream(e);
                })
                .forEach(System.out::println);

题外话:

char[] chars = "abc".toCharArray();
        for (char c : chars) {
            // a
            // b
            // c
            System.out.println(c);
        }
        char[] chars2 = "张三".toCharArray();
        for (char c : chars2) {
            // 张
            // 三
            System.out.println(c);
        }

说明:

此例中map和flatMap 的区别:

这个从函数式接口抽象方法需要的参数类型就可看出来:map 参数列表是T,返回的是R,flatMap 参数列表是T,返回的是Stream

其次,map 返回的Stream<R> 最终流里的元素 是R,是对每个元素操作后返回的R,进行合并

            flatMap 返回的是 Stream<Stream<R>>,最终流里的元素首先是 Stream<R>,然后对每个元素操作后返回的Stream<R> 里面的R 进行合并

简单一句话:map 最终合并的是 每个元素进行操作后的返回值;flatMap 最终合并的是 每个元素进行操作后返回的Stream<R> 里的元素

类似于:


        //map 模拟
       List<List> lastList = new ArrayList<>();
       // 模拟返回的第一个流
        List<String> oneList = new ArrayList<>();
        oneList.add("a");
        oneList.add("b");
        oneList.add("c");
        // 模拟返回的第二个流
        List<String> twoList = new ArrayList<>();
        twoList.add("aa");
        twoList.add("bb");
        twoList.add("cc");
        // 模拟返回的第三个流
        List<String> threeList = new ArrayList<>();
        threeList.add("aaa");
        threeList.add("bbb");
        threeList.add("ccc");
        // 将这三个流连接成一个新的流(关键字:连接)
        lastList.add(oneList);
        lastList.add(twoList);
        lastList.add(threeList);

        lastList.stream()
                .forEach(System.out::println);
        System.out.println("我是快乐的分割线----------------------------------------------------");
        lastList.stream()
                .forEach(e->e.stream().forEach(System.out::println));

结果为:

[a, b, c]
[aa, bb, cc]
[aaa, bbb, ccc]
我是快乐的分割线----------------------------------------------------
a
b
c
aa
bb
cc
aaa
bbb
ccc
  //flatMap 模拟
       List<String> lastList = new ArrayList<>();
       // 模拟返回的第一个流
        List<String> oneList = new ArrayList<>();
        oneList.add("a");
        oneList.add("b");
        oneList.add("c");
        // 模拟返回的第二个流
        List<String> twoList = new ArrayList<>();
        twoList.add("aa");
        twoList.add("bb");
        twoList.add("cc");
        // 模拟返回的第三个流
        List<String> threeList = new ArrayList<>();
        threeList.add("aaa");
        threeList.add("bbb");
        threeList.add("ccc");
        // 将这三个流连接成一个新的流(关键字:连接)
        lastList.addAll(oneList);
        lastList.addAll(twoList);
        lastList.addAll(threeList);

        lastList.stream()
                .forEach(System.out::println);

结果为:

a
b
c
aa
bb
cc
aaa
bbb
ccc

排序:

  List<Employee> employees = Arrays.asList(
                new Employee("张三", 30, Double.valueOf(90)),
                new Employee("李四", 19, Double.valueOf(120)),
                new Employee("王五", 25, Double.valueOf(220)),
                new Employee("赵六", 1, Double.valueOf(340))

        );
        Stream<String> a = Stream.of("a", "c", "d", "b");
        // 自然排序
        a.sorted().forEach(System.out::println);
        // 自定义排序规则
        employees.stream().sorted((x,y)->x.getAge()-y.getAge()).forEach(System.out::println);
        employees.stream().sorted((x,y)->x.getName().compareTo(y.getName())).forEach(System.out::println);

终止操作:

reduce:归约操作

可以将流中元素反复结合起来,得到一个值

Optional<T> reduce(BinaryOperator<T> accumulator);

T reduce(T identity, BinaryOperator<T> accumulator);

      参数说明:

     BinaryOperator<T> 的父接口 --->  BiFunction<T, U, R>  ---> R apply(T t, U u);

<U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner)

代码如下:

   List<Integer>  list = Arrays.asList(1,2,3);
        Integer reduce = list.stream()
                .reduce(0, (x, y) -> x + y);
        // 6  说明:0 作为identity ,x 为 0 y 为 1 ,0 + 1 作为新的x ,y为 2 ,0 + 1 + 2 作为新的x,y 为3
        System.out.println(reduce);

 List<Employee>  list = Arrays.asList(
                new Employee("张三",10,Double.valueOf(100)),
                new Employee("李四",20,Double.valueOf(200)),
                new Employee("王五",30,Double.valueOf(300))
                );
        //集合中员工总薪资  Stream 中没有 sum方法
        Optional<Double> max = list.stream()
                .map(Employee::getSalary)
                //  Optional<T> max(Comparator<? super T> comparator);
                .max(Double::compareTo);
        // Optional[300.0]
        System.out.println(max);
        // 300.0
        System.out.println(max.get());
        Optional<Double> min = list.stream()
                .map(Employee::getSalary)
                //  Optional<T> min(Comparator<? super T> comparator);
                .min((x,y)->{
                    return (BigDecimal.valueOf(x).intValue() - (BigDecimal.valueOf(y)).intValue());
                } );
        // Optional[100.0]
        System.out.println(min);
        // 100.0
        System.out.println(min.get());

        // 薪资求和
        Optional<Double> sumOpt = list.stream()
                .map(Employee::getSalary)
                .reduce(Double::sum);
        // Optional[600.0]
        System.out.println(sumOpt);
        // 600.0
        System.out.println(sumOpt.get());

收集器:Stream的 collect

Collectors 这个工具类提供了很多静态方法

①转为list,set集合

   List<Employee>  list = Arrays.asList(
                new Employee("张三",10,Double.valueOf(100)),
                new Employee("张三",10,Double.valueOf(100)),
                new Employee("李四",20,Double.valueOf(200)),
                new Employee("王五",30,Double.valueOf(300))
                );


        List<Employee> collect = list.stream().collect(Collectors.toList());
        collect.stream().forEach(System.out::println);
        System.out.println("----------------------------我是快乐的分割线----------------------------");
        // 去重,将元素放到set集合里
        Set<Employee> collect1 = list.stream().collect(Collectors.toSet());
        collect1.stream().forEach(System.out::println);
结果如下
Employee{name='张三', age=10, salary=100.0}
Employee{name='张三', age=10, salary=100.0}
Employee{name='李四', age=20, salary=200.0}
Employee{name='王五', age=30, salary=300.0}
----------------------------我是快乐的分割线----------------------------
Employee{name='张三', age=10, salary=100.0}
Employee{name='王五', age=30, salary=300.0}
Employee{name='李四', age=20, salary=200.0}

//自定义java类放到set里要重写equals和hashCode
package com.example.demo;

import java.math.BigDecimal;
import java.util.Objects;

/**
 * @program: springboot_01
 * @description:
 * @author: guoyiguang
 * @create: 2021-01-09 21:54
 **/
public class Employee {
    private String name;
    private Integer age;
    private Double salary;

    public Employee() {

    }

    public Employee(String name, Integer age, Double salary) {
        this.name = name;
        this.age = age;
        this.salary = salary;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Double getSalary() {
        return salary;
    }

    public void setSalary(Double salary) {
        this.salary = salary;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", salary=" + salary +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return Objects.equals(name, employee.name) &&
                Objects.equals(age, employee.age) &&
                Objects.equals(salary, employee.salary);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age, salary);
    }
}

Collectors 的 toCollection 方法指定返回的集合类型

Collector<T, ?, C> toCollection(Supplier<C> collectionFactory) 
  List<Employee>  list = Arrays.asList(
                new Employee("张三",10,Double.valueOf(100)),
                new Employee("张三",10,Double.valueOf(100)),
                new Employee("李四",20,Double.valueOf(200)),
                new Employee("王五",30,Double.valueOf(300))
                );


       // 指定返回集合
        // 指定 HashSet
        HashSet<Employee> collect = list.stream()
                //ollectors.toCollection(Supplier<T>)  形参是提供型接口
                .collect(Collectors.toCollection(() -> new HashSet<>()));
        collect.stream().forEach(System.out::println);
        System.out.println("------------------------------------------------");

        // 等价于下面写法   new 一个对象可以考虑构造器引用
        HashSet<Employee> collect2 = list.stream()
                //ollectors.toCollection(Supplier<T>)  形参是提供型接口
                .collect(Collectors.toCollection(HashSet::new));
        collect2.stream().forEach(System.out::println);

结果如下:

Employee{name='张三', age=10, salary=100.0}
Employee{name='王五', age=30, salary=300.0}
Employee{name='李四', age=20, salary=200.0}
------------------------------------------------
Employee{name='张三', age=10, salary=100.0}
Employee{name='王五', age=30, salary=300.0}
Employee{name='李四', age=20, salary=200.0}
------------------------------------------------
Employee{name='张三', age=10, salary=100.0}
Employee{name='张三', age=10, salary=100.0}
Employee{name='李四', age=20, salary=200.0}
Employee{name='王五', age=30, salary=300.0}

Collectors 里提供静态的 总数,求和,平均值,最大,最小

Collectors.summingDouble 求和的

Collectors 里提供静态的 summarizingDouble  概要,返回的值是DoubleSummaryStatistics 类型的,可以拿到 double类型的 总和,总数量,最大,最小,平均值

③和④的代码如下:

 List<Employee>  list = Arrays.asList(
                new Employee("张三",10,Double.valueOf(100)),
                new Employee("张三",10,Double.valueOf(100)),
                new Employee("李四",20,Double.valueOf(200)),
                new Employee("王五",30,Double.valueOf(300))
                );


       // ③Collectors 里提供静态的 总数,平均值,最大,最小
        Long count = list.stream()
                // 底层是归约算的 :reducing(0L, e -> 1L, Long::sum);
                .collect(Collectors.counting());
        System.out.println(count);
        long count1 = list.stream()
                .count();
        System.out.println(count1);
        Double sum = list.stream()
                .collect(Collectors.summingDouble(e -> e.getSalary()));
        // 700.0
        System.out.println(sum);

        Double ave = list.stream()
                .collect(Collectors.averagingInt(e -> e.getSalary().intValue()));
        System.out.println(ave);

        Optional<Double> max1 = list.stream()
                .map(Employee::getSalary)
                // Comparator<? super T> comparator
                .collect(Collectors.maxBy(Double::compareTo));
        // 300.0
        System.out.println(max1.get());

        Optional<Employee> min1 = list.stream()
                // 不做映射处理,x,y 就是 Employee
                // .map(Employee::getSalary)
                .collect(Collectors.minBy((x, y) -> (BigDecimal.valueOf(x.getSalary()).subtract(BigDecimal.valueOf(y.getSalary()))).intValue()));
        // Employee{name='张三', age=10, salary=100.0} ;如果上面做了 .map(Employee::getSalary) 处理,拿到的是  100.0
        System.out.println(min1.get());

        // ④Collectors 里提供静态的 summarizingDouble  概要,返回的值是DoubleSummaryStatistics 类型的,可以拿到 double类型的 总和,总数量,最大,最小,平均值
        DoubleSummaryStatistics collect = list.stream()
                .map(Employee::getSalary)
                // summarizingDouble(ToDoubleFunction<? super T> mapper) 是函数型接口
                .collect(Collectors.summarizingDouble(x -> x));
        System.out.println(collect.getCount());
        System.out.println(collect.getSum());
        System.out.println(collect.getMax());
        System.out.println(collect.getMin());
        System.out.println(collect.getAverage());

⑤ Collectors 的分组函数(有三个)

public static <T, K> Collector<T, ?, Map<K, List<T>>> groupingBy(Function<? super T, ? extends K> classifier)
 Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier, Collector<? super T, A, D> downstream)
 public static <T, K, D, A, M extends Map<K, D>> Collector<T, ?, M> groupingBy(Function<? super T, ? extends K> classifier,Supplier<M> mapFactory,Collector<? super T, A, D> downstream)

代码如下:

 List<Employee>  list = Arrays.asList(
                new Employee("张三",10,Double.valueOf(100)),
                new Employee("张三",15,Double.valueOf(150)),
                new Employee("李四",20,Double.valueOf(200)),
                new Employee("王五",30,Double.valueOf(300))
                );
        // 分组
        Map<String, List<Employee>> collect = list.stream()
                // public static <T, K> Collector<T, ?, Map<K, List<T>>> groupingBy(Function<? super T, ? extends K> classifier)
                // Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier, Collector<? super T, A, D> downstream)
                // public static <T, K, D, A, M extends Map<K, D>> Collector<T, ?, M> groupingBy(Function<? super T, ? extends K> classifier,Supplier<M> mapFactory,Collector<? super T, A, D> downstream)

                .collect(Collectors.groupingBy(Employee::getName));
        System.out.println(collect);

        // 多级分组
        Map<String, Map<Integer, List<Employee>>> collect1 = list.stream()
                .collect(Collectors.groupingBy(Employee::getName, Collectors.groupingBy(e -> e.getAge())));

⑥Collectors 分区

Collectors.partitioningBy
 List<Employee>  list = Arrays.asList(
                new Employee("张三",10,Double.valueOf(100)),
                new Employee("张三",15,Double.valueOf(150)),
                new Employee("李四",20,Double.valueOf(200)),
                new Employee("王五",30,Double.valueOf(300))
                );
        // 分区
        Map<Boolean, List<Employee>> collect = list.stream()
                // Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate)
                .collect(Collectors.partitioningBy(e -> e.getSalary().intValue() < 200));
        System.out.println(collect);

打印结果格式化后:

⑦Collectors.join 拼接,要求是字符串

 List<Employee>  list = Arrays.asList(
                new Employee("张三",10,Double.valueOf(100)),
                new Employee("张三",15,Double.valueOf(150)),
                new Employee("李四",20,Double.valueOf(200)),
                new Employee("王五",30,Double.valueOf(300))
                );
        String collect = list.stream()
                .map(Employee::getName)
                // public static Collector<CharSequence, ?, String> joining()
                .collect(Collectors.joining());
        // 张三张三李四王五
        System.out.println(collect);
        String collect2 = list.stream()
                .map(Employee::getName)
                // public static Collector<CharSequence, ?, String> joining()
                .collect(Collectors.joining(","));
        // 张三,张三,李四,王五
        System.out.println(collect2);

Optional类

代表一个值存在不存在,可以用来避免空指针

   // 创建 Optional(模拟从redis获取数据)
        Optional<Employee> employeeOpt = Optional.of(new Employee("王五",30,Double.valueOf(300)));
        // 空指针 模拟从数据库查出 Employee,并放到 Optional里
        //Employee nullEmp = null;
        //Optional.of(nullEmp); // 可以迅速定位 Optional.of(nullEmp) 这出异常了
        Optional<Employee> emptyOpt = Optional.empty();
        // java.util.NoSuchElementException: No value present
        //System.out.println(emptyOpt.get());
        Optional<Employee> ofNullOpt= Optional.ofNullable(new Employee("张三", 10, Double.valueOf(100)));
        if (employeeOpt.isPresent()) {
            // employeeOpt  里有 value 为:Employee{name='王五', age=30, salary=300.0}
            //System.out.println(" employeeOpt  里有 value 为:"+employeeOpt.get().toString());
        }else{
            // 模拟从数据库查数据
            //Employee emp = employeeOpt.orElse(new Employee("王五", 30, Double.valueOf(300)));
            Employee emp = employeeOpt.orElseGet(Employee::new); // 类似之前的 if  else
        }

        // orElseGet(Supplier<? extends T> other) 容器里有对象就返回,否则就用  Supplier 内部抽象方法实现的对象
        Employee employee = emptyOpt.orElseGet(() -> new Employee("李四", 20, Double.valueOf(200)));
        Optional<String> s = emptyOpt.map(e -> e.getName());
        System.out.println(s.get());

        // flatMap(Function<? super T, Optional<U>> mapper)  接受T 返回 Optional
        // 获取包装对象里的属性
        Optional<String> o = emptyOpt.flatMap(e -> Optional.of(e.getName()));

在代码中如何避免空指针的?

  // java 8 之前 获取员工老板姓名
        Boss xiaoMa = new Boss("马化腾", 60);
        Employee emp = new Employee("张小龙", 50, Double.valueOf(80), xiaoMa);
        String boosName ;
        if (null != emp) {
            if (null != emp.getBoss()) {
                boosName = emp.getBoss().getName();
            }
        }
        // java 8 用Optional 代替 null,消除 了 if(null != 对象引用){}else{创建对象}
        Optional<Employee> empOpt = Optional.ofNullable(new Employee("张小龙", 50, Double.valueOf(80), null));
        // 有就获取没有就创建 , 这样保证了 emp1 肯定不是空的;orElse 也可以达到一样的效果
        Employee emp1 = empOpt.orElseGet(() -> new Employee("张小龙(1)", 50, Double.valueOf(80), xiaoMa));
        Optional<Boss> bossOpt = Optional.ofNullable(emp1.getBoss());
        // 保证了boss不为空
        Boss boss = bossOpt.orElseGet(() -> new Boss("马化腾(1)", 60));
        // 马化腾(1)
        System.out.println(boss.getName());

日期:

LocalDate

 LocalDateTime now = LocalDateTime.now();
        // 2021-01-10T15:46:52.355
        System.out.println(now);
        LocalDateTime of = LocalDateTime.of(2021, 1, 10, 15, 40, 50);
        // 2021-01-10T15:40:50
        System.out.println(of);
        LocalDateTime tenYearsLater = now.plusYears(10L);
        // 2031-01-10T15:50:24.296
        System.out.println(tenYearsLater);
        System.out.println("获取年月日小时分钟秒");
        System.out.println(now.getYear());
        // JANUARY
        System.out.println(now.getMonth());
        // 10
        System.out.println(now.getDayOfMonth());
        // 10
        System.out.println(now.getDayOfYear());
        System.out.println(now.getHour());
        System.out.println(now.getMinute());
        System.out.println(now.getSecond());

  //
        LocalDate start = LocalDate.now();
        // 2021-01-10
        System.out.println(start);
        LocalDate end = LocalDate.now();
        Period between1 = Period.between(start, end);
        // 最少精确到日
        System.out.println(between1.getDays());
        // 时间戳: 从 1970 年开始到现在的毫秒值
       Instant ins = Instant.now();
       // 2021-01-10T07:56:10.131Z  时间不对;此刻是 15:58
        System.out.println(ins);
        OffsetDateTime offsetNow = ins.atOffset(ZoneOffset.ofHours(8));
        // 2021-01-10T15:59:24.551+08:00
        System.out.println(offsetNow);
        Instant ins2 = Instant.now();
        Duration between = Duration.between(ins, ins2);
        // 时间段差了几毫秒;几天,几小时,几分钟
        System.out.println(between.toMillis());

时间矫正器:

   // 时间矫正器
        LocalDate now = LocalDate.now();
        // 2021-01-10
        System.out.println(now);
        LocalDate with = now.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
        // 2021-01-17
        System.out.println(with);

        LocalDateTime nowTime = LocalDateTime.now();
        // 2021-01-10T16:15:05.441
        System.out.println(nowTime);
        LocalDateTime future = nowTime.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
        // 2021-01-17T16:14:51.428
        System.out.println(future);

DateTimeFormatter 格式化日期:

 // 格式化日期 (转成字符串,转成日期)
        DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE_TIME;
        LocalDateTime now = LocalDateTime.now();
        String format = now.format(dtf);
        // 2021-01-10T16:20:30.951
        System.out.println(format);

        DateTimeFormatter dtf2 = DateTimeFormatter.ISO_DATE;
        LocalDate nowDate = LocalDate.now();
        String format1 = nowDate.format(dtf2);
        // 2021-01-10
        System.out.println(format1);

        // 自定义格式化日期形式
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
        LocalDateTime nowTime = LocalDateTime.now();
        String format2 = nowTime.format(dateTimeFormatter);
        // 2021年01月10日 16:23:52
        System.out.println(format2);

        LocalDateTime parse1 = nowTime.parse(format2,dateTimeFormatter);
        // 2021-01-10T16:34:52
        System.out.println(parse1);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值