JDK8 新特性 Stream API 进阶 (结合案例详解--通透--讲清)

news2024/11/25 1:05:47

👳我亲爱的各位大佬们好😘😘😘
♨️本篇文章记录的为 JDK8 新特性 Stream API 进阶 相关内容,适合在学Java的小白,帮助新手快速上手,也适合复习中,面试中的大佬🙉🙉🙉。
♨️如果文章有什么需要改进的地方还请大佬不吝赐教❤️🧡💛
👨‍🔧 个人主页 : 阿千弟
🔥 相关内容👉👉👉 : 都2023年了,如果不会Lambda表达式、函数式编程?你确定能看懂公司代码?

前情回顾 :

最近, 我的一些已经入职一段时间的朋友和我说, 在公司中做的最多的业务就是crud, 他最近做的项目是一个h5的中移动一个外包项目, 虽然业务并不复杂, 但是呢数据量非常庞大, 数据库的表很多, 大概四五百张表, 每天的crud写的我这哥们也是很烦.😭😭😭

所以对于这个问题, 建议哥们可以尝试使用 JDK8 新特性 Stream的方式来处理数据, 对于集合, 数组, map的处理很方便, 也很快速, 这时一些朋友会问, stream阅读性不好, 难以读懂, 但是呢你想想别管它咋样, 能有利于咱们开发提高咱们的开发效率就行了呗

为此我专门出来一期关于JDK8 新特性 Stream API 进阶使用的文章, 来帮助咱们经常写crud的朋友来简化开发, 可能你刚开始用的时候很抵触, 但是你用熟练了会觉得它真的爽.🙏🙏🙏希望大家多多支持

在这里插入图片描述

1、了解 Stream

​ Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另外一个则是Stream API(java.util.stream.*)。Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。

2、什么是 Stream

流(Stream) 到底是什么呢?

是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。“集合讲的是数据,流讲的是计算!”

注意:

  • Stream 自己不会存储元素。
  • Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
  • Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

3、Stream 的操作三个步骤

  • 创建 Stream

一个数据源(如:集合、数组),获取一个流

  • 中间操作

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

  • 终止操作(终端操作)

一个终止操作,执行中间操作链,并产生结果

Stream 的中间操作

​ 多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”。

1、筛选与切片

方 法描 述
filter(Predicate p)接收 Lambda , 从流中排除某些元素。
distinct()筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
limit(long maxSize)截断流,使其元素不超过给定数量。
skip(long n)跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补

2、映射

方 法描 述
map(Function f) 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
mapToDouble(ToDoubleFunction f)接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 DoubleStream。
mapToInt(ToIntFunction f) 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 IntStream。
mapToLong(ToLongFunction f) 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 LongStream。
flatMap(Function f) 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流

3、排序

方 法描 述
sorted()产生一个新流,其中按自然顺序排序
sorted(Comparator comp)产生一个新流,其中按比较器顺序排序

Stream 的终止操作

终端操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如:List、Integer,甚至是 void。

1、查找与匹配

方 法描 述
allMatch(Predicate p)检查是否匹配所有元素
anyMatch(Predicate p)检查是否至少匹配一个元素
noneMatch(Predicate p)检查是否没有匹配所有元素
findFirst()返回第一个元素
findAny()返回当前流中的任意元素
count()返回流中元素总数
max(Comparator c)返回流中最大值
min(Comparator c)返回流中最小值
forEach(Consumer c)内部迭代(使用 Collection 接口需要用户去做迭代,称为外部迭代。相反,Stream API 使用内部迭代——它帮你把迭代做了)

2、归约

方 法描 述
reduce(T iden, BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回 T
reduce(BinaryOperator b)可以将流中元素反复结合起来,得到一个值。返回 Optional

3、收集

方 法描 述
collect(Collector c)将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法

​ Collector 接口中方法的实现决定了如何对流执行收集操作(如收集到 List、Set、Map)。但是 Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例,具体方法与实例如下表:

方法返回类型作用代码
toList List把流中元素收集到ListList emps= list.stream().collect(Collectors.toList());
toSetSet把流中元素收集到SetSet emps= list.stream().collect(Collectors.toSet());
toCollection Collection把流中元素收集到创建的集合Collectionemps=list.stream().collect(Collectors.toCollection(ArrayList::new));
countingLong计算流中元素的个数long count = list.stream().collect(Collectors.counting());
summingInt Integer对流中元素的整数属性求和int total=list.stream().collect(Collectors.summingInt(Employee::getSalary));
averagingIntDouble计算流中元素Integer属性的平均值double avg= list.stream().collect(Collectors.averagingInt(Employee::getSalary));
summarizingIntIntSummaryStatistics收集流中Integer属性的和。IntSummaryStatisticsiss= list.stream().collect(Collectors.summarizingInt(Employee::getSalary));
joiningString连接流中每个字符串String str= list.stream().map(Employee::getName).collect(Collectors.joining());
maxByOptional根据比较器选择最大值Optionalmax= list.stream().collect(Collectors.maxBy(comparingInt(Employee::getSalary)));
minByOptional根据比较器选择最小值Optional min = list.stream().collect(Collectors.minBy(comparingInt(Employee::getSalary)));
reducing归约产生的类型从一个作为累加器的初始值开始,利用BinaryOperator与流中元素逐个结合,从而归约成单个值int total=list.stream().collect(Collectors.reducing(0, Employee::getSalar, Integer::sum));
collectingAndThen转换函数返回的类型包裹另一个收集器,对其结果转换函数int how= list.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size));
groupingByMap<K, List>根据某属性值对流分组,属性为K,结果为VMap<Emp.Status, List> map= list.stream().collect(Collectors.groupingBy(Employee::getStatus));
partitioningByMap<Boolean, List>根据true或false进行分区Map<Boolean,List>vd= list.stream().collect(Collectors.partitioningBy(Employee::getManage));

在这里插入图片描述

下面是工作中经常被用到的案例, 请仔细品味

一些使用场景

1、取出自身重复的数据

@Test
public void test01() {
    List<String> list = Arrays.asList(
        "g", "k", "f", "k", "g", "b"
    );
    List<String> li = list.stream().
    		filter(li1 -> list.stream().filter((li2 -> li2.equals(li1))).count() > 1l)
        	.collect(toList());
    System.out.println(li);
}

2、累加数字

@Test
public void test12() {
    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
    Integer sum = list.stream()
        .reduce(0, (x, y) -> x + y);
    System.out.println(sum);
}

3、字符串数字集合与整数集合互转

@Test
public void test14() {
    List<Integer> intList = new ArrayList<>();
    intList.add(1);
    intList.add(3);
    intList.add(4);
    List<String> intToStrList = intList.stream().map(String::valueOf).collect(toList());
    intToStrList.stream().forEach(str -> {
        System.out.println(str);
    });

    List<String> stringList = new ArrayList<>();
    stringList.add("10");
    stringList.add("20");
    stringList.add("30");
    List<String> stringToIntList = stringList.stream().map(String::valueOf).collect(toList());
    stringToIntList.stream().forEach(num -> {
        System.out.println(num);
    });
}

4、取list1与list2的交集

List<String> list1 = Arrays.asList(
    "张三", "李四", "李刚", "隋通"
);

List<String> list2 = Arrays.asList(
    "熊大", "熊二", "张三", "李刚"
);

//15.取list1与list2的交集
@Test
public void test15() {
    List<String> intersection = list1.stream().filter(item -> list2.contains(item)).collect(toList());
    System.out.println("---得到交集---");
    intersection.parallelStream().forEach(System.out::println);
}

5、取list1与list2的差集

@Test
public void test16() {
    List<String> reduce1 = list1.stream().filter(item -> !list2.contains(item)).collect(toList());
    System.out.println("---得到差集 reduce1 (list1 - list2)---");
    reduce1.parallelStream().forEach(System.out::println);
}

6、取list1和list2的并集

@Test
public void test18() {
    List<String> listAll = list1.parallelStream().collect(toList());
    List<String> listAll2 = list2.parallelStream().collect(toList());
    listAll.addAll(listAll2);
    System.out.println("---得到并集 listAll---");
    listAll.parallelStream().forEach(System.out::println);
    // 去重并集
    List<String> listAllDistinct = listAll.stream().distinct().collect(toList());
    System.out.println("---得到去重并集 listAllDistinct---");
    listAllDistinct.parallelStream().forEach(System.out::println);
    System.out.println("---原来的List1---");
    list1.parallelStream().forEach(System.out::println);
    System.out.println("---原来的List2---");
    list2.parallelStream().forEach(System.out::println);
}

7、统计集合重复元素出现次数,并且去重返回hashmap

List<String> list = Arrays.asList(
    "b", "g", "d", "d", "t", "j", "d", "a", "c", "f", "a", "b", "s", "w", "w", "b"
);

//19.统计集合重复元素出现次数,并且去重返回hashmap
@Test
public void test19() {
    Map<String, Long> map = list.stream().
        collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
    System.out.println(map);
    //由于hashmap无序,所以在排序放入LinkedHashMap里(key升序)
    Map<String, Long> sortMap = new LinkedHashMap<>();
    map.entrySet().stream().sorted(Map.Entry.comparingByKey()).
        forEachOrdered(e -> sortMap.put(e.getKey(), e.getValue()));
    System.out.println(sortMap);
    //获取排序后map的key集合
    List<String> keys = new LinkedList<>();
    sortMap.entrySet().stream().forEachOrdered(e -> keys.add(e.getKey()));
    System.out.println(keys);
    //获取排序后map的value集合
    List<Long> values = new LinkedList<>();
    sortMap.entrySet().stream().forEachOrdered(e -> values.add(e.getValue()));
    System.out.println(values);
}

8、stream循环拿到下标

@Test
public void test21(){
    Stream.iterate(0, i -> i + 1).limit(users01.size()).forEach(index -> {
        System.out.println(index);
    });
}

9、List集合转Map任意一个属性作为键,键相同的对象用集合存储

@Test
public void test22(){
    Map<Integer,List<User>> userMap = new HashMap<>();
    List<User> userList = null;
    for (int i = 0; i < users02.size(); i++) {
        User user = users02.get(i);
        if(userMap.get(user.getAge())==null){
            userList = new ArrayList<>();
        }
        userList.add(user);
        userMap.put(user.getAge(),userList);
    }
    for(Integer key : userMap.keySet()){
        System.out.println("key:"+key+"\n"+"value:"+userMap.get(key));
    }
}

10、List集合转Map任意一个属性作为键,键相同的对象用集合存储(Java8新特性实现)

@Test
public void test23(){
    Map<Integer, List<User>> listMap = users02.stream().collect(Collectors.groupingBy(User::getAge));
    listMap.keySet().forEach(key->{
        System.out.println(key);
        listMap.get(key).forEach((user)->System.out.println(user));
    });
    for(Integer key : listMap.keySet()){
        System.out.println("key:"+key+"\n"+"value:"+listMap.get(key));
    }
}

11、取出users01中age一样的,并算出有几项

@Test
public void test03() {
    List<User> userList = users01.stream().filter(user1 -> users01.stream().filter((user2 -> user2.getAge().equals(user1.getAge()))).count() > 1l)
        .collect(toList());

    userList.stream().forEach((user) -> {
        System.out.println(user.getName() + ":" + user.getAge());
    });
    Map<Object, Object> str = new HashMap<>();
    for (User user : userList) {
        List<User> collect = userList.stream().filter(d -> d.getAge().equals(user.getAge())).collect(toList());
        str.put(user.getAge(), collect.size());
    }
    for (Object key : str.keySet()) {
        String value = str.get(key).toString();//
        System.out.println("key:" + key + " value:" + value);
    }
}

12、取出users01中的Id在users02中没有的user

/**
     * allMatch——检查是否匹配所有元素
     * anyMatch——检查是否至少匹配一个元素
     * noneMatch——检查是否没有匹配的元素
     */
//4.取出users01中的Id在users02中没有的user
@Test
public void test04() {
    //取出所有users02的id
    List<Integer> user02Ids = users02.stream().map(User::getId).collect(toList());
    System.out.println(user02Ids);
    List<User> userList = users01.stream().filter(user1 -> !user02Ids.stream().anyMatch(user02Id -> user1.getId().equals(user02Id))).collect(toList());
    userList.stream().forEach((user) -> {
        System.out.println(user.getName() + ":" + user.getAge());
    });



    List<SkuEsModel.Attrs> attrList = baseAttrs.stream().filter(item -> {
        // 过滤掉不包含在 searchAttrIds集合中的元素
        return idSet.contains(item.getAttrId());
    }).collect(Collectors.toList());
}

13、去掉users01name重复的只保留一个

@Test
public void test07() {
    List<User> userList = users01.stream().collect(
        Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(o -> o.getName()))),
                                     ArrayList::new));
    userList.stream().forEach((user) -> {
        System.out.println(user.getName() + ":" + user.getAge() + ":" + user.getBirthday());
    });
}

14、将Student信息注入到相应的Grade里面的studentList中

List<Student> stuList = Arrays.asList(
    new Student(1, "张三", 1),
    new Student(2, "李四", 2),
    new Student(3, "李飞", 2)
);

List<Grade> gradeList = Arrays.asList(
    new Grade(1, "大一"),
    new Grade(2, "大二")
);

//13.将Student信息注入到相应的Grade里面的studentList中
@Test
public void test13() {
    gradeList.stream().forEach((grade) -> {
        List<Student> students = stuList.stream().filter((stu) -> stu.getGradeId().equals(grade.getGradeId())).collect(toList());
        grade.setStudentList(students);
    });
    gradeList.stream().forEach(grade -> {
        System.out.println(grade.getGradeName() + "---");
        grade.getStudentList().stream().forEach(stu -> {
            System.out.println(stu.getStuName());
        });
    });
}

在这里插入图片描述

如果这篇【文章】有帮助到你💖,希望可以给我点个赞👍,创作不易,如果有对Java后端或者对spring, 分布式, 云原生感兴趣的朋友,请多多关注💖💖💖
👨‍🔧 个人主页 : 阿千弟

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/574839.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ruoyi-vue版本(十八)创建自己的项目,使用若依里面的技术,多数据源的实现

目录 1 创建自己的项目2 连接MySQL数据库(多数据源)2.1 若依实现多数据源2.1.1 主要思想2.2 第三方的依赖的实现1 创建自己的项目 1 创建一个空文件夹 2 idea 里面创建项目

GPU云服务器Stable Diffusion搭建保姆级教程

搭建Stable Diffusion最大门槛就是GPU。许多人的电脑配置太低&#xff0c;根本无法搭建。或者即使搭建出来&#xff0c;但是跑图太慢。说多了不通过&#xff0c;看下图。 选择服务器 我选择的是境外GPU服务器&#xff0c;windows版本&#xff08;73.59元&#xff09;。linux会…

SQL进阶教程读后总结与感想

1. 基本信息 SQL进阶教程 [日]MICK 人民邮电出版社,2017年11月出版&#xff0c;1版 1.1. 读薄率 书籍总字数455千字&#xff0c;笔记总字数25820字。 读薄率25820455000≈5.67% 1.2. 读厚方向 SQL权威指南&#xff08;第4版&#xff09; SQL解惑&#xff08;第2版&…

数据库数据量大了怎么办? 当然是分库分表,Sharding-JDBC了解一下?

Sharding-JDBC是一款基于JDBC规范的分布式数据库中间件&#xff0c;可以帮助Java应用轻松实现水平分库分表、读写分离等分布式数据库功能&#xff0c;并提供了方便易用、高可用、高性能的数据访问解决方案。本文将从以下几个方面进行详细介绍&#xff1a; Sharding-JDBC的原理…

chatgpt赋能python:Python录屏录音介绍

Python录屏录音介绍 在日常工作和学习中&#xff0c;录制屏幕和录制音频是一件很常见的事情。Python语言拥有强大的生态系统和第三方库支持&#xff0c;也可以轻松实现录制屏幕和录制音频的功能。本篇文章将介绍如何使用Python语言实现录屏录音功能。 Python录屏 录制屏幕可…

numpy包中的取余函数和取模函数numpy.remainder()numpy.mod()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 numpy包中的取余函数和取模函数 numpy.remainder() numpy.mod() 下列代码中np.remainder(m,2)输出的结果是&#xff1f; import numpy as np m np.array([4, 5, 6]) print("【显示】m &…

chatgpt赋能python:Python局部导入:提升代码效率与性能

Python 局部导入: 提升代码效率与性能 Python 是一种强大的编程语言&#xff0c;为开发者提供了许多工具和库&#xff0c;以简化开发过程。在项目中&#xff0c;对于复杂的代码文件&#xff0c;Python 的模块化设计可以让我们将代码分解为更小的组件&#xff0c;以便更好地维护…

chatgpt赋能python:Python的声音处理能力

#Python的声音处理能力 Python 是一种多功能编程语言&#xff0c;强有力的功能和库使它成为一种广泛使用的工具。Python也可以用于处理声音。在本文中&#xff0c;我们将深入了解Python的声音处理能力&#xff0c;并介绍使用Python处理声音的一些库和工具。 ##声音处理的步骤…

chatgpt赋能python:Python循环等待:什么是它?如何解决?

Python 循环等待&#xff1a;什么是它&#xff1f;如何解决&#xff1f; 在 Python 编程中&#xff0c;循环等待是一种常见的问题。它发生在代码一直等待某个操作的结果&#xff0c;而这个结果却永远不会到来。这种情况会导致程序停顿或挂起&#xff0c;从而影响整个应用程序。…

【 react项目 nginx配置服务 按钮点击可以进入页面,如果刷新页面或者通过链接进入页面会报错】

问题 报错内容&#xff1a; react项目部署之后&#xff0c;按钮点击可以进入页面&#xff0c;如果刷新页面或者通过链接进入页面会报错 分析问题得出结论是&#xff1a; react项目&#xff0c;nginx需要配置重定向 解决方案 nginx部分配置&#xff1a; location / {rewri…

ThingsBoard教程(五四):规则节点解析 Azure IoT Hub Node, RabbitMQ Node

Azure IoT Hub Node Since TB Version 2.5.3 配置 主题 - 获取有关IoT Hub主题的更多信息,请使用以下链接。主机名 - Azure IoT Hub主机名。设备ID - 来自Azure IoT Hub的设备ID。凭据 - Azure IoT Hub连接凭据。可以是共享访问签名或PEM格式证书。Azure IoT Hub支持不同的…

网络分级设计模型的三层架构:接入层、汇聚层、核心层到底有什么说法?

你好&#xff0c;这里是网络技术联盟站。 在现代网络中&#xff0c;为了满足不同规模和需求的组织和企业的通信需求&#xff0c;网络架构通常会划分为多个层次&#xff0c;其中包括接入层、汇聚层和核心层。这些层次在网络组网中扮演着不同的角色和功能。 本文将详细介绍接入层…

红队大杀器 Behinder_v4.0(冰蝎4.0)

Behinder_v4.0 GitHub : https://github.com/rebeyond/Behinder/releases/tag/Behinder_v4.0 修复 1.修复了在zimbra环境下的兼容性问题&#xff1b; 2.修复了在exchange环境下的兼容性问题&#xff1b; 3.修复了Linux环境下打开文件失败的问题&#xff1b; 4.修复了命令执行中…

chatgpt赋能python:Python中局部变量的输出到全局

Python 中局部变量的输出到全局 在 Python 中&#xff0c;变量的作用域分为全局和局部两种。全局变量可以在整个程序中使用&#xff0c;而局部变量只能在其定义的函数或代码块中使用。但是&#xff0c;有时候我们需要在局部作用域中定义的变量在全局作用域中使用&#xff0c;本…

chatgpt赋能python:Python在线聊天:如何用Python构建在线聊天应用

Python 在线聊天&#xff1a;如何用 Python 构建在线聊天应用 Python 是一种广泛使用的编程语言&#xff0c;它的易读性和易用性使得它成为编写各种类型应用程序的首选语言&#xff0c;其中包括构建在线聊天应用。如果您想构建一个在线聊天应用程序&#xff0c;那么 Python 是…

<SQL>《SQL命令(含例句)精心整理版(6)》

《SQL命令&#xff08;含例句&#xff09;精心整理版&#xff08;6&#xff09;》 18 DB2查询语句18.1 查询数据库大小18.2 查看表占表空间大小18.3 查看正在执行的语句18.4 db2expln 查看执行计划18.5 db2advis 查看优化建议 19 空值19.1 NULL19.2 TRIM 18 DB2查询语句 18.1 …

chatgpt赋能python:Python常用扩展包

Python常用扩展包 Python本身就已经是一门非常强大的编程语言了&#xff0c;但是为了适应不同的应用场景&#xff0c; Python社区开发了许多扩展包。这些包涵盖了从数据科学到Web开发的各个领域&#xff0c;让Python的应用范围更加广泛。 下面我们将介绍一些常用的Python扩展…

数据链路层:封装成帧

1.数据链路层&#xff1a;封装成帧 笔记来源&#xff1a; 湖科大教书匠&#xff1a;封装成帧 声明&#xff1a;该学习笔记来自湖科大教书匠&#xff0c;笔记仅做学习参考 封装成帧是指数据链路层给上层交付的协议数据单元添加帧头和帧尾使之成为帧 帧头和帧尾中包含重要的控制…

Vue Composition API之侦听器watch/watchEffect

目录 概述实例解析1.watch侦听器的用法基本使用深层侦听器即时回调监听器 2、watchEffect侦听器的用法3 停止侦听器 总结 概述 在日常的开发中&#xff0c;很多时候我们需要去对一些状态进行监听&#xff0c;比如当显示学生的成绩列表时&#xff0c;我们使用一个学生的学号stu…

【Python】循环语句 ④ ( for 循环 | for 循环基础语法 | 代码示例 - for 循环基础用法 | 代码示例2 - for 循环统计单词 )

文章目录 一、for 循环与 while 循环二、for 循环基础语法三、代码示例 - for 循环基础用法三、代码示例2 - for 循环统计单词 一、for 循环与 while 循环 for 循环 与 while 循环 可以 f实现 相同的 循环功能 , 二者有如下区别 : 循环条件不同 : while 循环 的 循环控制条件 …