Lambda表达式和Stream流

文章目录

  • 一、Lambda表达式
    • 1. Lambda简介
    • 2. 对接口的要求
    • 3. @FunctionalInterface
    • 4. 基础法语
    • 5. 简化语法
    • 6. Lambda表达式常用示例
      • 1)Lambda表达式 引用方法
      • 2)Lambda表达式 引用构造方法
      • 3)Lambda表达式 创建线程对象
      • 4)Lambda表达式 遍历集合
      • 5)Lambda表达式 移除集合指定的元素
      • 6)Lambda表达式 集合元素的排序
  • 二、Stream流
    • 1. Stream概述
    • 2. Stream特性
    • 3. Stream创建
    • 4. Stream使用
      • 1)遍历(foreach)、匹配(find、match)
      • 2)筛选(filter)
      • 3)聚合(max、min、count)
      • 4)映射(map、flatMap)
      • 5)规约(reduce)
      • 7)收集|归集(toList、toSet、toMap)
      • 8)统计(count、averaging、maxBy、minBy、summing)
      • 9)分组(partitioningBy、groupingBy)
      • 10)接合|拼接(joining)
      • 11)排序(sorted)
      • 12)提取/组合
  • 参考资料
    • 1. [视频地址](https://www.bilibili.com/video/BV1BK4y1G7xh)
    • 2. [仓库地址](https://gitee.com/sundaywind/study-lamdba-and-stream)

一、Lambda表达式

1. Lambda简介

  Lambda表达式是JDK8的一个新特性,可以取代大部分的匿名内部类,写出更优雅的Java代码,尤其在集合的遍历和其他集合操作中,可以极大的优化代码结构。
  JDK也提供了大量的内置函数式接口供我们使用,使得Lambda表达式的运用更加方便、高效。

2. 对接口的要求

  虽然使用Lambda表达式可以对某些接口进行简单的实现,但并不是所有接口都可以使用Lambda表达式来实现。Lambda规定接口中只能有一个需要被实现的方法,不是规定接口中只能有一个方法。
  JDK8中有另一个新特性:default,被default修饰的方法会有默认实现,不是必须被实现的方法,所以不影响Lambda表达式的使用。

3. @FunctionalInterface

  修饰函数式接口的,要求接口中的抽象方法只有一个。这个注解往往会和Lambda表达式一起出现。
作用:
  验证当前接口是否只有一个需要被实现的方法,如果不满足就编译报错。

4. 基础法语

package com.wind.lambda;

/**
 * Lambda表达式 基础语法测试
 *
 * @author Wind
 */
public class LambdaTest01 {
    public static void main(String[] args) {
        /*
            以前的写法 使用匿名内部类
         */
        NoRetrunNoParam noRetrunNoParam = new NoRetrunNoParam() {
            @Override
            public void method() {
                System.out.println("匿名内部类 OK!");
            }
        };
        noRetrunNoParam.method();

        /*
            无返回值无参数
         */
        NoRetrunNoParam noRetrunNoParam1 = () -> {
            System.out.println("无返回值无参数~OK!");
        };
        noRetrunNoParam1.method();

        /*
            无返回值有一个参数
         */
        NoRetrunOneParam noRetrunOneParam = (int a) -> {
            System.out.println("无返回值有一个参数:" + a);
        };
        noRetrunOneParam.method(10);

        /*
            无返回值有多个参数
         */
        NoRetrunMultiParam noRetrunMultiParam = (int a, int b) -> {
            System.out.println("无返回值有多个参数:" + (a + b));
        };
        noRetrunMultiParam.method(10, 5);

        /*
            有返回值无参数
         */
        RetrunNoParam retrunNoParam = () -> {
            return 110;
        };
        System.out.println("有返回值无参数:" + retrunNoParam.method());

        /*
            有返回值有一个参数
         */
        RetrunOneParam retrunOneParam = (int a) -> {
            return a;
        };
        System.out.println("有返回值有一个参数:" + retrunOneParam.method(120));

        /*
            有返回值有多个参数
         */
        RetrunMultiParam retrunMultiParam = (int a, int b) -> {
            return a + b;
        };
        System.out.println("有返回值有多个参数:" + retrunMultiParam.method(20, 30));
    }
}

5. 简化语法

package com.wind.lambda;

/**
 * Lambda表达式 语法简化
 * 

* 简化主要针对的是:参数类型、小括号、大括号 * * @author Wind */ public class LambdaTest02 { public static void main(String[] args) { /* 1. 简化参数类型:可以不写参数类型,但必须所有参数都不写 */ // 正常语法 NoRetrunMultiParam noRetrunMultiParam = (int a, int b) -> { System.out.println("无返回值有多个参数:" + (a + b)); }; noRetrunMultiParam.method(10, 5); // 简化写法:可以不写参数类型,但必须所有参数都不写 NoRetrunMultiParam noRetrunMultiParam1 = (a, b) -> { System.out.println(a + b); }; noRetrunMultiParam1.method(15, 20); /* 2. 简化参数小括号。如果只有一个参数可以省略参数小括号() */ // 正常语法 NoRetrunOneParam noRetrunOneParam = (int a) -> { System.out.println("无返回值有一个参数:" + a); }; noRetrunOneParam.method(10); // 简化写法:如果只有一个参数可以省略参数小括号() NoRetrunOneParam noRetrunOneParam1 = a -> { System.out.println("只有一个参数可以省略参数小括号()" + a); }; noRetrunOneParam1.method(10); /* 3. 简化方法体大括号。如果方法体中只有一行语句,则可以省略方法体大括号{} */ // 正常语法 NoRetrunNoParam noRetrunNoParam1 = () -> { System.out.println("无返回值无参数~OK!"); }; noRetrunNoParam1.method(); // 简化写法:方法体中只有一行语句,则可以省略方法体大括号{} NoRetrunNoParam noRetrunNoParam2 = () -> System.out.println("当实现类方法体中只有一行代码可以省略大括号~OK!"); noRetrunNoParam2.method(); /* 4. 简化方法体大括号。如果方法体只有一条语句,并且是 return 语句,则可省略方法体大括号和 return 关键字 */ // 正常语法 RetrunMultiParam retrunMultiParam = (int a, int b) -> { return a + b; }; System.out.println("有返回值有多个参数:" + retrunMultiParam.method(20, 30)); // 简化语法 RetrunMultiParam retrunMultiParam1 = (a, b) -> a + b; System.out.println("有返回值有多个参数:" + retrunMultiParam1.method(20, 30)); } }

6. Lambda表达式常用示例

1)Lambda表达式 引用方法

  有时候我们不是必须要自己重写某个匿名内部类的方法,我们可以利用Lambda表达式快速指向一个已经被实现的方法。

语法:方法归属者 :: 方法名

静态方法的归属者为类名

接口 对象名 = 类名::静态方法名;

普通方法归属者为对象

对象 对象名 = new 对象();
接口 接口对象 = 对象名::成员方法名;

package com.wind.lambda;

/**
 * Lambda表达式引用方法
 *
 * @author Wind
 */
public class LambdaTest03 {
    public static void main(String[] args) {
        // Lambda表达式引用已经实现的静态方法
        RetrunOneParam retrunOneParam = LambdaTest03::numStatic;
        System.out.println(retrunOneParam.method(20));

        // Lambda表达式引用已经实现的普通方法
        LambdaTest03 lambdaTest03 = new LambdaTest03();
        RetrunOneParam retrunOneParam1 = lambdaTest03::numGeneral;
        System.out.println(retrunOneParam1.method(50));
    }

    /**
     * 静态方法
     *
     * @param a
     * @return
     */
    public static int numStatic(int a) {
        return a + 1000;
    }

    /**
     * 普通方法
     *
     * @param a
     * @return
     */
    public int numGeneral(int a) {
        return a + 1500;
    }
}

2)Lambda表达式 引用构造方法

  一般我们需要声明接口,改接口作为对象的生成器,通过 类名::new 的方式来实例化对象,然后调用方法返回对象。

package com.wind.lambda;

/**
 * Lambda表达式 构造方法的引用
 *
 * @author Wind
 */
public class LambdaTest04 {
    public static void main(String[] args) {
        // 使用无参构造器来引用 1
        ItemCreatorBlackConstruct construct1 = () -> new Item();
        Item item1 = construct1.getItem();
        // 使用无参构造器来引用 2
        ItemCreatorBlackConstruct construct2 = Item::new;
        Item item2 = construct2.getItem();

        // 有参的构造方法
        ItemCreatorParamContruct contruct3 = Item::new;
        Item item3 = contruct3.getItem(1, "张三", 12.3);
    }
}


@FunctionalInterface
interface ItemCreatorBlackConstruct {
    Item getItem();
}

@FunctionalInterface
interface ItemCreatorParamContruct {
    Item getItem(int id, String name, double price);
}

class Item {

    int id;
    String name;
    double price;

    public Item() {

    }

    public Item(int id, String name, double price) {
        this.id = id;
        this.name = name;
        this.price = price;
    }
}

3)Lambda表达式 创建线程对象

  我们以往都是通过创建 Thread 对象,然后通过匿名内部类重写 run() 方法。一提到匿名内部类 我们就应该想到可以使用 Lambda 表达式来简化线程创建过程。

package com.wind.lambda;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static java.util.concurrent.Executors.*;

/**
 * Lambda表达式 创建线程对象
 *
 * @author Wind
 */
public class LambdaTest05 {
    public static void main(String[] args) {
        /*
            Runable
         */
        // 以前写法
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("OK~!");
            }
        }).start();

        // Lambda表达式创建
        new Thread(() -> {
            System.out.println("OK~!");
        }).start();

        // 简化上面Lambda
        new Thread(() -> System.out.println("OK~!")).start();

        /*
            提交
         */
        ExecutorService executorService = newCachedThreadPool();
        // Runable(无返回值)
        executorService.submit(() -> {
            System.out.println("OK~!");
        });
        // Callable(有返回值)
        executorService.submit(() -> {
            return "完成了!";
        });

    }
}

4)Lambda表达式 遍历集合

package com.wind.lambda;

import java.util.Arrays;
import java.util.List;

/**
 * Lambda表达式 遍历集合
 *
 * @author Wind
 */
public class LambdaTest06 {
    public static void main(String[] args) {
        // Arrays工具类创建集合
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);

        // 普通for循环遍历集合
        for (int i = 0; i < list.size(); i++) {
            System.out.print(list.get(i) + "\t");
        }
        System.out.println();
        System.out.println("-------------------------------------------------------");

        // 增强for循环遍历集合
        for (Integer i : list) {
            System.out.print(i + "\t");
        }
        System.out.println();
        System.out.println("-------------------------------------------------------");

        /*
            使用Lambda表达式遍历
         */
        list.forEach((t) -> {
            System.out.print(t + "\t");
        });
        System.out.println();
        System.out.println("-------------------------------------------------------");
        // 简化
        list.forEach(t -> System.out.print(t + "\t"));
        System.out.println();
        System.out.println("-------------------------------------------------------");
        // 极简
        list.forEach(System.out::print);
    }
}

5)Lambda表达式 移除集合指定的元素

package com.wind.lambda;

import java.util.ArrayList;
import java.util.List;

/**
 * Lambda表达式 遍历集合
 *
 * @author Wind
 */
public class LambdaTest07 {
    public static void main(String[] args) {
        List<Star> stars = new ArrayList<>();
        stars.add(new Star(1, "刘德华", true));
        stars.add(new Star(2, "郭富城", true));
        stars.add(new Star(3, "迪丽热巴", false));
        stars.add(new Star(4, "水菜麗", false));
        stars.add(new Star(5, "泷泽萝拉", false));

        // 普通for循环移除元素
        for (int i = 0; i < stars.size(); i++) {
            if (stars.get(i).getId() == 1) {
                stars.remove(stars.get(i));
                break;
            }
        }
        System.out.println(stars);
        System.out.println("----------------------------------");

        // 增强for循环 移除元素
        for (Star star : stars) {
            if (star.getId() == 2) {
                stars.remove(star);
                break;
            }
        }
        System.out.println(stars);
        System.out.println("----------------------------------");

        /*
            Lambda 表达式移除集合元素
         */
        stars.removeIf((t) -> {
            return t.getId() == 3;
        });
        System.out.println(stars);
        System.out.println("----------------------------------");
        // 简化
        stars.removeIf(t -> t.getId() == 5);
        System.out.println(stars);
        System.out.println("----------------------------------");
    }
}

6)Lambda表达式 集合元素的排序

package com.wind.lambda;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * Lambda表达式 遍历集合
 *
 * @author Wind
 */
public class LambdaTest08 {
    public static void main(String[] args) {
        List<Star> stars = new ArrayList<>();
        stars.add(new Star(4, "刘德华", true));
        stars.add(new Star(3, "郭富城", true));
        stars.add(new Star(2, "迪丽热巴", false));
        stars.add(new Star(5, "水菜麗", false));
        stars.add(new Star(1, "泷泽萝拉", false));

        // 使用集合工具类,给集合升序排序
        Collections.sort(stars, new Comparator<Star>() {
            @Override
            public int compare(Star o1, Star o2) {
                return o1.getId() - o2.getId(); // 升序
            }
        });
        System.out.println(stars);

        // 使用Lambda表达式 给集合降序排序
        Collections.sort(stars, (o1, o2) -> {
            return o2.getId() - o1.getId();
        });
        System.out.println(stars);
        // 以上代码当然可以简化了,因为方法体只有一条语句
        Collections.sort(stars, ((o1, o2) -> o2.getId() - o1.getId()));
        System.out.println(stars);
        // 集合工具类默认是升序排序,所以升序排序的话 还可以简化
        Collections.sort(stars, (Comparator.comparingInt(Star::getId)));
        System.out.println(stars);
    }
}

二、Stream流

1. Stream概述

  Stream将要处理的元素集合看作一种流,在流的过程中,借助Stream API对流中的元素进行操作。比如:筛选、排序、聚合 等。
  Stream专门为数组和集合打造的 不能用于其他地方。

Stream可以由数组或集合创建,对流的操作分为两种:

  1. 中间操作:每次返回一个新的流,可以有多个。
  2. 终端操作:每个流只能进行一次终端操作,终端结束后 流无法再次使用。终端操作会产生一个新的集合或值。

2. Stream特性

  1. Stream 不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果。
  2. Stream 不会改变数据源,通常情况下回产生一个新的集合或一个值。
  3. Stream 具有延迟执行特性,只有调用终端操作时,中间操作才会执行。

3. Stream创建

Steam可以通过集合或数组创建:

  1. 通过Collection集合创建流
  2. 通过数组创建流
  3. 使用Stream静态方法:of()、iterate()、generate()
package com.wind.stream;

import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * Stream创建的三种方式
 *
 * @author Wind
 * @date 2021-06-06
 */
public class Test01Stream {
    public static void main(String[] args) {
        /*
            1. Collection集合创建流
         */
        List<String> list = Arrays.asList("1", "2", "3", "4", "5");
        // 创建一个顺序流
        Stream<String> stream = list.stream();
        // 创建一个并行流
        Stream<String> parallelStream = list.parallelStream();

        /*
            2. 数组创建流
         */
        int[] array = {1, 2, 3, 4, 5};
        IntStream arrayStream = Arrays.stream(array);

        /*
            3. 使用Stream的静态方法:of()、iterate()、generate()
         */
        // of()
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
        // iterate()
        Stream<Integer> limitStream = Stream.iterate(0, x -> x + 1).limit(4);   // 从0开始,每次+1,循环4次
        // generate()
        String[] arrString = {"1", "2", "3"};
        Stream<String[]> generateStream = Stream.generate(() -> arrString);

    }
}

4. Stream使用

1)遍历(foreach)、匹配(find、match)

package com.wind.stream;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

/**
 * Stream的使用:遍历、匹配
 *
 * @author Wind
 * @date 2021-06-06
 */
public class Test02Stream {
    public static void main(String[] args) {

        List<Integer> list = Arrays.asList(7, 6, 9, 3, 8, 2, 1);

        /*
         1. 顺序遍历
         */
        Stream<Integer> stream = list.stream();
        stream.forEach(t -> {
            System.out.print(t);
        });
        System.out.println();
        // 简化写法
        list.stream().forEach(System.out::print);
        System.out.println();

        /*
         2. 并行遍历:可以理解成多线程
         */
        list.parallelStream().forEach(System.out::print);
        System.out.println();

        /*
         3. 匹配:遍历出符合条件的元素
         */
        // 遍历大于6的元素:思路是 过滤出大于6的元素,再遍历输出
        list.stream().filter(t -> t > 6).forEach(System.out::print);
        System.out.println();
        // 匹配第一个
        Integer int1 = list.stream().findFirst().get();
        System.out.println(int1);
        // 匹配任意(适用于并行流)
        Integer int2 = list.parallelStream().findAny().get();
        System.out.println(int2);
        // 是否包含符合特定条件的元素
        boolean b = list.stream().anyMatch(t -> t == 9);
        System.out.println(b);
    }
}

2)筛选(filter)

package com.wind.stream;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Stream的使用:过滤
 *
 * @author Wind
 * @date 2021-06-06
 */
public class Test03Stream {
    public static void main(String[] args) {

        List<Person> list = new ArrayList<>();
        list.add(new Person("张三", 7000, 34, "男", "陕西"));
        list.add(new Person("李四", 8000, 24, "男", "河北"));
        list.add(new Person("王五", 6000, 42, "女", "甘肃"));
        list.add(new Person("王五", 9000, 12, "女", "上海"));
        
        // 工资大于等于8000 并返回新的集合
        List<Person> collect = list.stream().filter(t -> t.getSalary() >= 8000).collect(Collectors.toList());
        System.out.println(collect);
    }
}

3)聚合(max、min、count)

package com.wind.stream;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

/**
 * Stream的使用:聚合
 *
 * @author Wind
 * @date 2021-06-06
 */
public class Test04Stream {
    public static void main(String[] args) {

        // 1. 获取String集合中最长的元素
        List<String> strList = Arrays.asList("李白", "张学友", "God");
        String s1 = strList.stream().max(((o1, o2) -> o1.length() - o2.length())).get();
        System.out.println(s1);
        // 上面的简化写法
        String s2 = strList.stream().max((Comparator.comparingInt(String::length))).get();
        System.out.println(s2);

        // 2. 获取Integer集合中的最大值
        List<Integer> list = Arrays.asList(7, 6, 9, 3, 8, 2, 1);
        Integer maxNum1 = list.stream().max(((o1, o2) -> o1 - o2)).get();
        System.out.println(maxNum1);
        // 上面的简化写法
        Integer maxNum2 = list.stream().max(Integer::compareTo).get();
        System.out.println(maxNum2);

        // 自然排序
        Integer maxNum3 = list.stream().max(Integer::compareTo).get();
        // 自定义排序
        Integer maxNum4 = list.stream().max(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1 - o2;
            }
        }).get();
        // 3. 获取员工工资最高的人
        List<Person> persons = new ArrayList<>();
        persons.add(new Person("张三", 7000, 34, "男", "陕西"));
        persons.add(new Person("李四", 8000, 24, "男", "河北"));
        persons.add(new Person("王五", 6000, 42, "女", "甘肃"));
        persons.add(new Person("王五", 9000, 12, "女", "上海"));
        Person person1 = persons.stream().max((o1, o2) -> o1.getSalary() - o2.getSalary()).get();
        // 简化写法
        Person person2 = persons.stream().max(Comparator.comparingInt(Person::getSalary)).get();

        // 4. 计算Integer集合中大于6的元素的个数
        long count = list.stream().filter(t -> t > 6).count();
        System.out.println(count);
    }
}

4)映射(map、flatMap)

映射:可以将一个流的元素按照一定的规则映射到另一个流中。
分为:map() 和 flatMap()

  1. map():接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
  2. flatMap():接收一个函数作为参数,将流中高地每个值都换成另一个流,然后把所有流连成一个流。
package com.wind.stream;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;

/**
 * Stream的使用:映射
 *
 * @author Wind
 * @date 2021-06-06
 */
public class Test05Stream {
    public static void main(String[] args) {

        // 1. 英文数组的英文全部改为大写
        String[] arrStr = {"abcd", "cdfm", "msg", "ssm"};
        List<String> list = Arrays.asList(arrStr);
        System.out.println(list);   // 原来的数组
        List<String> newList = list.stream().map(t -> t.toUpperCase(Locale.ROOT)).collect(Collectors.toList());
        System.out.println(newList);
        System.out.println(list);   // 原来的数组
        System.out.println("=============================================================");

        // 2. 整数数组每个元素+3
        List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);
        List<Integer> newIntegerList = integers.stream().map(t -> t + 3).collect(Collectors.toList());
        System.out.println(integers);
        System.out.println(newIntegerList);
        System.out.println("=============================================================");

        // 3. 将所有员工的薪资增加1000
        List<Person> persons1 = new ArrayList<>();
        persons1.add(new Person("张三", 7000, 34, "男", "陕西"));
        persons1.add(new Person("李四", 8000, 24, "男", "河北"));
        persons1.add(new Person("王五", 6000, 42, "女", "甘肃"));
        persons1.add(new Person("王五", 9000, 12, "女", "上海"));
        // 这种情况会改变原对象的值
        List<Person> newpersons1 = persons1.stream().map(t -> {
            t.setSalary(t.getSalary() + 1000);
            return t;
        }).collect(Collectors.toList());
        // 原来集合的值被修改了...因为操作的时候是原对象
        System.out.println(persons1);    // 原来集合的值
        System.out.println(newpersons1); // 新集合的值
        System.out.println("=============================================================");

        // 不改变原有集合值的情况(在修改的时候 new一个新的对象操作)
        List<Person> persons2 = new ArrayList<>();
        persons2.add(new Person("张三", 7000, 34, "男", "陕西"));
        persons2.add(new Person("李四", 8000, 24, "男", "河北"));
        persons2.add(new Person("王五", 6000, 42, "女", "甘肃"));
        persons2.add(new Person("王五", 9000, 12, "女", "上海"));
        List<Person> newPersons2 = persons2.stream().map(t -> {
            Person person = new Person(t.getName(), t.getSalary(), t.getAge(), t.getSex(), t.getArea());
            person.setSalary(t.getSalary() + 1000);
            return person;
        }).collect(Collectors.toList());
        System.out.println(persons2);
        System.out.println(newPersons2);
        System.out.println("=============================================================");

        // 4. 将两个字符数组 组合成一个新的字符数组
        List<String> strings = Arrays.asList("m-k-l-a", "1-2-4-7");
        List<String> newStrings = strings.stream().flatMap(t -> {
            String[] split = t.split("-");
            return Arrays.stream(split);
        }).collect(Collectors.toList());
        System.out.println(strings);
        System.out.println(newStrings);
    }
}

5)规约(reduce)

  规约,也称缩减,顾名思义就是把一个流缩减成一个值,能实现对集合求和、求乘积、求最值操作

package com.wind.stream;

import java.util.Arrays;
import java.util.List;

/**
 * Stream的使用:规约
 *
 * @author Wind
 * @date 2021-06-06
 */
public class Test06Stream {
    public static void main(String[] args) {

        List<Integer> list = Arrays.asList(1, 3, 2, 8, 11, 4);
        /*
            求和
         */
        // 求和方式一:调用Integer的sum()方法
        Integer sum1 = list.stream().reduce(Integer::sum).get();
        System.out.println(sum1);
        // 求和方式二:同方式一 多了一个初始值。怎么理解呢?类似于原来的写法 定义一个 int sum = 0,遍历集合后 sum+=。下面方法的第一个参数类似于 定义的 sum = 0
        Integer sum2 = list.stream().reduce(0, Integer::sum);
        System.out.println(sum2);
        // 求和方式三:
        Integer sum3 = list.stream().reduce((x, y) -> x + y).get();
        System.out.println(sum3);

        /*
            求乘积
         */
        Integer cj = list.stream().reduce((x, y) -> x * y).get();
        System.out.println(cj);

        /*
            求最大值
         */
        // 方式一:Stream的max()方法
        Integer max1 = list.stream().max(Integer::compareTo).get();
        System.out.println(max1);
        // 方式二:自己实现比较 最后返回比较结果
        Integer max2 = list.stream().reduce((x, y) -> x > y ? x : y).get();
        System.out.println(max2);
        // 方式三:利用Integer的max()方法
        Integer max3 = list.stream().reduce(Integer::max).get();
        System.out.println(max3);

    }
}

7)收集|归集(toList、toSet、toMap)

  因为流不存储数据,那么在流中的数据完成处理后,需要将流中的数据重新归集到新的集合里。toList、toSet、toMap比较常用,另外还有toCollection、toConcurrentMap等复杂一些的用法。

package com.wind.stream;

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

/**
 * Stream的使用:归集
 *
 * @author Wind
 * @date 2021-06-09
 */
public class Test07Stream {
    public static void main(String[] args) {

        List<Integer> list = Arrays.asList(1, 6, 3, 4, 4, 5, 7, 9, 6, 21);
        list.forEach(System.out::print);
        System.out.println();

        // toList
        List<Integer> newList = list.stream().filter(x -> x % 2 == 0).collect(Collectors.toList());
        newList.forEach(System.out::print);
        System.out.println();

        // toSet
        Set<Integer> newSet = list.stream().filter(x -> x % 2 == 0).collect(Collectors.toSet());
        newSet.forEach(System.out::print);
        System.out.println();

        // toMap
        List<Person> persons = new ArrayList<>();
        persons.add(new Person("张三", 7000, 34, "男", "陕西"));
        persons.add(new Person("李四", 8000, 24, "男", "河北"));
        persons.add(new Person("王五", 6000, 42, "女", "甘肃"));
        persons.add(new Person("王五", 9000, 12, "女", "上海"));
        Map<String, Person> map = persons.stream().filter(p -> p.getSalary() > 6000).collect(Collectors.toMap(Person::getName, p -> p));
        System.out.println(map);
    }

8)统计(count、averaging、maxBy、minBy、summing)

  • 总数:count
  • -最值:maxBy、minBy
  • 平均值:averagingInt、averagingLong、avergaingDouble
  • 求和:summingInt、summingLong、summingDouble
  • 统计以上所有:summarizingInt、summarizingLong、summarizingDouble
package com.wind.stream;

import java.util.ArrayList;
import java.util.DoubleSummaryStatistics;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Stream的使用:统计
 *
 * @author Wind
 * @date 2021-06-09
 */
public class Test08Stream {
    public static void main(String[] args) {

        List<Person> persons = new ArrayList<>();
        persons.add(new Person("张三", 7000, 34, "男", "陕西"));
        persons.add(new Person("李四", 8000, 24, "男", "河北"));
        persons.add(new Person("王五", 6000, 42, "女", "甘肃"));
        persons.add(new Person("王五", 9000, 12, "女", "上海"));

        // 求总数
        Long count = persons.stream().collect(Collectors.counting());
        System.out.println(count);

        // 求平均工资
        Double average = persons.stream().collect(Collectors.averagingDouble(Person::getSalary));
        System.out.println(average);

        // 求最高工资
        Integer max = persons.stream().map(t -> t.getSalary()).collect(Collectors.maxBy(Integer::compareTo)).get();
        System.out.println(max);

        // 求工资之和
        Double sum = persons.stream().collect(Collectors.summingDouble(Person::getSalary));
        System.out.println(sum);

        // 一次性统计所有(总结)
        DoubleSummaryStatistics summarizing = persons.stream().collect(Collectors.summarizingDouble(Person::getSalary));
        System.out.println(summarizing);    // DoubleSummaryStatistics{count=4, sum=30000.000000, min=6000.000000, average=7500.000000, max=9000.000000}
        System.out.println(summarizing.getCount());
        System.out.println(summarizing.getSum());
        System.out.println(summarizing.getMin());
        System.out.println(summarizing.getAverage());
        System.out.println(summarizing.getMax());
    }
}

9)分组(partitioningBy、groupingBy)

  • 分区:将Stream按条件分为两个Map,传入条件,满足true、不满足false。比如员工工资是否高于7000分为两部分
  • 分组:将集合分为多个Map,比如员工按性别分组。有单级分组和多级分组
package com.wind.stream;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Stream的使用:分组
 *
 * @author Wind
 * @date 2021-06-09
 */
public class Test09Stream {
    public static void main(String[] args) {

        List<Person> persons = new ArrayList<>();
        persons.add(new Person("张三", 7000, 34, "男", "陕西"));
        persons.add(new Person("李四", 8000, 24, "男", "河北"));
        persons.add(new Person("王五", 6000, 42, "女", "甘肃"));
        persons.add(new Person("王五", 9000, 12, "女", "上海"));

       // 分区:将员工薪资按照是否高于7000分区
        Map<Boolean, List<Person>> partitioning = persons.stream().collect(Collectors.partitioningBy(x -> x.getSalary() > 7000));
        System.out.println(partitioning);

        // 分组:将员工按照性别分组
        Map<String, List<Person>> grouping1 = persons.stream().collect(Collectors.groupingBy(Person::getSex));
        System.out.println(grouping1);
        // 分组:将员工先按照性别分组,再按照地区分组
        Map<String, Map<String, List<Person>>> grouping2 = persons.stream().collect(Collectors.groupingBy(Person::getSex, Collectors.groupingBy(Person::getArea)));
        System.out.println(grouping2);
    }
}

10)接合|拼接(joining)

  joining可以将Stream中的元素用特定的连接符(没有的话,则直接连接)连接成一个字符串

package com.wind.stream;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Stream的使用:接合
 *
 * @author Wind
 * @date 2021-06-09
 */
public class Test10Stream {
    public static void main(String[] args) {

        List<Person> persons = new ArrayList<>();
        persons.add(new Person("张三", 7000, 34, "男", "陕西"));
        persons.add(new Person("李四", 8000, 24, "男", "河北"));
        persons.add(new Person("王五", 6000, 42, "女", "甘肃"));
        persons.add(new Person("王五", 9000, 12, "女", "上海"));
        // 将员工姓名用 “,” 拼接
        String nameStr = persons.stream().map(p -> p.getName()).collect(Collectors.joining(","));
        System.out.println(nameStr);

        List<String> strings = Arrays.asList("A", "B", "C", "D");
        // 将集合元素拼接成字符串
        String str = strings.stream().collect(Collectors.joining("-"));
        System.out.println(str);
    }
}

11)排序(sorted)

sorted中间操作。有两种排序:

  1. sorted():自然排序,流中元素实现Comparble接口
  2. sorted(Comparator com):Comparator排序器 自定义排序
package com.wind.stream;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Stream的使用:排序
 *
 * @author Wind
 * @date 2021-06-09
 */
public class Test11Stream {
    public static void main(String[] args) {

        List<Person> persons = new ArrayList<>();
        persons.add(new Person("张三", 7000, 34, "男", "陕西"));
        persons.add(new Person("李四", 8000, 42, "男", "河北"));
        persons.add(new Person("王五", 8000, 24, "女", "甘肃"));
        persons.add(new Person("王五", 9000, 12, "女", "上海"));

        // 将员工工资升序排序(自然排序)【从小到大】
        List<Person> sorted1 = persons.stream().sorted(Comparator.comparing(Person::getSalary)).collect(Collectors.toList());
        sorted1.forEach(System.out::println);
        System.out.println();

        // 将员工工资降序排序(倒序排序)【从大到小】
        List<Person> sorted2 = persons.stream().sorted(Comparator.comparing(Person::getSalary).reversed()).collect(Collectors.toList());
        sorted2.forEach(System.out::println);
        System.out.println();

        // 先按工资 再按年龄,升序排序
        List<Person> sorted3 = persons.stream().sorted(Comparator.comparing(Person::getSalary).thenComparing(Person::getAge)).collect(Collectors.toList());
        sorted3.forEach(System.out::println);
    }
}

12)提取/组合

流也可以进行 合并去重限制跳过 等操作

package com.wind.stream;

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Stream的使用:提取/组合
 *
 * @author Wind
 * @date 2021-06-09
 */
public class Test12Stream {
    public static void main(String[] args) {

        String[] arr1 = {"a", "b", "c", "d"};
        String[] arr2 = {"d", "e", "f", "g"};
        Stream<String> stream1 = Stream.of(arr1);
        Stream<String> stream2 = Stream.of(arr2);

        // concat:合并两个流,去重
        List<String> arr = Stream.concat(stream1, stream2).distinct().collect(Collectors.toList());
        arr.forEach(System.out::print);
        System.out.println();

        // limit:限制从流中获得前n个数据
        List<Integer> limit = Stream.iterate(1, t -> t + 2).limit(10).collect(Collectors.toList());
        limit.forEach(t -> System.out.print(t + ","));
        System.out.println();

        // skip:跳过前n个数据
        List<Integer> skip = Stream.iterate(1, t -> t + 2).skip(2).limit(5).collect(Collectors.toList());
        skip.forEach(t -> System.out.print(t + ",")); // 跳过了 1和3
    }
}

参考资料

1. 视频地址

2. 仓库地址

你可能感兴趣的:(积沙成塔,java)