Java8 - Streams flatMap()

这篇具有很好参考价值的文章主要介绍了Java8 - Streams flatMap()。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


java stream flatmap,【Java - Java 8】,java,flatMap,Stream

官方文档

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

java stream flatmap,【Java - Java 8】,java,flatMap,Stream


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找出单词列表中各不相同的字符
java stream flatmap,【Java - Java 8】,java,flatMap,Stream


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 stream
        Stream<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 8
  String[] 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>

java stream flatmap,【Java - Java 8】,java,flatMap,Stream


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);
     }

 }

我们来来拆解下 【方式一】的处理过程如下
java stream flatmap,【Java - Java 8】,java,flatMap,Stream
java stream flatmap,【Java - Java 8】,java,flatMap,Stream

java stream flatmap,【Java - Java 8】,java,flatMap,Stream
java stream flatmap,【Java - Java 8】,java,flatMap,Stream

java stream flatmap,【Java - Java 8】,java,flatMap,Stream

java stream flatmap,【Java - Java 8】,java,flatMap,Stream

总结下每一步的输出:

java stream flatmap,【Java - Java 8】,java,flatMap,Stream


需求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 再flatMap
        BigDecimal reduce1 = orders.stream()
                .map(Order::getLineItems)
                .flatMap(Collection::stream)
                .map(line -> line.getTotal())
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        
        // 方式二  直接 flatMap
        BigDecimal 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
    @NoArgsConstructor
    public static class Order {
        private Integer id;
        private String invoice;
        private List<LineItem> lineItems;
        private BigDecimal total;
    }


    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class LineItem {
        private Integer id;
        private String item;
        private Integer qty;
        private BigDecimal price;
        private BigDecimal total;
    }
    

输出

java stream flatmap,【Java - Java 8】,java,flatMap,Stream


需求3:Splits the line by spaces

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

文本文件

hello world           Java
hello world Python
hello world Node JS
hello world Rust
hello world Flutter
  @SneakyThrows
    private 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

java stream flatmap,【Java - Java 8】,java,flatMap,Stream

private static void flatMap2PrimitiveType() {

        int[] array = {1, 2, 3, 4, 5, 6};

        //Stream<int[]>
        Stream<int[]> streamArray = Stream.of(array);

        //Stream<int[]> -> flatMap -> IntStream
        IntStream intStream = streamArray.flatMapToInt(x -> Arrays.stream(x));

        intStream.forEach(System.out::println);


        // flatMapToLong -> LongStream
        long[] 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());

    }

java stream flatmap,【Java - Java 8】,java,flatMap,Stream文章来源地址https://www.toymoban.com/news/detail-771863.html

到了这里,关于Java8 - Streams flatMap()的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java8 函数式编程stream流

    Java 8 中新增的特性旨在帮助程序员写出更好的代码,其中对核心类库的改进是很关键的一部分,也是本章的主要内容。对核心类库的改进主要包括集合类的 API 和新引入的流(Stream),流使程序员得以站在更高的抽象层次上对集合进行操作。下面将介绍stream流的用法。 ​场景

    2024年02月15日
    浏览(37)
  • Java8中Stream详细用法大全

    Java 8 是一个非常成功的版本,这个版本新增的Stream,配合同版本出现的Lambda ,给我们操作集合(Collection)提供了极大的便利。Stream流是JDK8新增的成员,允许以声明性方式处理数据集合,可以把Stream流看作是遍历数据集合的一个高级迭代器。Stream 是 Java8 中处理集合的关键抽

    2023年04月08日
    浏览(79)
  • Java8的Stream流的学习

    Stream可以由数组或集合创建,对流的操作分为两种: 中间操作,每次返回一个新的流,可以有多个。 终端操作,每个流只能进行一次终端操作,终端操作结束后流无法再次使用。终端操作会产生一个新的集合或值。 stream和parallelStream的简单区分: stream是顺序流,由主线程按

    2024年02月07日
    浏览(42)
  • Java8 Stream流处理树形结构数据

    参考资料 Java8新特性-使用Stream流递归实现遍历树形结构 ID为2,6,11的Menu 是 ID为1的Menu子节点 ID为3,4,5的Menu 是 ID为2的Menu子节点 💥 注意 是下面这种写法的一种更简单的写法

    2024年02月01日
    浏览(54)
  • Java8 Stream 之groupingBy 分组讲解

    本文主要讲解:Java 8 Stream之Collectors.groupingBy()分组示例 Collectors.groupingBy() 分组之常见用法 功能代码: /**      * 使用java8 stream groupingBy操作,按城市分组list      */     public void groupingByCity() {         MapString, ListEmployee map = employees.stream().collect(Collectors.groupingBy(Employee::getCi

    2024年02月13日
    浏览(46)
  • Java8 Stream流常见操作--持续更新中

    Java8 Stream流是一种处理数据集合的方式,它可以对集合进行一系列的操作,包括过滤、映射、排序等,从而实现对集合中元素的处理和转换。Stream流是一种惰性求值的方式,只有在需要返回结果时才会执行实际操作,这种方式可以提高程序的性能。 延迟执行:Stream流中的操作

    2024年02月11日
    浏览(62)
  • Java8的stream之groupingBy()分组排序

    groupingBy()是Stream API中最强大的收集器Collector之一,提供与SQL的GROUP BY子句类似的功能。 需要指定一个属性才能使用,通过该属性执行分组。我们通过提供功能接口的实现来实现这一点 - 通常通过传递lambda表达式。 TreeMap默认按照key升序排序,collectPlan.descendingMap()可以进行降序排

    2024年02月12日
    浏览(39)
  • java8 Stream流常用方法(持续更新中...)

    操作对象 模拟数据 操作 打印结果 打印结果 注意:异常自己捕捉,就比如这里String转Intger就可能出现NumberFormatException异常 打印结果 打印结果 断点查看 打印结果 断点查看 持续更新中…

    2024年04月28日
    浏览(65)
  • java中flatMap用法

        java中map是把集合每个元素重新映射,元素个数不变,但是元素值发生了变化。而flatMap从字面上来说是压平这个映射,实际作用就是将每个元素进行一个一对多的拆分,细分成更小的单元,返回一个新的Stream流,新的流元素个数增加。     java官方给出的示例如下:    

    2024年02月02日
    浏览(51)
  • Java8-使用stream.sorted()对List排序

    1.流的定义 Stream 中文称为 “流”,通过将集合转换为这么一种叫做 “流” 的元素序列,通过声明性方式,能够对集合中的每个元素进行一系列并行或串行的操作! 如果流中的元素的类实现了 Comparable 接口,即有自己的排序规则,那么可以直接调用 sorted() 方法对元素进行排

    2024年02月16日
    浏览(57)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包