Java 11 - Java8 新特性

1、Lambda 表达式

1.1、介绍

1、什么是 Lambda 表达式

  • 匿名内部类:可以作为接口对象的引用(重写了接口的抽象方法)。
  • Lambda 表达式:可以作为接口对象的引用(匿名内部类的简写方式)。
public class T01_Lambda {
    @Test
    public void test01() {
        // 匿名内部类
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("开启新的线程 ...");
            }
        };

        Thread thread = new Thread(runnable);
        thread.start();
    }

    public void test02() {
        // Lambda 表达式
        Runnable runnable = () -> System.out.println("开启新的线程 ...");

        Thread thread = new Thread(runnable);
        thread.start();
    }
}

2、Lambda 表达式语法

  • Lambda 表达式分为两个部分
    • 左边:参数列表,对应接口抽象方法的参数列表。
    • 右边:具体功能,对应接口抽象方法的内部代码。
(参数列表) -> { 代码/表达式 }
  • Lambda 表达式的特点(能省则省)
    • 参数类型可以省略(类型推断)。
    • 单个参数可以省略小括号。
    • 单个语句可以省略大括号。
    • 单个语句而且有返回值,可以省略 return 与大括号,简化为表达式。

1.2、示例

public class T03_LambdaSyntax {
    public static void main(String[] args) {
        // 1、无参无返回值
        Print01 p1 = () -> System.out.println("你好");
        p1.print();

        // 2、单个参数无返回值
        Print02 p2 = s -> System.out.println(s);
        p2.print("你好");

        // 3、多个参数无返回值
        Math01 m1 = (x, y) -> System.out.println(x * y);
        m1.operation(10, 15);

        // 4、多个参数有返回值
        Math02 m2 = (x, y) -> x * y;
        System.out.println(m2.operation(10, 15));
    }

    public interface Print01 {
        // 1、无参无返回值
        void print();
    }

    public interface Print02 {
        //2、单个参数无返回值
        void print(String s);
    }

    public interface Math01 {
        // 3、多个参数无返回值
        void operation(int x, int y);
    }

    public interface Math02 {
        // 4、多个参数有返回值
        int operation(int x, int y);
    }
}

1.3、存在问题:foreach() 方法中使用 Lambda 如何提前终止

  • 存在问题:使用 foreach() 方法遍历集合,其内部为 Lambda 表达式。需要提前终止遍历,但是 continue、break 直接报错。
  • 原因分析:因为 foreach() 是方法而不是循环语句,因此无法使用 continue、break。终止方法可以 return 或者抛出异常。
  • 如何解决
    • 方式一:使用 foreach() 方法遍历集合,使用 return 终止遍历。后续代码继续执行,相当于 continue
    • 方式二:使用 foreach() 方法遍历集合,使用 throw 抛出异常但不处理。后续代码没有执行,相当于 break
    • 方式三:使用增强 for 循环遍历集合,使用 break、continue 终止遍历
public class T03_LambdaForeach {
    // 方式一:使用 foreach() 方法遍历集合,使用 return 终止遍历。后续代码继续执行,**相当于 continue**。
    @Test
    public void test01() {
        List<String> list = Arrays.asList("A", "B", "C");
        list.forEach(s -> {
            if ("B".equals(s)) {
                System.out.print(" 终止或跳出循环 ");
//                continue;
//                break;
                return;
            }
            System.out.print(s);
        });
        // 结果:A 终止或跳出循环 C
    }

    // 方式二:使用 foreach() 方法遍历集合,使用 throw 抛出异常但不处理。后续代码没有执行,**相当于 break**。
    @Test
    public void test02() {
        List<String> list = Arrays.asList("A", "B", "C");
        try {
            list.forEach(s -> {
                if ("B".equals(s)) {
                    System.out.print(" 终止或跳出循环 ");
                    throw new RuntimeException(" 终止或跳出循环 ");
                }
                System.out.print(s);
            });
        } catch (RuntimeException e) {
        }
        // 结果:A 终止或跳出循环
    }

    // 方式三:使用增强 for 循环遍历集合,**使用 continue、break 终止遍历**。
    @Test
    public void test03() {
        List<String> list = Arrays.asList("A", "B", "C");
        for (String s : list) {
            if ("B".equals(s)) {
                System.out.print(" 终止或跳出循环 ");
//                continue;
                break;
            }
            System.out.print(s);
        }
        // continue 结果:A 终止或跳出循环 C
        // break 结果:A 终止或跳出循环
    }
}

2、方法引用

2.1、介绍

  • 方法引用:可以作为接口对象的引用(Lambda 表达式的简写方式,前提是该 Lambda 表达式存在已有实现)。
  • 方法引用分类
    • 调用实例方法:对象::实例方法名
    • 调用实例方法:类名::实例方法名(注意:Java 代码中不允许类名调用实例方法,方法引用可以)
    • 调用静态方法:类名::静态方法名
    • 调用构造方法:类名::new(只能调用无参构造)
    • 调用数组构造方法:类名[]::new(只能调用无参构造)

2.2、示例

// 方法引用
public class T01_MethodReference {
    // 调用实例方法:实例::实例方法名
    @Test
    public void test01() {
        Consumer<String> consumer1 = s -> System.out.println(s);
        consumer1.accept("张三");
        // 以上 Lambda 表达式,存在已有实现(out 实例的方法),因此可替换为方法引用
        Consumer<String> consumer2 = System.out::println;
        consumer2.accept("张三");
    }

    // 调用实例方法:类名::实例方法名
    @Test
    public void test02() {
        Function<String, Integer> function1 = s -> s.length();
        System.out.println(function1.apply("张三"));
        // 以上 Lambda 表达式,存在已有实现(String 类的实例方法),因此可替换为方法引用
        Function<String, Integer> function2 = String::length;
        System.out.println(function2.apply("张三"));
    }

    // 调用静态方法:类名::静态方法名
    @Test
    public void test03() {
        Function<Integer, String> function1 = integer -> String.valueOf(integer);
        System.out.println(function1.apply(30));
        // 以上 Lambda 表达式,存在已有实现(String 类的静态方法),因此可替换为方法引用
        Function<Integer, String> function2 = String::valueOf;
        System.out.println(function2.apply(30));
    }

    // 调用构造方法:类名::new
    @Test
    public void test04() {
        Supplier<Object> supplier1 = () -> new Object();
        System.out.println(supplier1.get());
        // 以上 Lambda 表达式,存在已有实现(Object 类的构造方法),因此可替换为方法引用
        Supplier<Object> supplier2 = Object::new;
        System.out.println(supplier2.get());
    }

    // 调用数组构造方法:类名[]::new
    @Test
    public void test05() {
        Function<Integer, String[]> function1 = integer -> new String[integer];
        System.out.println(Arrays.toString(function1.apply(10)));
        // 以上 Lambda 表达式,存在已有实现(String 数组的构造方法),因此可替换为方法引用
        Function<Integer, String[]> function2 = String[]::new;
        System.out.println(Arrays.toString(function2.apply(10)));
    }
}

2.3、匿名内部类、Lambda 表达式、方法引用的关系

  • 匿名内部类:可以作为接口对象的引用(重写了接口的抽象方法)。
  • Lambda 表达式:可以作为接口对象的引用(匿名内部类的简写方式)。
  • 方法引用:可以作为接口对象的引用(Lambda 表达式的简写方式,前提是该 Lambda 表达式存在已有实现)。

3、函数式接口

3.1、介绍

1、什么是函数式接口

  • 如果某个接口“只有一个抽象方法”(只有一个方法需要实现),则该接口为函数式接口。
  • 函数式接口的实现类对象可以使用 Lambda 表达式来表示

2、@FunctionalInterface 注解

  • @FunctionalInterface 注解表示该接口为函数式接口,若不符合要求则会报错(作用类似 @Override 注解,若该方法不符合重写要求则会报错)。
  • 函数式接口具有以下特点:
    • 只有一个抽象方法”(只有一个方法需要实现)。
    • 该抽象方法包括继承自其他接口的抽象方法。
    • 该抽象方法不包括默认方法、静态方法、私有方法(因为这些方法本身提供实现)。
    • 该抽象方法不包括重写 Object 类的方法(因为所有的类默认继承 Object 类,这些方法 Object 类已经实现)。
// 自定义函数式接口
@FunctionalInterface
public interface T01_FunctionalInterface {
    void print();

    default void print(Integer i) {
        System.out.println(i);
    }

    static void print(String s) {
        System.out.println(s);
    }

    String toString();
}

3、四大核心函数式接口

  • Consumer 接口:消费型接口。接收参数无返回值。
  • Supplier 接口:供给型接口。不接收参数有返回值。
  • Function 接口:函数型接口。接收参数有返回值。
  • Predicate 接口:断定型接口。接收参数返回布尔值。
public class T02_FunctionalInterface {
    public static void main(String[] args) {
        Consumer<Integer> consumer = x -> x = x + 10;
        Supplier<Integer> supplier = () -> 5 * 5;
        Function<Integer, Integer> function = x -> x * x;
        Predicate<Integer> predicate = x -> x > 10;
    }
}

3.2、Consumer 消费型接口

1、Consumer 接口

  • 抽象方法:accept():执行指定函数
  • 默认方法:andThen():返回组合函数。然后执行
package java.util.function;

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);

    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

2、示例

  • 指定字符串,先输出其长度,再输出其大写,再输出其小写。
// 指定字符串,先输出其长度,再输出其大写,再输出其小写
public class T01_Consumer {
    @Test
    public void test01() {
        print("Java", s -> System.out.println(s.length()), s -> System.out.println(s.toUpperCase()), s -> System.out.println(s.toLowerCase()));
    }

    public void print(String s, Consumer<String> c1, Consumer<String> c2, Consumer<String> c3) {
        // 组合多个函数
        Consumer<String> consumer = c1.andThen(c2).andThen(c3);
        // 执行函数
        consumer.accept(s);
    }
}

3.3、Supplier 供给型接口

1、Supplier 接口

  • 抽象方法:get():执行指定函数
package java.util.function;

@FunctionalInterface
public interface Supplier<T> {
    T get();
}

2、示例

  • 产生 10 个 0~100 之间的整数,添加到集合中。
// 产生 10 个 0~100 之间的整数,添加到集合中
public class T01_Supplier {
    @Test
    public void test01() {
        List<Integer> list = getList(10, () -> (new Random().nextInt(100)));
        list.forEach(System.out::println);
    }

    public List<Integer> getList(int length, Supplier<Integer> supplier) {
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < length; i++) {
            // 执行函数
            Integer integer = supplier.get();// 每次执行获得一个结果
            list.add(integer);
        }
        return list;
    }
}

3.4、Function 函数型接口

1、Function 接口

  • 抽象方法:apply():执行指定函数
  • 默认方法
    • compose():返回组合函数。将前一个函数的结果,作为后一个函数的参数
    • andThen():返回组合函数。然后执行
  • 静态方法:identity():返回一个函数。该函数为输入参数
package java.util.function;

@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);

    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }

    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }

    static <T> Function<T, T> identity() {
        return t -> t;
    }
}

2、示例

  • 输入“张三,30”,先截取年龄,再转为数字,再给年龄加 1。
// 输入“张三,30”,先截取年龄,再转为数字,再给年龄加 1
public class T01_Function {
    @Test
    public void test01() {
        Integer calc = calc("张三,30", s -> s.trim().split(",")[1], s -> Integer.parseInt(s), s -> s + 1);
        System.out.println(calc);
    }

    public Integer calc(String s, Function<String, String> f1, Function<String, Integer> f2, Function<Integer, Integer> f3) {
        // 返回组合函数。将前一个函数的结果,作为后一个函数的参数
        Function<String, Integer> function = f3.compose(f2.compose(f1));// 先将 f1 的结果作为 f2 的参数,再将 f2 的结果作为 f3 的参数
        return function.apply(s);
    }
}

3.5、Predicate 断言型接口

1、Predicate 接口

  • 抽象方法:test():执行指定函数
  • 默认方法
    • and():返回组合函数。逻辑且
    • negate():返回组合函数。逻辑非
    • or():返回组合函数。逻辑或
  • 静态方法:isEqual():返回一个函数。判断输入参数是否等于目标对象
package java.util.function;

@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);

    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }

    default Predicate<T> negate() {
        return (t) -> !test(t);
    }

    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }

    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }
}

2、Predicate 接口示例

    @Test
    public void test01() {
        isTrue("ABC", s -> s.startsWith("A"), s -> s.length() == 2);
    }

    public void isTrue(String s, Predicate<String> p1, Predicate<String> p2) {
        System.out.println("是否以 A 开始:" + p1.test(s));
        System.out.println("是否非 A 开始:" + p1.negate().test(s));
        System.out.println("是否以 A 开始,而且长度为 3:" + p1.and(p2).test(s));
        System.out.println("是否以 A 开始,或者长度为 3:" + p1.or(p2).test(s));
        System.out.println("输入参数是否等于 ABC:" + Predicate.isEqual("ABC").test(s));
    }
}

4、Stream 流

4.1、介绍

1、什么是 Stream 流

  • Stream 流可以将集合(数组、Collection 单列集合、Map 双列集合)看做是一个流,并对集合中的元素进行各种操作。例如:筛选、遍历、排序、映射、收集、聚合等等。
  • Stream 流相比直接操作集合,代码简洁,功能强大。
  • 根据 Stream 对象方法的返回值类型,Stream 流分为两种操作
    • 中间操作:返回值类型为 Stream 流,可以继续进行其他流式操作。
    • 终结操作:返回值类型为其他对象,不能继续进行其他流式操作。
  • 注意事项
    • 每次调用中间操作,就会生成新的 Stream 对象。
    • 只有调用终结操作,中间操作才会执行。
    • 调用终结操作之后,Stream 对象不能再次使用,否则会发生非法状态异常 IllegalStateException。
    • 不用手动关闭(指向内存的流不用关闭,指向硬盘/网络等等外部资源的流需要关闭)。

2、如何获取 Stream 流

  • Array 数组:一是使用 Arrays 类的静态方法 stream(T[] array),二是使用 Stream 的静态方法 of()、iterate()、generate()。
  • Collection 单列集合:直接使用 Collection 接口的默认方法 stream()。
  • Map 双列集合:需要先将 Map 转换为 Collection,然后间接使用 Collection 接口的默认方法 stream()。
public class T01_GetStream {
    @Test
    public void test01() {
        String[] s = new String[]{"张三", "李四", "王五"};
        Arrays.stream(s).forEach(System.out::println);// 张三  李四 王五
        Stream.of(s).forEach(System.out::println);// 张三  李四 王五
    }

    @Test
    public void test02() {
        Collection<String> collection = Arrays.asList("张三", "李四", "王五");
        collection.stream().forEach(System.out::println);// 张三  李四 王五
    }

    @Test
    public void test03() {
        Map<String, String> map = new HashMap<>();
        map.put("张三", "zhangsan");
        map.put("李四", "lisi");
        map.put("王五", "wangwu");
        map.keySet().stream().forEach(System.out::print);// 李四 张三 王五
        map.values().stream().forEach(System.out::println);// lisi zhangsan wangwu
        map.entrySet().stream().forEach(System.out::println);// 李四=lisi 张三=zhangsan 王五=wangwu
    }
}

4.2、相关接口

package java.util.stream;
public interface BaseStream<T, S extends BaseStream<T, S>> extends AutoCloseable {
    Iterator<T> iterator();
    Spliterator<T> spliterator();
    boolean isParallel();
    S sequential();
    S parallel();
    S unordered();
    S onClose(Runnable closeHandler);
    @Override
    void close();
}

4.3、Optional 类

  • 容器,用来存储对象。经常作为 Stream 流部分方法的返回值。
  • 特点:final 类,私有构造方法。
package java.util;
public final class Optional<T> {
    private static final Optional<?> EMPTY = new Optional<>();
    private final T value;
    private Optional() {
        this.value = null;
    }
    public static<T> Optional<T> empty() {}
    public static <T> Optional<T> of(T value) {}
    public static <T> Optional<T> ofNullable(T value) {}
    public T get() {}// 获取
    public boolean isPresent() {}// 判断是否存在
    public void ifPresent(Consumer<? super T> consumer) {}// 如果存在,执行消费函数
    public Optional<T> filter(Predicate<? super T> predicate) {}// 过滤,根据断定函数
    public <U> Optional<U> map(Function<? super T, ? extends U> mapper) {}// 映射,根据函数
    public <U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {}// 映射,根据函数
    public T orElse(T other) {}// 如果存在,返回该值,否则返回 T other
    public T orElseGet(Supplier<? extends T> other) {}// 如果存在,返回该值,否则返回供给型函数生成的结果
    public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {}// 如果存在,返回该值,否则抛出供给函数生成的异常
}

4.4、常用方法介绍

  • 常用方法
    • 遍历 forEach、排序 sort、过滤 filter、映射 map、归纳 reduce、窥视 peek
  • 其他方法
    • 最小 min、最大 max、计数 count、匹配 match、查找 find
    • 去重 distinct、限量 limit、跳过 skip
  • 静态方法
    • 返回流构建器、返回空流、转换为流、生成无限流、合并流
  • 收集
    • 转换为数组、收集为集合
package java.util.stream;
public interface Stream<T> extends BaseStream<T, Stream<T>> {
    // 1、遍历
    void forEach(Consumer<? super T> action);// 遍历
    void forEachOrdered(Consumer<? super T> action);// 顺序遍历
    // 2、排序
    Stream<T> sorted();// 自然排序
    Stream<T> sorted(Comparator<? super T> comparator);// 比较器排序
    // 3、过滤
    Stream<T> filter(Predicate<? super T> predicate);
    // 4、映射
    <R> Stream<R> map(Function<? super T, ? extends R> mapper);
    IntStream mapToInt(ToIntFunction<? super T> mapper);
    LongStream mapToLong(ToLongFunction<? super T> mapper);
    DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper);
    <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
    IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper);
    LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper);
    DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper);
    // 5、归纳
    Optional<T> reduce(BinaryOperator<T> accumulator);// 不能改变归纳类型,无初始值
    T reduce(T identity, BinaryOperator<T> accumulator);// 不能改变归纳类型,有初始值
    <U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner);// 可以改变归纳类型,有初始值
    // 6、窥视
    Stream<T> peek(Consumer<? super T> action);
    // 7.1、最小、最大、计数、匹配、查找
    Optional<T> min(Comparator<? super T> comparator);// 最小
    Optional<T> max(Comparator<? super T> comparator);// 最大
    long count();// 计数
    boolean anyMatch(Predicate<? super T> predicate);// 匹配(任意一个符合条件则返回 true)
    boolean allMatch(Predicate<? super T> predicate);// 匹配(全部元素符合条件则返回 true)
    boolean noneMatch(Predicate<? super T> predicate);// 匹配(没有一个符合条件则返回 true)
    Optional<T> findFirst();// 查找
    Optional<T> findAny();// 查找
    // 7.2、去重、限量、跳过
    Stream<T> distinct();
    Stream<T> limit(long maxSize);// 限量
    Stream<T> skip(long n);// 跳过
    // 8、静态方法
    public static<T> Builder<T> builder() {}// 返回流构建器,用于构建流
    public static<T> Stream<T> empty() {}// 返回空流,然后使用 concat() 合并流
    public static<T> Stream<T> of(T t) {}// 转换为流
    public static<T> Stream<T> of(T... values) {}// 转换为流
    public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) {}// 生成无限流,根据指定种子
    public static<T> Stream<T> generate(Supplier<T> s) {}// 生成无限流
    public static<T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) {}// 合并流
    public interface Builder<T> extends Consumer<T> {
        @Override
        void accept(T t);
        default Builder<T> add(T t) {}
        Stream<T> build();
    }
    // 9.1、转换为数组
    Object[] toArray();// 收集为 Object 类型的数组
    <A> A[] toArray(IntFunction<A[]> generator);// 收集为指定类型的数组
    // 9.2、收集为集合
    <R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner);// 自定义收集
    <R, A> R collect(Collector<? super T, A, R> collector);// 指定收集器收集
}
  • Employee 类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Employee {
    private String name;
    private String gender;
    private Integer age;
    private String address;
    private Double salary;

    public static List<Employee> getList() {
        List<Employee> list = new ArrayList<>();
        list.add(new Employee("张三", "男", 17, "西安", 6500.0D));
        list.add(new Employee("李四", "女", 19, "郑州", 4000.0D));
        list.add(new Employee("王五", "男", 18, "上海", 4800.0D));
        list.add(new Employee("赵六", "女", 20, "北京", 4000.0D));
        list.add(new Employee("钱七", "男", 22, "武汉", 4500.0D));
        list.add(new Employee("孙八", "女", 21, "南京", 8000.0D));
        return list;
    }
}

4.5、常用方法 - 遍历

/*
    // 1、遍历
    void forEach(Consumer<? super T> action);// 遍历
    void forEachOrdered(Consumer<? super T> action);// 顺序遍历
 */
public class T01_Foreach {
    @Test
    public void test01() {
        List<String> list = Arrays.asList("B", "C", "A");
        list.stream().forEach(System.out::println);
        list.stream().forEachOrdered(System.out::println);
    }
}

4.6、串行流与并行流

1、如何获取并行流

  • 方式一:将串行流转换为并行流
  • 方式二:直接生成并行流
// 如何获取并行流
public class T01_GetParallelStream {
    @Test
    public void test01() {
        List<String> list = new ArrayList<>();
        // 方式一:将串行流转换为并行流
        Stream<String> s1 = list.stream().parallel();
        // 方式二:直接生成并行流
        Stream<String> s2 = list.parallelStream();
    }
}

2、串行流与并行流的区别

  • 遍历区别:foreach() 与 foreachOrdered() 方法,串行流下两者结果一致,并行流下前者不能保证遍历顺序,后者可以。
  • 查找区别:findAny() 与 findFirst() 方法,串行流下两者都是返回第一个元素,并行流下前者不能保证每次都返回第一个元素,后者可以。
  • 速度区别:并行流比串行流速度更快。
// 串行流与并行流的区别
public class T02_ParallelStream {
    // 遍历区别
    @Test
    public void test01() {
        List<String> list = Arrays.asList("B", "C", "A");
        System.out.println("并行流 forEach() 方法");
        list.parallelStream().forEach(System.out::println);
        System.out.println("并行流 forEachOrdered() 方法");
        list.parallelStream().forEachOrdered(System.out::println);// 结果始终为:B C A
    }

    // 查找区别
    @Test
    public void test02() {
        List<String> list = Arrays.asList("B", "C", "A");
        Optional<String> any = list.parallelStream().findAny();
        System.out.println(any.get());
        Optional<String> first = list.parallelStream().findFirst();
        System.out.println(first.get());// 结果始终为:B
    }
}

4.7、常用方法 - 排序

/*
    // 2、排序
    Stream<T> sorted();// 自然排序
    Stream<T> sorted(Comparator<? super T> comparator);// 比较器排序
 */
public class T01_Sorted {
    // 自然排序
    @Test
    public void test01() {
        List<String> list = Arrays.asList("B", "C", "A");
        list.stream().sorted().forEach(System.out::println);
    }

    // 比较器排序
    @Test
    public void test02() {
        List<Employee> employees = Employee.getList();
        employees.stream().sorted((e1, e2) -> {
            double d = e2.getSalary() - e1.getSalary();
            int i = e1.getAge() - e2.getAge();
            return d > 0 ? 1 : (d < 0 ? -1 : i > 0 ? 1 : (i < 0 ? -1 : 0));
        }).forEach(System.out::println);
    }
}

4.8、常用方法 - 过滤

/*
    // 3、过滤
    Stream<T> filter(Predicate<? super T> predicate);
 */
public class T01_Filter {
    @Test
    public void test01() {
        List<String> list = Arrays.asList("乔峰", "段誉", "虚竹", "鸠摩智", "段正淳", "段延庆", "庄聚贤", "慕容复");
        // 以下写法结果相同
        list.stream().filter(s -> s.startsWith("段")).filter(s -> s.length() == 2).forEach(System.out::println);
        list.stream().filter(s -> s.startsWith("段") && s.length() == 2).forEach(System.out::println);
    }

    @Test
    public void test02() {
        List<Employee> list = Employee.getList();
        // 以下写法结果相同
        list.stream().filter(e -> "男".equals(e.getGender())).filter(e -> e.getSalary() >= 5000.0D).forEach(System.out::println);
        list.stream().filter(e -> "男".equals(e.getGender()) && e.getSalary() >= 5000.0D).forEach(System.out::println);
    }
}

4.9、常用方法 - 映射

1、映射分类

  • 根据方法返回流中元素的数量分为:mapXXX() 一对一映射、faltMapXXX() 一对多映射
  • 根据方法返回流的数据类型分为:Stream、IntStream、LongStream、DoubleStream。Stream 流泛型为引用数据类型,后三个为底层流,专门用于操作基本数据类型

2、示例一

/*
    // 4、映射
    <R> Stream<R> map(Function<? super T, ? extends R> mapper);
    IntStream mapToInt(ToIntFunction<? super T> mapper);
    LongStream mapToLong(ToLongFunction<? super T> mapper);
    DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper);
    <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
    IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper);
    LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper);
    DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper);
 */
public class T01_Map01 {
    // map()
    @Test
    public void test01() {
        List<Employee> list = Employee.getList();
        Stream<String> stream1 = list.stream().map(Employee::getName);
        stream1.forEach(System.out::println);
        // 结果:张三 李四 王五 赵六 钱七 孙八
    }

    // flatMap()
    @Test
    public void test02() {
        List<Employee> list = Employee.getList();
        Stream<String> stream2 = list.stream().flatMap(e -> Stream.of(e.getName().split("")));
        stream2.forEach(System.out::println);
        // 结果:张 三 李 四 王 五 赵 六 钱 七 孙 八
    }

    // map() 与 mapToInt() 的区别
    @Test
    public void test03() {
        List<Employee> list = Employee.getList();
        Stream<Integer> stream = list.stream().map(Employee::getAge);
        IntStream intStream = list.stream().mapToInt(Employee::getAge);
    }

    // flatMap() 与 flatMapToInt() 的区别
    @Test
    public void test04() {
        List<Employee> list = Employee.getList();
        Stream<Integer> stream = list.stream().flatMap(e -> Stream.of(e.getAge(), e.getSalary().intValue()));
        IntStream intStream = list.stream().flatMapToInt(e -> IntStream.of(e.getAge(), e.getSalary().intValue()));
    }
}

3、示例二

/*
    // 4、映射
    <R> Stream<R> map(Function<? super T, ? extends R> mapper);
    IntStream mapToInt(ToIntFunction<? super T> mapper);
    LongStream mapToLong(ToLongFunction<? super T> mapper);
    DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper);
    <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
    IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper);
    LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper);
    DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper);
 */
public class T01_Map02 {
    // 1、所有员工工资加 1000
    @Test
    public void test01() {
        List<Employee> list = Employee.getList();
        Stream<Employee> stream = list.stream().map(e -> {
            Employee employee = new Employee();
            employee.setName(e.getName());
            employee.setSalary(e.getSalary() + 1000.0D);
            return employee;
        });
        stream.forEach(System.out::println);
    }

    // 2、所有员工工资加 1000
    @Test
    public void test02() {
        List<Employee> list = Employee.getList();
        Stream<Employee> stream = list.stream().map(e -> {
            e.setSalary(e.getSalary() + 1000.0D);
            return e;
        });
        stream.forEach(System.out::println);
    }
}

4.10、常用方法 - 归纳

  • 归纳总结三种方式的区别
    • 方式一:不能改变归纳类型,无初始值
    • 方式二:不能改变归纳类型,有初始值
    • 方式三:可以改变归纳类型,有初始值
/*
    // 5、归纳
    Optional<T> reduce(BinaryOperator<T> accumulator);// 不能改变归纳类型,无初始值
    T reduce(T identity, BinaryOperator<T> accumulator);// 不能改变归纳类型,有初始值
    <U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner);// 可以改变归纳类型,有初始值
 */
public class T01_Reduce {
    // 员工年龄求和
    @Test
    public void test01() {
        List<Employee> list = Employee.getList();
        Optional<Integer> reduce = list.stream().map(Employee::getAge).reduce(Integer::sum);
        System.out.println(reduce.get());
    }

    // 员工年龄求和
    @Test
    public void test02() {
        List<Employee> list = Employee.getList();
        Integer reduce = list.stream().map(Employee::getAge).reduce(0, Integer::sum);
        System.out.println(reduce);
    }

    // 员工年龄求和
    @Test
    public void test03() {
        List<Employee> list = Employee.getList();
        Integer reduce = list.stream().reduce(0, (age, e) -> Integer.sum(age, e.getAge()), Integer::sum);
        System.out.println(reduce);
    }
}

4.11、常用方法 - 窥视

  • peek()、map()、forEach() 的区别
    • peek():进行消费型操作,返回操作之前的流。额外操作,不会改变流中的数据,但是可以改变流中数据的引用
    • map():进行函数型操作,返回操作之后的流。
    • forEach():进行消费型操作,无返回值。
/*
    // 6、窥视
    Stream<T> peek(Consumer<? super T> action);

    peek()、map()、forEach() 的区别
        peek():进行消费型操作,返回操作之前的流。额外操作,不会改变流中的数据,但是可以改变流中数据的引用。
        map():进行函数型操作,返回操作之后的流。
        forEach():进行消费型操作,无返回值。
    peek()、map()、forEach() 方法
        Stream<T> peek(Consumer<? super T> action);
        <R> Stream<R> map(Function<? super T, ? extends R> mapper);
        void forEach(Consumer<? super T> action);
 */
public class T01_Peek {
    // peek() 不会改变流中的数据
    @Test
    public void test01() {
        List<String> list = Arrays.asList("B", "C", "A");
        list.stream().peek(s -> System.out.println("额外操作:" + s.toLowerCase())).forEach(s -> System.out.println("遍历输出:" + s));
    }

    // peek() 但是可以改变流中数据的引用
    @Test
    public void test02() {
        List<Employee> list = Employee.getList();
        list.stream().peek(e -> e.setAge(100)).forEach(System.out::println);
    }
}

4.12、常用方法 - 其他方法

/*
    // 7.1、最小、最大、计数、匹配、查找
    Optional<T> min(Comparator<? super T> comparator);// 最小
    Optional<T> max(Comparator<? super T> comparator);// 最大
    long count();// 计数
    boolean anyMatch(Predicate<? super T> predicate);// 匹配(任意一个符合条件则返回 true)
    boolean allMatch(Predicate<? super T> predicate);// 匹配(全部元素符合条件则返回 true)
    boolean noneMatch(Predicate<? super T> predicate);// 匹配(没有一个符合条件则返回 true)
    Optional<T> findFirst();// 查找
    Optional<T> findAny();// 查找
    // 7.2、去重、限量、跳过
    Stream<T> distinct();
    Stream<T> limit(long maxSize);// 限量
    Stream<T> skip(long n);// 跳过
 */
public class T01_OtherMethods {
    @Test
    public void test01() {
        List<Employee> list = Employee.getList();
        // 最小
        Optional<Employee> min = list.stream().min((o1, o2) -> o1.getAge() - o2.getAge());
        min.ifPresent(System.out::println);
        // 最大
        Optional<Employee> max = list.stream().max((o1, o2) -> o1.getAge() - o2.getAge());
        max.ifPresent(System.out::println);
        // 计数
        System.out.println(list.stream().count());
        // 匹配
        boolean b1 = list.stream().anyMatch(employee -> employee.getAge() > 20);
        boolean b2 = list.stream().allMatch(employee -> employee.getAge() > 20);
        boolean b3 = list.stream().noneMatch(employee -> employee.getAge() > 20);
        System.out.println(b1);
        System.out.println(b2);
        System.out.println(b3);
        // 查找
        Optional<Employee> first = list.stream().findFirst();
        Optional<Employee> any = list.stream().findAny();
        first.ifPresent(System.out::println);
        any.ifPresent(System.out::println);
    }

    @Test
    public void test02() {
        List<String> list = Arrays.asList("A", "B", "C", "A", "B", "C");
        // 去重
        System.out.println("去重:");
        list.stream().distinct().forEach(System.out::println);// A B C
        System.out.println("跳过、限量:");
        // 跳过、限量
        list.stream().skip(2).limit(2).forEach(System.out::println);// C A
    }
}

4.13、常用方法 - 静态方法

  • of():转换为流
  • iterate()、generate():生成无限流
  • builder():返回流构建器,用于构建流
  • empty():返回空流,然后使用 concat() 合并流
  • concat():合并流
/*
    // 8、静态方法
    public static<T> Builder<T> builder() {}// 返回流构建器,用于构建流
    public static<T> Stream<T> empty() {}// 返回空流,然后使用 concat() 合并流
    public static<T> Stream<T> of(T t) {}// 转换为流
    public static<T> Stream<T> of(T... values) {}// 转换为流
    public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) {}// 生成无限流,根据指定种子
    public static<T> Stream<T> generate(Supplier<T> s) {}// 生成无限流
    public static<T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) {}// 合并流
 */
public class T01_StaticMethods {
    // 1、转换为流
    @Test
    public void test01() {
        Stream<String> s1 = Stream.of("张三");
        Stream<String> s2 = Stream.of("张三", "李四", "王五");
        String[] array = new String[]{"张三", "李四", "王五"};
        Stream<String> s3 = Stream.of(array);
    }

    /*
        2、iterate() 生成无限流:
            1、生成字符串:张三-1 张三-2 张三-3 张三-4 张三-5
            2、计算 5 的阶乘
     */
    @Test
    public void test02() {
        Stream<String> stream = Stream.iterate("张三-1", s -> {
            String[] split = s.split("-");
            return split[0] + "-" + (Integer.parseInt(split[1]) + 1);
        }).limit(5);
        stream.forEach(System.out::println);

        Optional<Integer> optional = Stream.iterate(1, integer -> integer + 1).limit(5).reduce((i1, i2) -> i1 * i2);
        System.out.println(optional.get());
    }

    // 3、generate() 生成无限流:生成 10 个 100 以内的随机数
    @Test
    public void test03() {
        Stream<Integer> stream = Stream.generate(() -> new Random().nextInt(100)).limit(10);
        stream.forEach(System.out::println);
    }

    // 4、流构件器
    @Test
    public void test04() {
        Stream.Builder<String> builder = Stream.builder();
        Stream<String> stream = builder.add("张三").add("李四").add("王五").build();
        stream.forEach(System.out::println);
    }

    // 5、合并流
    @Test
    public void test05() {
        Stream<String> empty = Stream.empty();
        Stream<String> stream1 = Stream.of("张三", "李四", "王五");
        Stream<String> stream2 = Stream.concat(empty, stream1);
        stream2.forEach(System.out::println);
    }
}

4.14、常用方法 - 收集

1、介绍

  • 转换为数组、收集为集合
// 9.1、转换为数组
Object[] toArray();// 收集为 Object 类型的数组
<A> A[] toArray(IntFunction<A[]> generator);// 收集为指定类型的数组
// 9.2、收集为集合
<R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner);// 自定义收集
<R, A> R collect(Collector<? super T, A, R> collector);// 指定收集器收集
  • Collectors 类 - 收集器工具类
package java.util.stream;
public final class Collectors {
    // 1.1、收集为指定 Collection、List、Set
    public static <T, C extends Collection<T>> Collector<T, ?, C> toCollection(Supplier<C> collectionFactory) {}// 收集为指定 Collection
    public static <T> Collector<T, ?, List<T>> toList() {}// 收集为 List
    public static <T> Collector<T, ?, Set<T>> toSet() {}// 收集为 Set
    // 1.2、收集为 Map
    public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(
            Function<? super T, ? extends K> keyMapper,
            Function<? super T, ? extends U> valueMapper) {}
    public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(
            Function<? super T, ? extends K> keyMapper,
            Function<? super T, ? extends U> valueMapper,
            BinaryOperator<U> mergeFunction) {}
    public static <T, K, U, M extends Map<K, U>> Collector<T, ?, M> toMap(
            Function<? super T, ? extends K> keyMapper,
            Function<? super T, ? extends U> valueMapper,
            BinaryOperator<U> mergeFunction,
            Supplier<M> mapSupplier) {}
    // 1.3、收集为 ConcurrentMap
    public static <T, K, U> Collector<T, ?, ConcurrentMap<K,U>> toConcurrentMap(
            Function<? super T, ? extends K> keyMapper,
            Function<? super T, ? extends U> valueMapper) {}
    public static <T, K, U> Collector<T, ?, ConcurrentMap<K,U>> toConcurrentMap(
            Function<? super T, ? extends K> keyMapper,
            Function<? super T, ? extends U> valueMapper,
            BinaryOperator<U> mergeFunction) {}
    public static <T, K, U, M extends ConcurrentMap<K, U>> Collector<T, ?, M> toConcurrentMap(
            Function<? super T, ? extends K> keyMapper,
            Function<? super T, ? extends U> valueMapper,
            BinaryOperator<U> mergeFunction,
            Supplier<M> mapSupplier) {}
    // 2、字符串连接
    public static Collector<CharSequence, ?, String> joining() {}
    public static Collector<CharSequence, ?, String> joining(CharSequence delimiter) {}
    public static Collector<CharSequence, ?, String> joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix) {}
    // 7、映射
    public static <T, U, A, R> Collector<T, ?, R> mapping(Function<? super T, ? extends U> mapper, Collector<? super U, A, R> downstream) {}
    // 8、收集,然后执行 Function
    public static <T,A,R,RR> Collector<T,A,RR> collectingAndThen(Collector<T,A,R> downstream, Function<R,RR> finisher) {}
    // 3、统计:计数、最小、最大、求和、平均、统计所有
    public static <T> Collector<T, ?, Long> counting() {}// 计数
    public static <T> Collector<T, ?, Optional<T>> minBy(Comparator<? super T> comparator) {}// 最小
    public static <T> Collector<T, ?, Optional<T>> maxBy(Comparator<? super T> comparator) {}// 最大
    public static <T> Collector<T, ?, Integer> summingInt(ToIntFunction<? super T> mapper) {}// 求和
    public static <T> Collector<T, ?, Long> summingLong(ToLongFunction<? super T> mapper) {}// 求和
    public static <T> Collector<T, ?, Double> summingDouble(ToDoubleFunction<? super T> mapper) {}// 求和
    public static <T> Collector<T, ?, Double> averagingInt(ToIntFunction<? super T> mapper) {}// 平均
    public static <T> Collector<T, ?, Double> averagingLong(ToLongFunction<? super T> mapper) {}// 平均
    public static <T> Collector<T, ?, Double> averagingDouble(ToDoubleFunction<? super T> mapper) {}// 平均
    public static <T> Collector<T, ?, IntSummaryStatistics> summarizingInt(ToIntFunction<? super T> mapper) {}// 统计所有
    public static <T> Collector<T, ?, LongSummaryStatistics> summarizingLong(ToLongFunction<? super T> mapper) {}// 统计所有
    public static <T> Collector<T, ?, DoubleSummaryStatistics> summarizingDouble(ToDoubleFunction<? super T> mapper) {}// 统计所有
    // 4、归纳
    public static <T> Collector<T, ?, T> reducing(T identity, BinaryOperator<T> op) {}
    public static <T> Collector<T, ?, Optional<T>> reducing(BinaryOperator<T> op) {}
    public static <T, U> Collector<T, ?, U> reducing(U identity, Function<? super T, ? extends U> mapper, BinaryOperator<U> op) {}
    // 5.1、分组:返回 Map
    public static <T, K> Collector<T, ?, Map<K, List<T>>> groupingBy(
            Function<? super T,
            ? extends K> classifier) {}
    public static <T, K, A, D> 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) {}
    // 5.2、分组:返回 ConcurrentMap
    public static <T, K> Collector<T, ?, ConcurrentMap<K, List<T>>> groupingByConcurrent(
            Function<? super T, ? extends K> classifier) {}
    public static <T, K, A, D>Collector<T, ?, ConcurrentMap<K, D>> groupingByConcurrent(
            Function<? super T, ? extends K> classifier,
            Collector<? super T, A, D> downstream) {}
    public static <T, K, A, D, M extends ConcurrentMap<K, D>> Collector<T, ?, M> groupingByConcurrent(
            Function<? super T, ? extends K> classifier,
            Supplier<M> mapFactory,
            Collector<? super T, A, D> downstream) {}
    // 6、分区
    public static <T> Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(
            Predicate<? super T> predicate) {}
    public static <T, D, A> Collector<T, ?, Map<Boolean, D>> partitioningBy(
            Predicate<? super T> predicate,
            Collector<? super T, A, D> downstream) {}
}

2、收集为数组

/*
    // 9.1、转换为数组
    Object[] toArray();// 收集为 Object 类型的数组
    <A> A[] toArray(IntFunction<A[]> generator);// 收集为指定类型的数组
 */
public class T01_ToArray {
    @Test
    public void test01() {
        List<Employee> list = Employee.getList();
        Object[] objects = list.stream().toArray();
        for (Object object : objects) {
            System.out.println(object);
        }
    }

    @Test
    public void test02() {
        List<Employee> list = Employee.getList();
//        Employee[] employees = list.stream().toArray(i -> new Employee[i]);
        Employee[] employees = list.stream().toArray(Employee[]::new);
        for (Employee employee : employees) {
            System.out.println(employee.getName());
        }
    }
}

3、收集为集合 - 自定义收集

/*
	// 9.2、收集为集合
	<R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner);// 自定义收集
        Supplier<R> supplier:提供一个收集数据的容器,容器的泛型为 R。例如 ArrayList<String>、HashMap<String, Employee>。
        BiConsumer<R, ? super T> accumulator:如何给容器添加数据,添加什么数据,容器的泛型为 R,流的泛型为 T。
        BiConsumer<R, R> combiner:如何将多个容器合并,容器的泛型为 R。
 */
public class T02_Collect01 {
    @Test
    public void test01() {
        List<Employee> list = Employee.getList();
        ArrayList<String> arrayList = list.stream().collect(
                ArrayList::new,
                (nameArrayList, e) -> nameArrayList.add(e.getName()),
                ArrayList::addAll);
        arrayList.forEach(System.out::println);
    }

    @Test
    public void test02() {
        List<Employee> list = Employee.getList();
        HashMap<String, Employee> hashMap = list.stream().collect(
                HashMap::new,
                (nameHashMap, e) -> nameHashMap.put(e.getName(), e),
                HashMap::putAll
        );
        hashMap.forEach((k, v) -> System.out.println(k + "::" + v));
    }
}

4、收集为集合 - 指定收集器收集

package T19_Stream.T14_Collect;

import T19_Stream.Employee;
import org.junit.Test;

import java.util.*;
import java.util.stream.Collectors;

/*
    Stream 接口
        <R, A> R collect(Collector<? super T, A, R> collector);// 指定收集器收集
    Collectors 类 - 收集器工具类
 */
public class T03_Collect02 {
    // 1.1、收集为指定 Collection、List、Set
    @Test
    public void test01() {
        List<Employee> employees = Employee.getList();
        ArrayList<Employee> arrayList = employees.stream().collect(Collectors.toCollection(ArrayList::new));
        List<Employee> list = employees.stream().collect(Collectors.toList());
        Set<Employee> set = employees.stream().collect(Collectors.toSet());
    }

    // 1.2、收集为 Map
    @Test
    public void test02() {
        List<Employee> employees = Employee.getList();
        Map<String, Integer> map1 = employees.stream().collect(Collectors.toMap(Employee::getName, Employee::getAge));
        System.out.println(map1);
        Map<Integer, String> map2 = employees.stream().collect(Collectors.toMap(Employee::getAge, Employee::getName, (o1, o2) -> o1));
        System.out.println(map2);
        HashMap<Integer, String> map3 = employees.stream().collect(Collectors.toMap(Employee::getAge, Employee::getName, (o1, o2) -> o1, HashMap::new));
        System.out.println(map3);
    }

    // 2、字符串连接
    @Test
    public void test03() {
        List<Employee> employees = Employee.getList();
        String s1 = employees.stream().map(Employee::getName).collect(Collectors.joining());
        System.out.println(s1);
        String s2 = employees.stream().map(Employee::getName).collect(Collectors.joining("-"));
        System.out.println(s2);
        String s3 = employees.stream().map(Employee::getName).collect(Collectors.joining("-", "开始<", ">结束"));
        System.out.println(s3);
    }

    // 3、统计:计数、最小、最大、求和、平均、统计所有
    @Test
    public void test04() {
        List<Employee> list = Employee.getList();
        // 计数
        Long count = list.stream().collect(Collectors.counting());
        System.out.println(count);
        // 最小
        Optional<Employee> min = list.stream().collect(Collectors.minBy((o1, o2) -> o1.getAge() - o2.getAge()));
        System.out.println(min.get());
        // 最大
        Optional<Employee> max = list.stream().collect(Collectors.maxBy((o1, o2) -> o1.getAge() - o2.getAge()));
        System.out.println(max.get());
        // 求和
        int sum = list.stream().collect(Collectors.summingInt(Employee::getAge));
        System.out.println(sum);
        // 平均
        double avg = list.stream().collect(Collectors.averagingInt(Employee::getAge));
        System.out.println(avg);
        // 统计所有
        IntSummaryStatistics summary = list.stream().collect(Collectors.summarizingInt(Employee::getAge));
        System.out.println(summary);
    }

    /*
        // 归纳
        public static <T> Collector<T, ?, T> reducing(T identity, BinaryOperator<T> op) {}
        public static <T> Collector<T, ?, Optional<T>> reducing(BinaryOperator<T> op) {}
        public static <T, U> Collector<T, ?, U> reducing(U identity, Function<? super T, ? extends U> mapper, BinaryOperator<U> op) {}
     */
    // 4、归纳
    @Test
    public void test05() {
        List<Employee> employees = Employee.getList();
        Integer sum1 = employees.stream().map(Employee::getAge).collect(Collectors.reducing(100, Integer::sum));
        System.out.println(sum1);
        Optional<Integer> sum2 = employees.stream().map(Employee::getAge).collect(Collectors.reducing(Integer::sum));
        System.out.println(sum2.get());
        Integer sum3 = employees.stream().map(Employee::getSalary).collect(Collectors.reducing(0, Double::intValue, Integer::sum));
        System.out.println(sum3);
    }

    /*
        // 5.1、分组:返回 Map
        public static <T, K> Collector<T, ?, Map<K, List<T>>> groupingBy(
                Function<? super T,
                ? extends K> classifier) {}
        public static <T, K, A, D> 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) {}
     */
    @Test
    public void test06() {
        List<Employee> employees = Employee.getList();
//        Map<String, List<Employee>> map = employees.stream().collect(Collectors.groupingBy(Employee::getGender));
//        map.forEach((k, v) -> System.out.println(k + "::" + v));
//        Map<String, Map<Integer, List<Employee>>> map2 = employees.stream().collect(Collectors.groupingBy(Employee::getGender, Collectors.groupingBy(Employee::getAge)));
//        map2.forEach((k, v) -> {
//            System.out.println(k);
//            v.forEach((k1, v1) -> System.out.println("\t" + k1 + "::" + v1));
//        });
        HashMap<String, Map<Integer, List<Employee>>> map3 = employees.stream().collect(Collectors.groupingBy(Employee::getGender, HashMap::new, Collectors.groupingBy(Employee::getAge)));
        map3.forEach((k, v) -> {
            System.out.println(k);
            v.forEach((k1, v1) -> System.out.println("\t" + k1 + "::" + v1));
        });
    }

    /*
        // 6、分区
        public static <T> Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(
                Predicate<? super T> predicate) {}
        public static <T, D, A> Collector<T, ?, Map<Boolean, D>> partitioningBy(
                Predicate<? super T> predicate,
                Collector<? super T, A, D> downstream) {}
     */
    @Test
    public void test07() {
        List<Employee> employees = Employee.getList();
//        Map<Boolean, List<Employee>> map1 = employees.stream().collect(Collectors.partitioningBy(e -> e.getSalary() > 4500.0D));
//        System.out.println("薪资是否超过 4500:");
//        map1.forEach((k, v) -> {
//            System.out.println(k + "::" + v);
//        });
        Map<Boolean, Map<Boolean, List<Employee>>> map2 = employees.stream().collect(Collectors.partitioningBy(e -> e.getSalary() >= 4500.0D, Collectors.partitioningBy(e -> e.getAge() >= 20)));
        System.out.println("薪资是否超过 4500");
        map2.forEach((k, v) -> {
            System.out.println(k);
            System.out.println("\t年龄是否超过 20");
            v.forEach((k1, v1) -> {
                System.out.println("\t" + k1 + "::" + v1);
            });
        });
    }

    /*
        // 7、映射
        public static <T, U, A, R> Collector<T, ?, R> mapping(Function<? super T, ? extends U> mapper, Collector<? super U, A, R> downstream) {}
     */
    @Test
    public void test08() {
        List<Employee> list = Employee.getList();
        Map<Boolean, List<Integer>> map = list.stream().collect(Collectors.mapping(Employee::getAge, Collectors.partitioningBy(integer -> integer >= 20)));
        map.forEach((k, v) -> System.out.println(k + "::" + v));
    }
    /*
        // 8、收集,然后执行 Function
        public static <T,A,R,RR> Collector<T,A,RR> collectingAndThen(Collector<T,A,R> downstream, Function<R,RR> finisher) {}
     */

    @Test
    public void test09() {
        List<Employee> list = Employee.getList();
        Object[] collect = list.stream().collect(Collectors.collectingAndThen(Collectors.mapping(Employee::getGender, Collectors.toList()), ls -> ls.toArray()));
        System.out.println(collect.length);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值