flatMap示例

flatMap示例flatMap示例什么是flatMap()回顾下面的数据结构,#Stream<String[]>#Stream<Stream<String>>#String[][][[1,2],[3,4],[5,6]]在Java8中,我们可以使用flatMap将上述数据结构转化为一下结构#Stream<String>#String[][1,2,3,4,5,6]为什么要平流处理包含超过一个级别的流,例

大家好,又见面了,我是你们的朋友全栈君。

flatMap示例

什么是flatMap()

回顾下面的数据结构,

# Stream<String[]>
# Stream<Stream<String>>
# String[][]

[
  [1, 2],
  [3, 4],
  [5, 6]
]

在Java8中,我们可以使用flatMap将上述数据结构转化为一下结构

# Stream<String>
# String[]

[1, 2, 3, 4, 5, 6]

为什么要平流

处理包含超过一个级别的流,例如Stream<String[]>、Stream<List>或者Stream<Stream>是具有挑战的。将两个级别的流划分为一个级别,例如Stream或者Stream,我们就可以很容易的处理它。

回顾下面这个示例,在使用流上使用flatMap前后对比

下面是一个二维数组,我们使用Arrays.stream或者Stream.of将他转化为流,然后生成String[]或Stream<String[]>的流

String[][] array = new String[][]{ 
   { 
   "a", "b"}, { 
   "c", "d"}, { 
   "e", "f"}};

  // array to a stream
  Stream<String[]> stream1 = Arrays.stream(array);

  // same result
  Stream<String[]> stream2 = Stream.of(array);

然后我们得到下面这样的数据结构

[
  [a, b],
  [c, d],
  [e, f]
] 

这里我们有一个要求,过滤到a,然后打印所有的字符

首先,我们直接使用Stream#filter,然而下面的程序不会打印任何内容。因为Stream#filter中的x是String[]类型,不是String类型,这条件将总是false,因此Stream流不会收集到任何内容。

String[][] array = new String[][]{ 
   { 
   "a", "b"}, { 
   "c", "d"}, { 
   "e", "f"}};

  // convert array to a stream
  Stream<String[]> stream1 = Arrays.stream(array);

  List<String[]> result = stream1
      .filter(x -> !x.equals("a"))      // x is a String[], not String!
      .collect(Collectors.toList());

  System.out.println(result.size());    // 0

  result.forEach(System.out::println);  // print nothing?

这次我们重构这个过滤方法,处理String[]类型

 String[][] array = new String[][]{ 
   { 
   "a", "b"}, { 
   "c", "d"}, { 
   "e", "f"}};

  // array to a stream
  Stream<String[]> stream1 = Arrays.stream(array);

  // x is a String[]
  List<String[]> result = stream1
          .filter(x -> { 
   
              for(String s : x){ 
         // really?
                  if(s.equals("a")){ 
   
                      return false;
                  }
              }
              return true;
          }).collect(Collectors.toList());

  // print array
  result.forEach(x -> System.out.println(Arrays.toString(x)));

输出

[c, d]
[e, f]

在上面例子中,Stream过滤到了整个[a, b],但是我们只想过滤到a

下面是最终版本,我们先组合数组,然后组合过滤器。在Java中,我们转化二维数组为一维数组,我们能够通过遍历二维数组,然后把所有元素放到一个新数组中。或者我们可以使用flatMap将二维数组展平为以为数组,从而将Stream<String[]>转化为Stream。

  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]

  for (String s : result) { 
   
      System.out.println(s);
  }

输出

a
b
c
d
e
f

现在我们可以很容易过滤出a,一下是最终版本

  String[][] array = new String[][]{ 
   { 
   "a", "b"}, { 
   "c", "d"}, { 
   "e", "f"}};

  List<String> collect = Stream.of(array)     // Stream<String[]>
          .flatMap(Stream::of)                // Stream<String>
          .filter(x -> !"a".equals(x))        // filter out the a
          .collect(Collectors.toList());      // return a List

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

输出

b
c
d
e
f

需要指出的是,多维数组展平为以为数组是有些复杂的一件事,容易产生误解和出错。我们可以使用Stream#flatMap展平二维流为一维流。

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

flatMap示例,查找所有书

下面示例使用stream()将List转化为对象流,每个对象都是书的集合,我们可以使用flatMap来生成一个流,它包含所有对象的所有数据

在最后,我们可以过滤出包含python的书,然后去掉重复的书籍

Developer.java

import java.util.HashSet;
import java.util.Set;

public class Developer { 
   

    private Integer id;
    private String name;
    private Set<String> book;

    //getters, setters, toString

    public void addBook(String book) { 
   
        if (this.book == null) { 
   
            this.book = new HashSet<>();
        }
        this.book.add(book);
    }
}
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class FlatMapExample1 { 
   

    public static void main(String[] args) { 
   

        Developer o1 = new Developer();
        o1.setName("mkyong");
        o1.addBook("Java 8 in Action");
        o1.addBook("Spring Boot in Action");
        o1.addBook("Effective Java (3nd Edition)");

        Developer o2 = new Developer();
        o2.setName("zilap");
        o2.addBook("Learning Python, 5th Edition");
        o2.addBook("Effective Java (3nd Edition)");

        List<Developer> list = new ArrayList<>();
        list.add(o1);
        list.add(o2);

        // hmm....Set of Set...how to process?
        /*Set<Set<String>> collect = list.stream() .map(x -> x.getBook()) .collect(Collectors.toSet());*/

        Set<String> collect =
                list.stream()
                        .map(x -> x.getBook())                              // Stream<Set<String>>
                        .flatMap(x -> x.stream())                           // Stream<String>
                        .filter(x -> !x.toLowerCase().contains("python"))   // filter python book
                        .collect(Collectors.toSet());                       // remove duplicated

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

    }

}

输出

Spring Boot in Action
Effective Java (3nd Edition)
Java 8 in Action

我们还可以进行简化

 Set<String> collect2 = list.stream()
                    //.map(x -> x.getBook())
                    .flatMap(x -> x.getBook().stream())                 // Stream<String>
                    .filter(x -> !x.toLowerCase().contains("python"))   // filter python book
                    .collect(Collectors.toSet());

flatMap示例——order和lineItems

orders是采购订单的一个流,每个采购订单包含订单项的集合,我们可以使用flatMap生成一个Stream流,这个流包含订单中所有的订单项。此外我们使用reduce操作对订单项的金额进行求和。

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;

public class FlatMapExample2 { 
   

    public static void main(String[] args) { 
   

        List<Order> orders = findAll();

        /* Stream<List<LineItem>> listStream = orders.stream() .map(order -> order.getLineItems()); Stream<LineItem> lineItemStream = orders.stream() .flatMap(order -> order.getLineItems().stream()); */

        // sum the line items' total amount
        BigDecimal sumOfLineItems = orders.stream()
                .flatMap(order -> order.getLineItems().stream())    // Stream<LineItem>
                .map(line -> line.getTotal())                       // Stream<BigDecimal>
                .reduce(BigDecimal.ZERO, BigDecimal::add);          // reduce to sum all

        // sum the order's total amount
        BigDecimal sumOfOrder = orders.stream()
                .map(order -> order.getTotal())                     // Stream<BigDecimal>
                .reduce(BigDecimal.ZERO, BigDecimal::add);          // reduce to sum all

        System.out.println(sumOfLineItems);                         // 3194.20
        System.out.println(sumOfOrder);                             // 3194.20

        if (!sumOfOrder.equals(sumOfLineItems)) { 
   
            System.out.println("The sumOfOrder is not equals to sumOfLineItems!");
        }

    }

    // create dummy records
    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);

    }
}

Order.java

public class Order { 
   

    private Integer id;
    private String invoice;
    private List<LineItem> lineItems;
    private BigDecimal total;

    // getter, setters, constructor
}

LineItem.java

public class LineItem { 
   

    private Integer id;
    private String item;
    private Integer qty;
    private BigDecimal price;
    private BigDecimal total;

    // getter, setters, constructor
}

输出

3194.20
3194.20

flatMap示例——使用空格分割线

读取text文件,使用空格分隔行,展示所有的单词数

F:\\test.txt

hello world Java
hello world Python
hello world Node JS
hello world Rust
hello world Flutter
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;

public class FlatMapExample3 { 
   

    public static void main(String[] args) throws IOException { 
   

        Path path = Paths.get("C:\\test\\test.txt");

        // read file into a stream of lines
        Stream<String> lines = Files.lines(path, StandardCharsets.UTF_8);

        // stream of array...hard to process.
        // Stream<String[]> words = 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(" ")));

        // result a stream of words, good!
        Stream<String> words = lines.flatMap(line -> Stream.of(line.split(" ")));

        // count the number of words.
        long noOfWords = words.count();

        System.out.println(noOfWords);  // 16
    }
}

输出

16

flatMap和基本数据类型

对于基本数据类型,像int、long、double等,Java8也提供了相关的flatMapTo{primative type}去展平基本数据类型的流,原理是相同的。

flagMapToInt -> IntStream

import java.util.Arrays;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class FlatMapExample4 { 
   

    public static void main(String[] args) { 
   

        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(x -> System.out.println(x));
    }
}

输出

1
2
3
4
5
6

flatMapToLong -> LongStream

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

  Stream<long[]> longArray = Stream.of(array);

  LongStream longStream = longArray.flatMapToLong(x -> Arrays.stream(x));

  System.out.println(longStream.count());
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/137842.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • vuex的五大核心_vue的核心是什么

    vuex的五大核心_vue的核心是什么Vuex的核心概念Vuex有5个核心概念,分别是State,Getters,mutations,Actions,Modules。StateVuex使用单一状态树,也就是说,用一个对象包含了所有应

    2022年7月31日
    4
  • spss 卡方检验,Logistic回归方法「建议收藏」

    spss 卡方检验,Logistic回归方法「建议收藏」案例:新生儿体重较低影响因素1:影响因素分析,求出哪些自变量对因变量发生概率有影响,并计算各自变量对因变量的比数比;2:作为判别分析方法,来估计各种自变量组合条件下因变量各类别的发生概率,从而对结局进行预测,该模型在结果上等价于判别分析;说明:低出生体重标准:新生儿体重<2500克结果变量为是否娩出低出生体重儿,变量名为low,1=低出生体重,0=非低出生体重;考虑的影响因素…

    2022年5月16日
    43
  • JMM概述_jmi名词解释

    JMM概述_jmi名词解释简介什么是JMM内存模型可以理解为在特定的操作协议下,对特定的内存或者高速缓存进行读写访问的过程抽象描述,不同架构下的物理机拥有不一样的内存模型,Java虚拟机是一个实现了跨平台的虚拟系统,因此它也有自己的内存模型,即Java内存模型(JavaMemoryModel,JMM)。因此它不是对物理内存的规范,而是在虚拟机基础上进行的规范从而实现平台一致性,以达到Java程序能够“一次编写,到处运行

    2022年9月5日
    4
  • 2021 idea 激活码(JetBrains全家桶)

    (2021 idea 激活码)这是一篇idea技术相关文章,由全栈君为大家提供,主要知识点是关于2021JetBrains全家桶永久激活码的内容IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.htmlMLZPB5EL5Q-eyJsaWN…

    2022年3月21日
    80
  • 程序员笑话「建议收藏」

    程序员笑话「建议收藏」十行代码九个警告八个错误竟然敢说七日精通六天学会五湖四海也不见如此三心二意之项目经理简直一等下流。

    2022年10月22日
    1
  • 2022年化工自动化控制仪表考试模拟100题及答案详解_化工仪表及自动化答案

    2022年化工自动化控制仪表考试模拟100题及答案详解_化工仪表及自动化答案题库来源:安全生产模拟考试一点通公众号小程序2022化工自动化控制仪表上岗证题目系化工自动化控制仪表培训试题上机考试练习题!2022年化工自动化控制仪表考试模拟100题及答案根据化工自动化控制仪表考试大纲。化工自动化控制仪表判断题通过安全生产模拟考试一点通准确把握考试要点。1、【单选题】“硬水”是指水中所溶的()离子较多的水。(B)A、钙和钠B、钙和镁C、镁和铁2、【单选题】串级控制系统具有一定的自适应能力可用于负荷和操作条件有较大变化的场合,是由于增加了()。(B…

    2022年9月7日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号