User-Profile-Image
hankin
  • 5
  • Java
  • Kotlin
  • Spring
  • Web
  • SQL
  • MegaData
  • More
  • Experience
  • Enamiĝu al vi
  • 分类
    • Zuul
    • Zookeeper
    • XML
    • WebSocket
    • Web Notes
    • Web
    • Vue
    • Thymeleaf
    • SQL Server
    • SQL Notes
    • SQL
    • SpringSecurity
    • SpringMVC
    • SpringJPA
    • SpringCloud
    • SpringBoot
    • Spring Notes
    • Spring
    • Servlet
    • Ribbon
    • Redis
    • RabbitMQ
    • Python
    • PostgreSQL
    • OAuth2
    • NOSQL
    • Netty
    • MySQL
    • MyBatis
    • More
    • MinIO
    • MegaData
    • Maven
    • LoadBalancer
    • Kotlin Notes
    • Kotlin
    • Kafka
    • jQuery
    • JavaScript
    • Java Notes
    • Java
    • Hystrix
    • Git
    • Gateway
    • Freemarker
    • Feign
    • Eureka
    • ElasticSearch
    • Docker
    • Consul
    • Ajax
    • ActiveMQ
  • 页面
    • 归档
    • 摘要
    • 杂图
    • 问题随笔
  • 友链
    • Spring Cloud Alibaba
    • Spring Cloud Alibaba - 指南
    • Spring Cloud
    • Nacos
    • Docker
    • ElasticSearch
    • Kotlin中文版
    • Kotlin易百
    • KotlinWeb3
    • KotlinNhooo
    • 前端开源搜索
    • Ktorm ORM
    • Ktorm-KSP
    • Ebean ORM
    • Maven
    • 江南一点雨
    • 江南国际站
    • 设计模式
    • 熊猫大佬
    • java学习
    • kotlin函数查询
    • Istio 服务网格
    • istio
    • Ktor 异步 Web 框架
    • PostGis
    • kuangstudy
    • 源码地图
    • it教程吧
    • Arthas-JVM调优
    • Electron
    • bugstack虫洞栈
    • github大佬宝典
    • Sa-Token
    • 前端技术胖
    • bennyhuo-Kt大佬
    • Rickiyang博客
    • 李大辉大佬博客
    • KOIN
    • SQLDelight
    • Exposed-Kt-ORM
    • Javalin—Web 框架
    • http4k—HTTP包
    • 爱威尔大佬
    • 小土豆
    • 小胖哥安全框架
    • 负雪明烛刷题
    • Kotlin-FP-Arrow
    • Lua参考手册
    • 美团文章
    • Java 全栈知识体系
    • 尼恩架构师学习
    • 现代 JavaScript 教程
    • GO相关文档
    • Go学习导航
    • GoCN社区
    • GO极客兔兔-案例
    • 讯飞星火GPT
    • Hollis博客
    • PostgreSQL德哥
    • 优质博客推荐
    • 半兽人大佬
    • 系列教程
    • PostgreSQL文章
    • 云原生资料库
    • 并发博客大佬
Help?

Please contact us on our email for need any support

Support
    首页   ›   Java   ›   Java Notes   ›   正文
Java Notes

java—stream()方法的使用(java8)

2020-07-21 01:12:35
895  0 0
参考目录 隐藏
1) 具体用法(创建流)
2) 流的中间操作
3) sort 与 sorted 区别
4) stream 排序
5) 流的终止操作

阅读完需:约 19 分钟

Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。

特点:

        1 . 不是数据结构,不会保存数据。

        2. 不会修改原来的数据源,它会将操作后的数据保存到另外一个对象中。(保留意见:毕竟peek方法可以修改流中元素)

        3. 惰性求值,流在中间处理过程中,只是对操作进行了记录,并不会立即执行,需要等到执行终止操作的时候才会进行实际的计算。


  • 无状态:指元素的处理不受之前元素的影响;
  • 有状态:指该操作只有拿到所有元素之后才能继续下去。
  • 非短路操作:指必须处理所有元素才能得到最终结果;
  • 短路操作:指遇到某些符合条件的元素就可以得到最终结果,如 A || B,只要A为true,则无需判断B的结果。

具体用法(创建流)

1. 使用Collection下的 stream() 和 parallelStream() 方法

List<String> list = new ArrayList<>();
Stream<String> stream = list.stream(); //获取一个顺序流
Stream<String> parallelStream = list.parallelStream(); //获取一个并行流

2. 使用Arrays 中的 stream() 方法,将数组转成流

Integer[] nums = new Integer[10];
Stream<Integer> stream = Arrays.stream(nums);

3. 使用Stream中的静态方法:of()、iterate()、generate()

Stream<Integer> stream = Stream.of(1,2,3,4,5,6);
 
Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 2).limit(6);
stream2.forEach(System.out::println); // 0 2 4 6 8 10
 
Stream<Double> stream3 = Stream.generate(Math::random).limit(2);
stream3.forEach(System.out::println);

4. 使用 BufferedReader.lines() 方法,将每行内容转成流

BufferedReader reader = new BufferedReader(new FileReader("F:\\test_stream.txt"));
Stream<String> lineStream = reader.lines();
lineStream.forEach(System.out::println);

5. 使用 Pattern.splitAsStream() 方法,将字符串分隔成流

Pattern pattern = Pattern.compile(",");
Stream<String> stringStream = pattern.splitAsStream("a,b,c,d");
stringStream.forEach(System.out::println);

流的中间操作

1.筛选与切片
        filter:过滤流中的某些元素
        limit(n):获取n个元素
        skip(n):跳过n元素,配合limit(n)可实现分页
        distinct:通过流中元素的 hashCode() 和 equals() 去除重复元素

Stream<Integer> stream = Stream.of(6, 4, 6, 7, 3, 9, 8, 10, 12, 14, 14);
 
Stream<Integer> newStream = stream.filter(s -> s > 5) //6 6 7 9 8 10 12 14 14
        .distinct() //6 7 9 8 10 12 14
        .skip(2) //9 8 10 12 14
        .limit(2); //9 8
newStream.forEach(System.out::println);

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

List<String> list = Arrays.asList("a,b,c", "1,2,3");
 
//将每个元素转成一个新的且不带逗号的元素
Stream<String> s1 = list.stream().map(s -> s.replaceAll(",", ""));
s1.forEach(System.out::println); // abc  123
 
Stream<String> s3 = list.stream().flatMap(s -> {
    //将每个元素转换成一个stream
    String[] split = s.split(",");
    Stream<String> s2 = Arrays.stream(split);
    return s2;
});
s3.forEach(System.out::println); // a b c 1 2 3

3. 排序
        sorted():自然排序,流中元素需实现Comparable接口
        sorted(Comparator com):定制排序,自定义Comparator排序器  


List<String> list = Arrays.asList("aa", "ff", "dd");
//String 类自身已实现Compareable接口
list.stream().sorted().forEach(System.out::println);// aa dd ff
 
Student s1 = new Student("aa", 10);
Student s2 = new Student("bb", 20);
Student s3 = new Student("aa", 30);
Student s4 = new Student("dd", 40);
List<Student> studentList = Arrays.asList(s1, s2, s3, s4);
 
//自定义排序:先按姓名升序,姓名相同则按年龄升序
studentList.stream().sorted(
        (o1, o2) -> {
            if (o1.getName().equals(o2.getName())) {
                return o1.getAge() - o2.getAge();
            } else {
                return o1.getName().compareTo(o2.getName());
            }
        }
).forEach(System.out::println);

sort 与 sorted 区别

sort()与sorted()的不同在于,sort排序不产生新的列表,而sorted()是产生一个新的列表。

sort 是应用在 list 上的方法,sorted 可以对所有可迭代的对象进行排序操作。

stream 排序

// 实体类
@Data
@Builder
class Person {
    private String name;
    private Integer age;
    private BigDecimal salary;
    @JSONField(format = "yyyy-MM-dd HH:mm:ss")
    private Date birthday;
}

// 测试类
public class Java8StreamTest {

    /**
     * 常用排序手段: 根据date排序, 根据number排序, 根据money排序
     */
    public static void testStream() throws ParseException {
        LocalDateTime ldt = LocalDateTime.now();
        LocalDateTime with = ldt.with(TemporalAdjusters.lastDayOfMonth());
        Date date = Date.from(with.atZone(ZoneId.systemDefault()).toInstant());
        LocalDateTime parse = LocalDateTime.parse("2021-01-02 21:21:21", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date1 = sdf.parse("2021-01-02 21:32:32");
        Date date2 = sdf.parse("2021-07-05 12:32:45");
        Date date3 = sdf.parse("2020-09-18 23:21:21");
        Date date4 = sdf.parse("2018-05-02 19:23:01");
        Date date5 = sdf.parse("2019-11-25 03:54:12");
        List<Person> personList = new ArrayList<>();
        Person tom = Person.builder()
                .name("tom")
                .age(38)
                .salary(new BigDecimal("11123.00"))
                .birthday(date1).build();
        Person jerry = Person.builder()
                .name("jerry")
                .age(25)
                .salary(new BigDecimal("6464.00"))
                .birthday(date2).build();
        Person jack = Person.builder()
                .name("jack")
                .age(49)
                .salary(new BigDecimal("9797.00"))
                .birthday(date3).build();
        Person rose = Person.builder()
                .name("rose")
                .age(67)
                .salary(new BigDecimal("8098.00"))
                .birthday(date4).build();
        Person shel = Person.builder()
                .name("shel")
                .age(52)
                .salary(new BigDecimal("94465165.00"))
                .birthday(date5).build();
        personList.add(tom);
        personList.add(tom);
        personList.add(jerry);
        personList.add(jack);
        personList.add(rose);
        personList.add(shel);
        personList.sort((o1, o2) -> o1.getSalary().compareTo(o2.getSalary()));
        System.out.println("根据金钱升序:" + personList);
        personList.sort((o1, o2) -> -1 * o1.getSalary().compareTo(o2.getSalary()));
        System.out.println("根据金钱降序:" + personList);

        personList.sort(new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                return o1.getAge().compareTo(o2.getAge());
            }
        });
        System.out.println("根据年龄升序:" + personList);

        personList.sort(new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                return o1.getBirthday().compareTo(o2.getBirthday());
            }
        });
        System.out.println("根据日期升序:" + personList);

        List<Person> collect = personList.stream().distinct().collect(Collectors.toList());
        System.out.println("java8根据对象去重:" + collect);

        List<Person> collect1 = personList.stream().sorted(Comparator.comparing(Person::getAge)).collect(Collectors.toList());
        System.out.println("java8根据年龄升序:" + collect1);

        List<Person> collect2 = personList.stream().sorted(Comparator.comparing(Person::getSalary).reversed()).collect(Collectors.toList());
        System.out.println("java8根据金钱降序:" + collect2);

        List<Person> collect3 = personList.stream().distinct().sorted(Comparator.comparing(Person::getBirthday).thenComparing(Person::getSalary)).collect(Collectors.toList());
        System.out.println("java8先去重再根据日期排序,再根据年龄排序:" + collect3);


        List<Person> collect4 = personList.stream().filter(person -> person.getName() == "tom" || person.getName() == "jerry").collect(Collectors.toList());
        System.out.println("java8获取符合条件的变量的对象:" + collect4);

        // 相当于获取数据库表的列
        List<String> collect5 = personList.stream().map(person -> person.getName() + " - " + person.getAge()).collect(Collectors.toList());
        System.out.println("java8获取所有的对象的属性组合:" + collect5);
        List<BigDecimal> collect6 = personList.stream().map(person -> person.getSalary()).collect(Collectors.toList());
        System.out.println("java8获取所有对象的某个属性(salary):" + collect6);
        List<BigDecimal> collect7 = collect6.stream().skip(1).collect(Collectors.toList());
        System.out.println("将第一个元素跳过: " + collect7);
        BigDecimal max = collect6.stream().max(BigDecimal::compareTo).get();
        System.out.println("获取最大的值:" + max);
        BigDecimal min = collect6.stream().min(BigDecimal::compareTo).get();
        System.out.println("获取最小的值:" + min);
        BigDecimal sum = collect6.stream().reduce(BigDecimal::add).get();
        System.out.println("获取总和:" + sum);
        BigDecimal min2 = collect6.stream().reduce(BigDecimal.valueOf(0), BigDecimal::min);
        System.out.println("最小值:" + min2);
        BigDecimal max2 = collect6.stream().reduce(BigDecimal.valueOf(0), BigDecimal::max);
        System.out.println("最大值:" + max2);

    }
    public static void main(String[] args) throws ParseException {
        testStream();
    }
}

// 结果
根据金钱升序:[Person(name=jerry, age=25, salary=6464.00, birthday=Mon Jul 05 12:32:45 CST 2021), Person(name=rose, age=67, salary=8098.00, birthday=Wed May 02 19:23:01 CST 2018), Person(name=jack, age=49, salary=9797.00, birthday=Fri Sep 18 23:21:21 CST 2020), Person(name=tom, age=38, salary=11123.00, birthday=Sat Jan 02 21:32:32 CST 2021), Person(name=tom, age=38, salary=11123.00, birthday=Sat Jan 02 21:32:32 CST 2021), Person(name=shel, age=52, salary=94465165.00, birthday=Mon Nov 25 03:54:12 CST 2019)]
根据金钱降序:[Person(name=shel, age=52, salary=94465165.00, birthday=Mon Nov 25 03:54:12 CST 2019), Person(name=tom, age=38, salary=11123.00, birthday=Sat Jan 02 21:32:32 CST 2021), Person(name=tom, age=38, salary=11123.00, birthday=Sat Jan 02 21:32:32 CST 2021), Person(name=jack, age=49, salary=9797.00, birthday=Fri Sep 18 23:21:21 CST 2020), Person(name=rose, age=67, salary=8098.00, birthday=Wed May 02 19:23:01 CST 2018), Person(name=jerry, age=25, salary=6464.00, birthday=Mon Jul 05 12:32:45 CST 2021)]
根据年龄升序:[Person(name=jerry, age=25, salary=6464.00, birthday=Mon Jul 05 12:32:45 CST 2021), Person(name=tom, age=38, salary=11123.00, birthday=Sat Jan 02 21:32:32 CST 2021), Person(name=tom, age=38, salary=11123.00, birthday=Sat Jan 02 21:32:32 CST 2021), Person(name=jack, age=49, salary=9797.00, birthday=Fri Sep 18 23:21:21 CST 2020), Person(name=shel, age=52, salary=94465165.00, birthday=Mon Nov 25 03:54:12 CST 2019), Person(name=rose, age=67, salary=8098.00, birthday=Wed May 02 19:23:01 CST 2018)]
根据日期升序:[Person(name=rose, age=67, salary=8098.00, birthday=Wed May 02 19:23:01 CST 2018), Person(name=shel, age=52, salary=94465165.00, birthday=Mon Nov 25 03:54:12 CST 2019), Person(name=jack, age=49, salary=9797.00, birthday=Fri Sep 18 23:21:21 CST 2020), Person(name=tom, age=38, salary=11123.00, birthday=Sat Jan 02 21:32:32 CST 2021), Person(name=tom, age=38, salary=11123.00, birthday=Sat Jan 02 21:32:32 CST 2021), Person(name=jerry, age=25, salary=6464.00, birthday=Mon Jul 05 12:32:45 CST 2021)]
java8根据对象去重:[Person(name=rose, age=67, salary=8098.00, birthday=Wed May 02 19:23:01 CST 2018), Person(name=shel, age=52, salary=94465165.00, birthday=Mon Nov 25 03:54:12 CST 2019), Person(name=jack, age=49, salary=9797.00, birthday=Fri Sep 18 23:21:21 CST 2020), Person(name=tom, age=38, salary=11123.00, birthday=Sat Jan 02 21:32:32 CST 2021), Person(name=jerry, age=25, salary=6464.00, birthday=Mon Jul 05 12:32:45 CST 2021)]
java8根据年龄升序:[Person(name=jerry, age=25, salary=6464.00, birthday=Mon Jul 05 12:32:45 CST 2021), Person(name=tom, age=38, salary=11123.00, birthday=Sat Jan 02 21:32:32 CST 2021), Person(name=tom, age=38, salary=11123.00, birthday=Sat Jan 02 21:32:32 CST 2021), Person(name=jack, age=49, salary=9797.00, birthday=Fri Sep 18 23:21:21 CST 2020), Person(name=shel, age=52, salary=94465165.00, birthday=Mon Nov 25 03:54:12 CST 2019), Person(name=rose, age=67, salary=8098.00, birthday=Wed May 02 19:23:01 CST 2018)]
java8根据金钱降序:[Person(name=shel, age=52, salary=94465165.00, birthday=Mon Nov 25 03:54:12 CST 2019), Person(name=tom, age=38, salary=11123.00, birthday=Sat Jan 02 21:32:32 CST 2021), Person(name=tom, age=38, salary=11123.00, birthday=Sat Jan 02 21:32:32 CST 2021), Person(name=jack, age=49, salary=9797.00, birthday=Fri Sep 18 23:21:21 CST 2020), Person(name=rose, age=67, salary=8098.00, birthday=Wed May 02 19:23:01 CST 2018), Person(name=jerry, age=25, salary=6464.00, birthday=Mon Jul 05 12:32:45 CST 2021)]
java8先去重再根据日期排序,再根据年龄排序:[Person(name=rose, age=67, salary=8098.00, birthday=Wed May 02 19:23:01 CST 2018), Person(name=shel, age=52, salary=94465165.00, birthday=Mon Nov 25 03:54:12 CST 2019), Person(name=jack, age=49, salary=9797.00, birthday=Fri Sep 18 23:21:21 CST 2020), Person(name=tom, age=38, salary=11123.00, birthday=Sat Jan 02 21:32:32 CST 2021), Person(name=jerry, age=25, salary=6464.00, birthday=Mon Jul 05 12:32:45 CST 2021)]
java8获取符合条件的变量的对象:[Person(name=tom, age=38, salary=11123.00, birthday=Sat Jan 02 21:32:32 CST 2021), Person(name=tom, age=38, salary=11123.00, birthday=Sat Jan 02 21:32:32 CST 2021), Person(name=jerry, age=25, salary=6464.00, birthday=Mon Jul 05 12:32:45 CST 2021)]
java8获取所有的对象的属性组合:[rose - 67, shel - 52, jack - 49, tom - 38, tom - 38, jerry - 25]
java8获取所有对象的某个属性(salary):[8098.00, 94465165.00, 9797.00, 11123.00, 11123.00, 6464.00]
将第一个元素跳过: [94465165.00, 9797.00, 11123.00, 11123.00, 6464.00]
获取最大的值:94465165.00
获取最小的值:6464.00
获取总和:94511770.00
最小值:0
最大值:94465165.00

4. 消费
        peek:如同于map,能得到流中的每一个元素。但map接收的是一个Function表达式,有返回值;而peek接收的是Consumer表达式,没有返回值。

Student s1 = new Student("aa", 10);
Student s2 = new Student("bb", 20);
List<Student> studentList = Arrays.asList(s1, s2);
 
studentList.stream()
        .peek(o -> o.setAge(100))
        .forEach(System.out::println);   
 
//结果:
Student{name='aa', age=100}
Student{name='bb', age=100} 

流的终止操作

1. 匹配、聚合操作
        allMatch:接收一个 Predicate 函数,当流中每个元素都符合该断言时才返回true,否则返回false
        noneMatch:接收一个 Predicate 函数,当流中每个元素都不符合该断言时才返回true,否则返回false
        anyMatch:接收一个 Predicate 函数,只要流中有一个元素满足该断言则返回true,否则返回false
        findFirst:返回流中第一个元素
        findAny:返回流中的任意元素
        count:返回流中元素的总个数
        max:返回流中元素最大值
        min:返回流中元素最小值

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
 
boolean allMatch = list.stream().allMatch(e -> e > 10); //false
boolean noneMatch = list.stream().noneMatch(e -> e > 10); //true
boolean anyMatch = list.stream().anyMatch(e -> e > 4);  //true
 
Integer findFirst = list.stream().findFirst().get(); //1
Integer findAny = list.stream().findAny().get(); //1
 
long count = list.stream().count(); //5
Integer max = list.stream().max(Integer::compareTo).get(); //5
Integer min = list.stream().min(Integer::compareTo).get(); //1

2. 递归操作
        Optional reduce(BinaryOperator accumulator):第一次执行时,accumulator函数的第一个参数为流中的第一个元素,第二个参数为流中元素的第二个元素;第二次执行时,第一个参数为第一次函数执行的结果,第二个参数为流中的第三个元素;依次类推。
        T reduce(T identity, BinaryOperator accumulator):流程跟上面一样,只是第一次执行时,accumulator函数的第一个参数为identity,而第二个参数为流中的第一个元素。
         U reduce(U identity,BiFunction accumulator,BinaryOperator combiner):在串行流(stream)中,该方法跟第二个方法一样,即第三个参数combiner不会起作用。在并行流(parallelStream)中,我们知道流被fork join出多个线程进行执行,此时每个线程的执行流程就跟第二个方法reduce(identity,accumulator)一样,而第三个参数combiner函数,则是将每个线程的执行结果当成一个新的流,然后使用第一个方法reduce(accumulator)流程进行递归。

//经过测试,当元素个数小于24时,并行时线程数等于元素个数,当大于等于24时,并行时线程数为16
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24);
 
Integer v = list.stream().reduce((x1, x2) -> x1 + x2).get();
System.out.println(v);   // 300
 
Integer v1 = list.stream().reduce(10, (x1, x2) -> x1 + x2);
System.out.println(v1);  //310
 
Integer v2 = list.stream().reduce(0,
        (x1, x2) -> {
            System.out.println("stream accumulator: x1:" + x1 + "  x2:" + x2);
            return x1 - x2;
        },
        (x1, x2) -> {
            System.out.println("stream combiner: x1:" + x1 + "  x2:" + x2);
            return x1 * x2;
        });
System.out.println(v2); // -300
 
Integer v3 = list.parallelStream().reduce(0,
        (x1, x2) -> {
            System.out.println("parallelStream accumulator: x1:" + x1 + "  x2:" + x2);
            return x1 - x2;
        },
        (x1, x2) -> {
            System.out.println("parallelStream combiner: x1:" + x1 + "  x2:" + x2);
            return x1 * x2;
        });
System.out.println(v3); //197474048

3. 收集操作
        collect:接收一个Collector实例,将流中元素收集成另外一个数据结构。
        Collector 是一个接口,有以下5个抽象方法:
        Supplier supplier():创建一个结果容器A
        BiConsumer accumulator():消费型接口,第一个参数为容器A,第二个参数为流中元素T。
        BinaryOperator combiner():函数接口,该参数的作用跟上一个方法(reduce)中的combiner参数一样,将并行流中各                                                                 个子进程的运行结果(accumulator函数操作后的容器A)进行合并。
        Function finisher():函数式接口,参数为:容器A,返回类型为:collect方法最终想要的结果R。
        Set characteristics():返回一个不可变的Set集合,用来表明该Collector的特征。有以下三个特征:
        CONCURRENT:表示此收集器支持并发。(官方文档还有其他描述,暂时没去探索,故不作过多翻译)
        UNORDERED:表示该收集操作不会保留流中元素原有的顺序。
        IDENTITY_FINISH:表示finisher参数只是标识而已,可忽略。

Collector 工具库:Collectors

Student s1 = new Student("aa", 10,1);
Student s2 = new Student("bb", 20,2);
Student s3 = new Student("cc", 10,3);
List<Student> list = Arrays.asList(s1, s2, s3);
 
//装成list
List<Integer> ageList = list.stream().map(Student::getAge).collect(Collectors.toList()); // [10, 20, 10]
 
//转成set
Set<Integer> ageSet = list.stream().map(Student::getAge).collect(Collectors.toSet()); // [20, 10]
 
//转成map,注:key不能相同,否则报错
Map<String, Integer> studentMap = list.stream().collect(Collectors.toMap(Student::getName, Student::getAge)); // {cc=10, bb=20, aa=10}
 
//字符串分隔符连接
String joinName = list.stream().map(Student::getName).collect(Collectors.joining(",", "(", ")")); // (aa,bb,cc)
 
//聚合操作
//1.学生总数
Long count = list.stream().collect(Collectors.counting()); // 3
//2.最大年龄 (最小的minBy同理)
Integer maxAge = list.stream().map(Student::getAge).collect(Collectors.maxBy(Integer::compare)).get(); // 20
//3.所有人的年龄
Integer sumAge = list.stream().collect(Collectors.summingInt(Student::getAge)); // 40
//4.平均年龄
Double averageAge = list.stream().collect(Collectors.averagingDouble(Student::getAge)); // 13.333333333333334
// 带上以上所有方法
DoubleSummaryStatistics statistics = list.stream().collect(Collectors.summarizingDouble(Student::getAge));
System.out.println("count:" + statistics.getCount() + ",max:" + statistics.getMax() + ",sum:" + statistics.getSum() + ",average:" + statistics.getAverage());
 
//分组
Map<Integer, List<Student>> ageMap = list.stream().collect(Collectors.groupingBy(Student::getAge));
//多重分组,先根据类型分再根据年龄分
Map<Integer, Map<Integer, List<Student>>> typeAgeMap = list.stream().collect(Collectors.groupingBy(Student::getType, Collectors.groupingBy(Student::getAge)));
 
//分区
//分成两部分,一部分大于10岁,一部分小于等于10岁
Map<Boolean, List<Student>> partMap = list.stream().collect(Collectors.partitioningBy(v -> v.getAge() > 10));
 
//递归
Integer allAge = list.stream().map(Student::getAge).collect(Collectors.reducing(Integer::sum)).get(); //40

Collectors.groupingBy用法

public Product(Long id, Integer num, BigDecimal price, String name, String category) {
	this.id = id;
	this.num = num;
	this.price = price;
	this.name = name;
	this.category = category;
}

Product prod1 = new Product(1L, 1, new BigDecimal("15.5"), "面包", "零食");
Product prod2 = new Product(2L, 2, new BigDecimal("20"), "饼干", "零食");
Product prod3 = new Product(3L, 3, new BigDecimal("30"), "月饼", "零食");
Product prod4 = new Product(4L, 3, new BigDecimal("10"), "青岛啤酒", "啤酒");
Product prod5 = new Product(5L, 10, new BigDecimal("15"), "百威啤酒", "啤酒");
List<Product> prodList = Lists.newArrayList(prod1, prod2, prod3, prod4, prod5);


//按照类目分组:
Map<String, List<Product>> prodMap= prodList.stream().collect(Collectors.groupingBy(Product::getCategory));
//{"啤酒":[{"category":"啤酒","id":4,"name":"青岛啤酒","num":3,"price":10},{"category":"啤酒","id":5,"name":"百威啤酒","num":10,"price":15}],"零食":[{"category":"零食","id":1,"name":"面包","num":1,"price":15.5},{"category":"零食","id":2,"name":"饼干","num":2,"price":20},{"category":"零食","id":3,"name":"月饼","num":3,"price":30}]}

//按照几个属性拼接分组:
Map<String, List<Product>> prodMap = prodList.stream().collect(Collectors.groupingBy(item -> item.getCategory() + "_" + item.getName()));
//{"零食_月饼":[{"category":"零食","id":3,"name":"月饼","num":3,"price":30}],"零食_面包":[{"category":"零食","id":1,"name":"面包","num":1,"price":15.5}],"啤酒_百威啤酒":[{"category":"啤酒","id":5,"name":"百威啤酒","num":10,"price":15}],"啤酒_青岛啤酒":[{"category":"啤酒","id":4,"name":"青岛啤酒","num":3,"price":10}],"零食_饼干":[{"category":"零食","id":2,"name":"饼干","num":2,"price":20}]}

//根据不同条件分组
Map<String, List<Product>> prodMap= prodList.stream().collect(Collectors.groupingBy(item -> {
	if(item.getNum() < 3) {
		return "3";
	}else {
		return "other";
	}
}));
//{"other":[{"category":"零食","id":3,"name":"月饼","num":3,"price":30},{"category":"啤酒","id":4,"name":"青岛啤酒","num":3,"price":10},{"category":"啤酒","id":5,"name":"百威啤酒","num":10,"price":15}],"3":[{"category":"零食","id":1,"name":"面包","num":1,"price":15.5},{"category":"零食","id":2,"name":"饼干","num":2,"price":20}]}

//多级分组
Map<String, Map<String, List<Product>>> prodMap= prodList.stream().collect(Collectors.groupingBy(Product::getCategory, Collectors.groupingBy(item -> {
	if(item.getNum() < 3) {
		return "3";
	}else {
		return "other";
	}
})));
//{"啤酒":{"other":[{"category":"啤酒","id":4,"name":"青岛啤酒","num":3,"price":10},{"category":"啤酒","id":5,"name":"百威啤酒","num":10,"price":15}]},"零食":{"other":[{"category":"零食","id":3,"name":"月饼","num":3,"price":30}],"3":[{"category":"零食","id":1,"name":"面包","num":1,"price":15.5},{"category":"零食","id":2,"name":"饼干","num":2,"price":20}]}}

//按子组收集数据

//求总数
Map<String, Long> prodMap = prodList.stream().collect(Collectors.groupingBy(Product::getCategory, Collectors.counting()));
//{"啤酒":2,"零食":3}

//求和
Map<String, Integer> prodMap = prodList.stream().collect(Collectors.groupingBy(Product::getCategory, Collectors.summingInt(Product::getNum)));
//{"啤酒":13,"零食":6}

//把收集器的结果转换为另一种类型
Map<String, Product> prodMap = prodList.stream().collect(Collectors.groupingBy(Product::getCategory, Collectors.collectingAndThen(Collectors.maxBy(Comparator.comparingInt(Product::getNum)), Optional::get)));
//{"啤酒":{"category":"啤酒","id":5,"name":"百威啤酒","num":10,"price":15},"零食":{"category":"零食","id":3,"name":"月饼","num":3,"price":30}}

//联合其他收集器
Map<String, Set<String>> prodMap = prodList.stream().collect(Collectors.groupingBy(Product::getCategory, Collectors.mapping(Product::getName, Collectors.toSet())));
//{"啤酒":["青岛啤酒","百威啤酒"],"零食":["面包","饼干","月饼"]}

Collectors.toList() 解析

//toList 源码
public static <T> Collector<T, ?, List<T>> toList() {
    return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
            (left, right) -> {
                left.addAll(right);
                return left;
            }, CH_ID);
}
 
//为了更好地理解,我们转化一下源码中的lambda表达式
public <T> Collector<T, ?, List<T>> toList() {
    Supplier<List<T>> supplier = () -> new ArrayList();
    BiConsumer<List<T>, T> accumulator = (list, t) -> list.add(t);
    BinaryOperator<List<T>> combiner = (list1, list2) -> {
        list1.addAll(list2);
        return list1;
    };
    Function<List<T>, List<T>> finisher = (list) -> list;
    Set<Collector.Characteristics> characteristics = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH));
 
    return new Collector<T, List<T>, List<T>>() {
        @Override
        public Supplier supplier() {
            return supplier;
        }
 
        @Override
        public BiConsumer accumulator() {
            return accumulator;
        }
 
        @Override
        public BinaryOperator combiner() {
            return combiner;
        }
 
        @Override
        public Function finisher() {
            return finisher;
        }
 
        @Override
        public Set<Characteristics> characteristics() {
            return characteristics;
        }
    };
 
}

如本文“对您有用”,欢迎随意打赏作者,让我们坚持创作!

0 打赏
Enamiĝu al vi
不要为明天忧虑.因为明天自有明天的忧虑.一天的难处一天当就够了。
543文章 68评论 294点赞 593846浏览

随机文章
SpringCloud—LoadBalanced负载均衡
2年前
Spring笔记15—声明式事务
5年前
Java—注解用法详解—@SuppressWarnings
3年前
SpringSecurity 竟然可以同时存在多个过滤器链?
5年前
Spring Data REST—两行代码搞定RESTFul(SpringBoot补充)
5年前
博客统计
  • 日志总数:543 篇
  • 评论数目:68 条
  • 建站日期:2020-03-06
  • 运行天数:1927 天
  • 标签总数:23 个
  • 最后更新:2024-12-20
Copyright © 2025 网站备案号: 浙ICP备20017730号 身体没有灵魂是死的,信心没有行为也是死的。
主页
页面
  • 归档
  • 摘要
  • 杂图
  • 问题随笔
博主
Enamiĝu al vi
Enamiĝu al vi 管理员
To be, or not to be
543 文章 68 评论 593846 浏览
测试
测试
看板娘
赞赏作者

请通过微信、支付宝 APP 扫一扫

感谢您对作者的支持!

 支付宝 微信支付