Java 业务开发常见错误 100 例
朱晔
贝壳金服资深架构师
52944 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 48 讲
代码篇 (23讲)
Java 业务开发常见错误 100 例
15
15
1.0x
00:00/00:00
登录|注册

32 | 加餐2:带你吃透课程中Java 8的那些重要知识点(二)

根据下单年月+用户名两次分组统计订单ID列表
根据下单年月分组统计订单ID列表
统计用户下的金额最高的订单
统计被采购最多的商品
按照用户名分组,统计商品采购数量
按照用户名分组,统计订单总金额
按照用户名分组,统计下单数量
partitionBy
groupBy
对结果求平均值
对商品数量求和
将对象快速转换为Map
获得指定类型的集合
收集为Set去重
字符串拼接
通过IntStream或DoubleStream构造基本类型的流
通过Stream.generate方法从外部传入一个提供元素的Supplier来构造无限流,然后使用limit限制流元素个数
通过Stream.iterate方法使用迭代的方式构造一个无限流,然后使用limit限制流元素个数
通过Stream.of方法直接传入多个元素构成一个流
通过stream方法把List或数组转换为流
自定义收集器
观察数据变化
Collectors类
collect
skip & limit
distinct
sorted
flatMap
map
filter
创建流
思考与讨论
Stream API
带你吃透课程中Java 8的那些重要知识点

该思维导图由 AI 生成,仅供参考

你好,我是朱晔。
上一讲的几个例子中,其实都涉及了 Stream API 的最基本使用方法。今天,我会与你详细介绍复杂、功能强大的 Stream API。
Stream 流式操作,用于对集合进行投影、转换、过滤、排序等,更进一步地,这些操作能链式串联在一起使用,类似于 SQL 语句,可以大大简化代码。可以说,Stream 操作是 Java 8 中最重要的内容,也是这个课程大部分代码都会用到的操作。
我先说明下,有些案例可能不太好理解,建议你对着代码逐一到源码中查看 Stream 操作的方法定义,以及 JDK 中的代码注释。

Stream 操作详解

为了方便你理解 Stream 的各种操作,以及后面的案例,我先把这节课涉及的 Stream 操作汇总到了一张图中。你可以先熟悉一下。
在接下来的讲述中,我会围绕订单场景,给出如何使用 Stream 的各种 API 完成订单的统计、搜索、查询等功能,和你一起学习 Stream 流式操作的各种方法。你可以结合代码中的注释理解案例,也可以自己运行源码观察输出。
我们先定义一个订单类、一个订单商品类和一个顾客类,用作后续 Demo 代码的数据结构:
//订单类
@Data
public class Order {
private Long id;
private Long customerId;//顾客ID
private String customerName;//顾客姓名
private List<OrderItem> orderItemList;//订单商品明细
private Double totalPrice;//总价格
private LocalDateTime placedAt;//下单时间
}
//订单商品类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class OrderItem {
private Long productId;//商品ID
private String productName;//商品名称
private Double productPrice;//商品价格
private Integer productQuantity;//商品数量
}
//顾客类
@Data
@AllArgsConstructor
public class Customer {
private Long id;
private String name;//顾客姓名
}
在这里,我们有一个 orders 字段保存了一些模拟数据,类型是 List。这里,我就不贴出生成模拟数据的代码了。这不会影响你理解后面的代码,你也可以自己下载源码阅读。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

Java 8中Stream API的复杂、功能强大的操作方法。Stream流式操作可以对集合进行投影、转换、过滤、排序等操作,并且这些操作可以链式串联在一起使用,类似于SQL语句,能够大大简化代码。文章围绕订单场景,给出了如何使用Stream的各种API完成订单的统计、搜索、查询等功能。作者首先介绍了创建流的五种方式,然后详细讲解了filter、map、flatMap、sorted、distinct、skip和limit等操作的使用方法,并给出了相应的示例代码。通过这些示例,读者可以快速了解Stream API的强大功能和灵活运用。文章通过清晰的示例代码和详细的讲解,使读者能够快速掌握Java 8中Stream API的重要知识点,为实际项目开发提供了有力的参考。Collectors类提供了丰富的现成收集器,如collect、toSet、toMap等,同时也介绍了groupBy和partitionBy等特殊收集器的使用方法。通过大量案例的介绍,读者可以深入理解Stream API的灵活性和强大功能。最后,作者提出了两个思考问题,引发读者对Stream API的进一步思考和探索。整体而言,本文通过丰富的案例和清晰的讲解,全面介绍了Java 8中Stream API的使用方法和技巧,对读者快速掌握Stream API具有重要参考价值。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Java 业务开发常见错误 100 例》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(27)

  • 最新
  • 精选
  • 汝林外史
    置顶
    private List<Map> getNoRoomList(List<Map> inspectRooms, List<Map> items) { boolean flag = false; List<Map> noInspectRoom = new ArrayList<>(); for (Map item: items) { for (Map inspectRoom: inspectRooms) { if (inspectRoom.get("project").equals(item.get("checkItem"))) { flag = true; break; } } if (!flag) { noInspectRoom.add(item); }else { flag = false; } } return noInspectRoom; } 我直接贴我写的处理代码吧,应该可以理解我的想法,这测试用例还真不好写。

    作者回复: private static List<Map> getNoRoomList(List<Map> inspectRooms, List<Map> items) { return items.stream().filter(item->inspectRooms.stream().noneMatch(inspectRoom->inspectRoom.get("project").equals(item.get("checkItem")))) .collect(Collectors.toList()); }

    2020-03-20
    4
  • 海拉鲁
    置顶
    为了写作业又去翻了《Java 8 实战》,测试终于通过了 public class MostPopularCollector implements Collector<Object, // 收集String流 Map<Object, Integer>, // 累加器是一个Map,key为字符,value为出现的次数 Optional> // 返回的是出现次数最多的字符 { /** * 返回一个在调用时创建的累加器 * @return */ public Supplier<Map<Object, Integer>> supplier() { return () -> new HashMap<>(); } /** * 定义收集流中数据逻辑 * @return */ public BiConsumer<Map<Object, Integer>, Object> accumulator() { return (Map<Object, Integer> acc, Object chart) -> acc.compute(chart, (key, val) -> val == null ? 1 : val + 1); // 如果当前字符未统计则统计为1,否则+1 } /** * 处理并行操作,其实就是将两个map合成一个,把value加起来 * @return */ public BinaryOperator<Map<Object, Integer>> combiner() { return (Map<Object, Integer> m1, Map<Object, Integer> m2) -> { Map<Object, Integer> all = new HashMap<>(m1); m2.forEach((chart, count) -> all.merge(chart, count, Integer::sum)); return all; }; } public Function<Map<Object, Integer>, Optional> finisher() { return (Map<Object, Integer> acc) -> Optional.ofNullable(acc.entrySet() .stream() .max(Map.Entry.comparingByValue()) .get().getKey()); } public Set<Characteristics> characteristics() { return Collections.unmodifiableSet(EnumSet.of(Characteristics.CONCURRENT)); } }

    作者回复: 👍🏻

    2020-03-17
    2
    12
  • Wiggle Wiggle
    置顶
    Stream API 有个 peek 方法可以接收一个 consumer 来打印数据,可以接在任意 transformation 操作后面查看数据

    作者回复: 是的,这是一种方法,此外IDEA已经增加了非常方便的Stream调试功能,可以参考https://www.jetbrains.com/help/idea/analyze-java-stream-operations.html

    2020-03-17
    8
  • Darren
    以前真没有特意去关注收集器,看了做了,参考了2片文章: https://www.cnblogs.com/yw0219/p/9589124.html https://my.oschina.net/piorcn/blog/424375 最终搞定,请老师指点 https://github.com/y645194203/geektime-java-100/blob/master/MostPopularCollector.java

    作者回复: 非常好

    2020-03-17
    8
  • pedro
    我目前想到的数据观察的方式比较原始,一种是通过log打印,一种是debug。但我肯定这都不是啥好办法,希望老师告知解放生产力的方法。

    作者回复: IDEA已经增加了非常方便的Stream调试功能,可以参考https://www.jetbrains.com/help/idea/analyze-java-stream-operations.html

    2020-03-17
    6
  • Demon.Lee
    每天晚上回去敲一点,花了好几个晚上,终于把这两节中的所有代码运行了一遍,只不过似懂非懂,还要继续练习。已经开始在工作中运用一些简单的了,读完这篇文章可能只需要20分钟,但把所有代码都练习一遍,就不是20分钟的事了,要持续学习才行。💪🏽

    作者回复: 还是需要自己想案例实际写一下代码

    2020-04-24
    2
    4
  • 汝林外史
    List<Map> l1,List<Map> l2,两个list,l1中有四个map,其中有key分别为1、2、3、4的四个字段,l2有两个map,其中有key分别为1,2的l1中一样的字段,怎么筛选最终得到一个list,只有key为3、4对应的两个map?写的比较乱,还请老师见谅,我想了下没想出来,最后for循环做的。

    作者回复: 把测试用例帖一下,不太明白l1和l2是啥。。。

    2020-03-19
    2
  • insight
    //各种转换,后面注释代表了输出结果 System.out.println(IntStream.of(1, 2).toArray().getClass()); //class [I System.out.println(Stream.of(1, 2).mapToInt(Integer::intValue).toArray().getClass()); //class [I System.out.println(IntStream.of(1, 2).boxed().toArray().getClass()); //class [Ljava.lang.Object; System.out.println(IntStream.of(1, 2).asDoubleStream().toArray().getClass()); //class [D System.out.println(IntStream.of(1, 2).asLongStream().toArray().getClass()); //class [J 老师,这一段代码的输出结果为什么是这样的呀?没看懂,求指教!

    作者回复: 看一下toArray的返回类型对比一下输出就知道了

    2020-03-18
    2
  • 鲁鸣
    在实际中,发现distinct需要根据元素类型的属性进行判断,这个时候就需要用别的方式了

    作者回复: https://stackoverflow.com/questions/23699371/java-8-distinct-by-property/27872852#27872852

    2020-09-27
    1
  • 大胖子呀、
    工作中遇到一个需求,计算运费:先从运费集合中找出同一个客户的数据,然后类似于累加数量(还有很多其他的逻辑)计算出运费(因为相同的客户数量超过一定数值会有优惠)。最后把计算出来的运费数据插入到数据库里。 我的做法是:以第一条数据的客户为基准,循环找出相同客户的数据,保存到一个新的集合中,同时从原数据集合里移除这条数据,最后计算出新集合里的运费就可以了。 感觉这种需求的话,好像就没办法用老师介绍的流方法来遍历计算了,因为不能删除数据,不知道我认为的是不是对的。 另外就我的实现来说,会不会出现问题?有没有更好的解决方案?

    作者回复: 按照客户直接进行分组聚合不是更简单

    2020-05-20
    3
    1
收起评论
显示
设置
留言
27
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部