文章目录

  • 官方文档
  • What is flatMap()?
  • Why flat a Stream?
  • Demo
    • 需求1:Find all books
    • 需求2:Order and LineItems
    • 需求3:Splits the line by spaces
    • 需求4: flatMap and primitive type

官方文档

https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html


What is flatMap()?

# Stream<String[]>
# Stream<Stream<String>>
# String[][][[1, 2],[3, 4],[5, 6]
]

它由一个 2 级 Stream 或一个二维数组组成 。

在 Java 8 中,我们可以使用 flatMap 将上述 2 级 Stream 转换为一级 Stream 或将 二维数组转换为 一维数组。

# Stream<String>
# String[][1, 2, 3, 4, 5, 6]

简言之, flatmap方法让你把一个流中的每个值都换成另一个流,然后把所有的流连接
起来成为一个流。

看一个简单的例子: 使用flatMap找出单词列表中各不相同的字符


Why flat a Stream?

处理包含多个级别的 Stream ,比如 Stream<String[]>Stream<List<LineItem>>Stream<Stream<String>> 想 将 2 级 Stream 扁平化为一级,如 Stream<String>Stream<LineItem>,这样就可以轻松地循环 Stream 并对其进行处理。

来看个简单的功能实现,以及常犯的一些错误。

需求: 有 {"a", "b"}, {"c", "d"}, {"e", "f"} 三个数组,要求输出 除去a之后的数据

 /*** filter out the a and print out all the characters*/private static void filterAndPrintCharacters() {String[][] array = new String[][]{{"a", "b"}, {"c", "d"}, {"e", "f"}};// convert  array to a streamStream<String[]> stream = Arrays.stream(array);// array to a stream [same result]Stream<String[]> array1 = Stream.of(array);log.info("==========错误的方式一===============");//    x is a String[], not String!List<String[]> result = stream.filter(x -> !x.equals("a")).collect(Collectors.toList());log.info(String.valueOf(result.size()));result.forEach(x -> log.info(Arrays.toString(x)));log.info("==========错误的方式二===============");List<String[]> result1 = Arrays.stream(array).filter(x -> {for (String s : x) {   // really?if (s.equals("a")) {return false;}}return true;}).collect(Collectors.toList());log.info(String.valueOf(result1.size()));result1.forEach(x -> log.info(Arrays.toString(x)));log.info("============正确的方式 flatMap=============");log.info("============先测试转换成一维数组=============");// [a, b, c, d, e, f]String[] objects = Arrays.stream(array).flatMap(Stream::of).toArray(String[]::new);Arrays.stream(objects).forEach(x -> log.info("|---->{}", x));log.info("============开始处理=============");List<String> collect = Arrays.stream(array).flatMap(Stream::of).filter(x -> !x.equals("a")).collect(Collectors.toList());collect.forEach(x -> log.info(x));log.info("============处理结束=============");}

我们先看看:

[错误的方式一]

filter(x -> !x.equals("a"))  // x 是数组 ,而非字符串

[错误的方式二]

x -> {for (String s : x) {   // really?if (s.equals("a")) {return false;}}return true;}   //  会把整个 [a, b] 过滤出去,而非我们想要过滤的 a

[正确的方式 ]

// flatMap 将二维数组转换成意味数组, 或者可以说是从 Stream<String[]> 转换成Stream<String>.String[][] array = new String[][]{{"a", "b"}, {"c", "d"}, {"e", "f"}};// Java 8String[] result = Stream.of(array)  // Stream<String[]>.flatMap(Stream::of)        // Stream<String>.toArray(String[]::new);    // [a, b, c, d, e, f]Arrays.stream(objects).forEach(x -> log.info("|---->{}", x));

接下来我们就可以很轻松地过滤出来 a了, 就得到了一下最终版本

 List<String> collect = Arrays.stream(array).flatMap(Stream::of).filter(x -> !x.equals("a")).collect(Collectors.toList());collect.forEach(x -> log.info(x));

【小结】

Stream#flatMap 可以将 2 levels Stream 转换成 1 level Stream.

Stream<String[]>      -> flatMap ->  Stream<String>
Stream<Set<String>>   -> flatMap ->   Stream<String>
Stream<List<String>>  -> flatMap ->   Stream<String>
Stream<List<Object>>  -> flatMap ->   Stream<Object>


Demo

需求1:Find all books

分析: 使用 stream 将List转换为对象流,每个对象都包含一组书籍,使用flatMap生成包含所有对象中所有书籍的流。过滤掉包含单词cloud的书,并收集一个Set以便于删除重复的书。

 private static void findAllBooks() {Developer o1 = new Developer();o1.setName("artisan");o1.addBook("Java 8 in Action");o1.addBook("Spring Boot in Action");o1.addBook("Effective Java (3nd Edition)");Developer o2 = new Developer();o2.setName("小工匠");o2.addBook("Spring Cloud");o2.addBook("Effective Java (3nd Edition)");List<Developer> list = new ArrayList<>();list.add(o1);list.add(o2);// 这....Set of Set...(Set<Set<String>>)咋处理?Set<Set<String>> collect = list.stream().map(x -> x.getBook()).collect(Collectors.toSet());// 方式一Set<String> result = list.stream().map(x -> x.getBook()).flatMap(Collection::stream).filter(x -> !x.toLowerCase().contains("cloud")).collect(Collectors.toSet());result.forEach(x -> log.info("element:------>{}", x));// 方式二// 当然了,map也可以不用,直接在flatMap中  x->x.getBook().stream()Set<String> result1 = list.stream().flatMap(x -> x.getBook().stream()).filter(x -> !x.toLowerCase().contains("cloud")).collect(Collectors.toSet());result1.forEach(x -> log.info("element:------>{}", x));}

当然了 有个内部类

@Data
static class Developer {private Integer id;private String name;private Set<String> book;public void addBook(String book) {if (this.book == null) {this.book = new HashSet<>();}this.book.add(book);}}

我们来来拆解下 【方式一】的处理过程如下


总结下每一步的输出:


需求2:Order and LineItems

订单是一个采购订单流,每个采购订单都包含一组行项目,然后使用flatMap生成一个包含所有订单中所有行项目的streamStream<LineItem>。此外,还添加了一个reduce操作来合计行项目的总金额 .

  private static void orderAndLineItems() {List<Order> orders = findAll();//  sum the order's total amount// 计算 order的total 总和BigDecimal reduce = orders.stream().map(Order::getTotal).reduce(BigDecimal.ZERO, BigDecimal::add);log.info(reduce.toString());// sum the line items' total amount// 计算 全部的 line的 price 总和// 方式一 先 map 再flatMapBigDecimal reduce1 = orders.stream().map(Order::getLineItems).flatMap(Collection::stream).map(line -> line.getTotal()).reduce(BigDecimal.ZERO, BigDecimal::add);// 方式二  直接 flatMapBigDecimal reduce2 = orders.stream().flatMap(order -> order.getLineItems().stream()).map(line -> line.getTotal()).reduce(BigDecimal.ZERO, BigDecimal::add);log.info(reduce1.toString());log.info(reduce2.toString());}/*** 模拟数据** @return*/private static List<Order> findAll() {LineItem item1 = new LineItem(1, "apple", 1, new BigDecimal("1.20"), new BigDecimal("1.20"));LineItem item2 = new LineItem(2, "orange", 2, new BigDecimal(".50"), new BigDecimal("1.00"));Order order1 = new Order(1, "A0000001", Arrays.asList(item1, item2), new BigDecimal("2.20"));LineItem item3 = new LineItem(3, "monitor BenQ", 5, new BigDecimal("99.00"), new BigDecimal("495.00"));LineItem item4 = new LineItem(4, "monitor LG", 10, new BigDecimal("120.00"), new BigDecimal("1200.00"));Order order2 = new Order(2, "A0000002", Arrays.asList(item3, item4), new BigDecimal("1695.00"));LineItem item5 = new LineItem(5, "One Plus 8T", 3, new BigDecimal("499.00"), new BigDecimal("1497.00"));Order order3 = new Order(3, "A0000003", Arrays.asList(item5), new BigDecimal("1497.00"));return Arrays.asList(order1, order2, order3);}@Data@AllArgsConstructor@NoArgsConstructorpublic static class Order {private Integer id;private String invoice;private List<LineItem> lineItems;private BigDecimal total;}@Data@AllArgsConstructor@NoArgsConstructorpublic static class LineItem {private Integer id;private String item;private Integer qty;private BigDecimal price;private BigDecimal total;}

输出


需求3:Splits the line by spaces

读取一个文本文件,计算单词数量

文本文件

hello world           Java
hello world Python
hello world Node JS
hello world Rust
hello world Flutter
  @SneakyThrowsprivate static void splitLinesBySpaces() {Path path = Paths.get("D:\\IdeaProjects\\boot2\\java8review\\src\\main\\java\\com\\artisan\\java8\\stream2\\a.txt");//  按行读取Stream<String> lines = Files.lines(path, StandardCharsets.UTF_8);//  stream of array...hard to process.// Stream<String[]> stream = lines.map(line -> line.split(" +"));// stream of stream of string....hmm...better flat to one level.// Stream<Stream<String>> words = lines.map(line -> Stream.of(line.split(" +")));// +、*、|、\等符号在正则表达示中有相应的不同意义// 加号可用于与字符匹配 1 次或多次。例如,'bre+' 匹配 bre 和 bree,但不匹配 br// " +" 匹配空格// result a stream of words, good! 方式一Stream<String> words = Files.lines(path, StandardCharsets.UTF_8).flatMap(line -> Stream.of(line.split(" +")));System.out.println(words.count());// 方式二long count = Files.lines(path, StandardCharsets.UTF_8).map(line -> line.split(" +")).flatMap(line -> Stream.of(line)).count();System.out.println(count);}

需求4: flatMap and primitive type

private static void flatMap2PrimitiveType() {int[] array = {1, 2, 3, 4, 5, 6};//Stream<int[]>Stream<int[]> streamArray = Stream.of(array);//Stream<int[]> -> flatMap -> IntStreamIntStream intStream = streamArray.flatMapToInt(x -> Arrays.stream(x));intStream.forEach(System.out::println);// flatMapToLong -> LongStreamlong[] array2 = {1, 2, 3, 4, 5, 6};Stream<long[]> longArray = Stream.of(array2);LongStream longStream = longArray.flatMapToLong(x -> Arrays.stream(x));System.out.println(longStream.count());}

Java8 - Streams flatMap()相关推荐

  1. 一点杂感 以及 java8 Streams API 与 C# Linq 简要对比分析

    写在前面的一点小吐槽.一点杂感 学 Haskell 学了一段时间之后,虽说拿他来写东西还是完全不行,但是看别的语言特性时,总是会带着一种"诶,这玩意在哪哪见过"的蜜汁既视感.且不说 ...

  2. java双层list扁平化,浅谈java8 stream flatMap流的扁平化操作

    概念: Steam 是Java8 提出的一个新概念,不是输入输出的 Stream 流,而是一种用函数式编程方式在集合类上进行复杂操作的工具.简而言之,是以内部迭代的方式处理集合数据的操作,内部迭代可以 ...

  3. Java8 Streams用法总结大全 之 Collector用法详解

    1.前言   在<Java8 Streams用法总结大全 之 Stream中的常见操作>中,我们已经学习了Stream中的常用操作,其中也提到了collect()的用法,当时只是通过入参C ...

  4. Java8 - Streams map()

    文章目录 概述 Case 1 : A List of Strings to Uppercase Case 2 : List of objects -> List of String Case 3 ...

  5. Java8 Stream flatMap使用

    一句话总结,类似于ES6中的多维数组展平 ⏹1. flatMap实践 实体类 class User {Integer id;String name;List<String> hobby;/ ...

  6. Java8 Streams Collectors 使用

    引言 在本文中,我们将向您展示如何使用 java8 流的 Collectors 对列表进行分组.计数.求和和排序. 1. 分组.计数和排序 按列表分组并显示列表的总数. List<String& ...

  7. java7 flatmap_Java 8 Streams FlatMap方法示例

    问题 我一直在查看即将发布的Java update,即:Java 8 or JDK 8.是的,我很不耐烦,有很多新东西,但是,有一些我不明白的东西,一些简单的代码: final Streamstrea ...

  8. java8 streams_使用Java 8 Streams进行编程对算法性能的影响

    java8 streams 多年来,使用Java进行多范式编程已经成为可能,它支持面向服务,面向对象和面向方面的编程的混合. 带有lambda和java.util.stream.Stream类的Jav ...

  9. java8 streams_Java 8 Streams API:对流进行分组和分区

    java8 streams 这篇文章展示了如何使用Streams API中可用的Collectors将具有groupingBy的流元素和具有partitioningBy的流元素进行groupingBy ...

最新文章

  1. 使用什么优化器_在机器学习项目中该如何选择优化器?
  2. iOS 获取当前月份的天数(转)
  3. Android官方开发文档Training系列课程中文版:分享简单数据之从其它APP接收简单数据
  4. csv格式清洗与转换python123,Python Pandas 清理错误格式数据
  5. javaSE----学习路线
  6. C++模板(关键字template,typename)介绍
  7. Keras搭建M2Det目标检测平台(转载)
  8. jupyter in vscode python语法不高亮 单元格语言格式CVE
  9. python拼接sql语句字符串 无效字符,Python拼接SQL字符串的方法
  10. Tomcat9下载以及安装
  11. win7 显示快捷方式扩展名 lnk
  12. cad导入mysql_CAD插入一个数据库
  13. 【解决方案】关于自动生成表hibernate_sequence的问题
  14. mybatis简单查询
  15. Codeforces936B. Sleepy Game
  16. 【GameMaker】分离文件路径、文件名、后缀
  17. 关于我AbortME
  18. 3d打印,机器人,计算机,3D打印的机器人将教孩子计算机编码!
  19. 大商创x支持mysql版本_大商创x全面升级2.0,匠心打造b2b2c多用户商城系统
  20. 法院不能既判决驳回诉讼请求又告知当事人另行起诉

热门文章

  1. “宝万之争”惊动三会 300亿资金如何越过监管边界
  2. Istio - 集成ELK - HPE_INVALID_METHOD, lumberjack protocol error
  3. 数据分析达人博客大全
  4. 计算机访学面试,国家公派访问学者面试经典问题总结
  5. linux 上下文切换时对用户task和内核task区别对待——针对fpu
  6. CEF3:用CEF3实现最简单的浏览器
  7. Go实战--Gorilla web toolkit使用之gorilla/context
  8. reacr富文本编辑器
  9. 杭州千岛湖|杭州千岛湖风景介绍|杭州千岛湖景点介绍
  10. Benchmark 第一篇 了解Benchmark