Java8 - Streams flatMap()

article/2025/10/18 19:11:02

文章目录

  • 官方文档
  • 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());}

在这里插入图片描述


http://chatgpt.dhexx.cn/article/J9dJ08iT.shtml

相关文章

JAVA8 中的flatmap

构建对象 class User{private String addr } 将多个User集合中的addr按照;分割合并成一个字符串list List<User> uList Lists.newArrayList();User u1 new User();u1.setAddr("a1;a2;a3;a4;a5");User u2 new User();u2.setAddr("b1;b2;b3;b4;b5&qu…

Unity resource style/Theme.AppCompat.Dialog (aka xxx:style/Theme.AppCompat.Dialog) not found

关于Unity 打包报错"resource style/Theme.AppCompat.Dialog (aka com.game.chipsmerge:style/Theme.AppCompat.Dialog) not found."的问题 解决方法: 在mainTemplate文件中添加依赖: implementation ‘com.android.support:appcompat-v7:28.0.0’ 或者自己去下载其…

android最新v7包下载,support v7 appcompat.jar包下载

android support v7 appcompat.jar包是一款非常实用的jar文件,是android开发中必备的一份文件,能够在低版本Android平台上开发一个应用程序,兼容性极强。感兴趣的朋友欢迎前来IT猫扑下载体验吧! android support v7 appcompat.jar包介绍 android-support-v7-appcompat.jar包…

解决 appcompat 1.1.0 导致 webview crash 的问题

Android SDK 太不让人省心了&#xff0c;正式版本居然也埋雷。 前段时间把 support 升级到了 androidx&#xff0c;appcompat 自动升级了新版本 androidx.appcompat:appcompat:1.1.0。 简单回归了下功能就发上线了&#xff0c;结果在在 5.1 的系统上发生了大规模的 crash&…

从AppCompat切换到MaterialComponents一些主题属性介绍

文章目录 前言主题属性颜色排版字体形状小部件ButtonsText FieldsCardsBottom Navigation 后话 前言 絮叨两句&#xff0c;感觉Component这个库有点傲娇&#xff0c;我碰到一个情景&#xff0c;使用Button&#xff0c;设置了background属性&#xff0c;当使用样式是AppCompat时…

Gradle编译问题(appcompat和material相关)

在使用Android Studio编译项目时&#xff0c;发现的编译问题。已解决&#xff0c;在此记录一下 问题1 Cant determine type for tag <macro name"m3_comp_bottom_app_bar_container_color">?attr/colorSurface</macro> 原因是androidx.appcompat:app…

Android报错之You need to use a Theme.AppCompat theme (or descendant) with this activity.

[TOC](Android报错之You need to use a Theme.AppCompat theme (or descendant) with this activity.) 一、报错如下 原因为&#xff1a;Activty继承自android.support.v7.app.AppCompatActivty,而不是android.app.Activty。 二、解决方法 看一下提示&#xff0c;就是要用Th…

appcompat_v7项目说明

一、appcompat_v7项目说明 今天来说一下appcompat_v7项目的问题&#xff0c;使用eclipse创建Android项目时&#xff0c;发现project列表中会多创建出一个appcompat_v7项目&#xff0c;这是我搭建最新的Android开发环境创建第一个Android测试项目后发现的&#xff0c;我在创建An…

Android Studio报错Could not find any version that matches com.android.support:appcompat-v7:33.+.

今天用AndroidStudio新建了一个项目&#xff0c;没想到新建项目就爆红了 而且Java代码有标红&#xff0c;cannot reslove symbol"v7" 解决方案&#xff1a; 1.打开build.gradle文件&#xff0c;找到dependencies下 implementation com.android.support:appcompat-…

Android关于Theme.AppCompat相关问题的深入分析

先来看这样一个错误&#xff1a; No resource found that matches the given name style/Theme.AppCompat.Light 对于这个错误&#xff0c;相信大部分Android开发者都遇到过&#xff0c;可能很多朋友通过百度或者Google已经解决了这个问题&#xff0c;但是网上大部分都只给出…

细说 AppCompat 主题引发的坑:You need to use a Theme.AppCompat theme with this activity!

一般来说按照文档的建议去做&#xff0c;出现问题的概率很低。但很多人的情况不同&#xff0c;每每会发生意外状况&#xff0c;就比如这次没有使用 AppCompat 主题引发的坑&#xff01; AppCompat 框架作为 Jetpack 集合的基石&#xff0c;非常重要。Android Studio 上创建的默…

Android Jetpack基础组件之AppCompat

1.简介 相比苹果封闭的IOS系统&#xff0c;Android系统的开放性带来了很多的优势。与此同时&#xff0c;也带来了严重的碎片化问题&#xff0c;包括硬件的碎片化和软件碎片化。这里&#xff0c;我们主要说的是软件方面。各Android设备厂商&#xff0c;受限于成本和技术原因&am…

AppCompat发布两年了,还没了解?

近日随笔 近期疫情日渐严峻&#xff0c;大家多多保重&#xff0c;出门记得戴口罩。希望河北&#xff0c;黑龙江能尽早控制住好局面迎来拐点&#xff0c;全国人民过个好年。 为了能够让低版本的Android系统能够运行新特性&#xff0c;AppCompat框架自Support时代就已推出。但随着…

AppCompat (AppCompatActivity) Jetpack

进入AppCompat章节后&#xff0c;我们发现它又被分为了4个部分&#xff0c;这4个部分被称为“key class”&#xff0c;也就是重点类&#xff0c;它们分别是&#xff1a; ActionBar&#xff1a;提供Actionbar用户界面模式的实现&#xff1b;AppCompatActivity&#xff1a;添加可…

【5】SpringBoot日志存储路径和设置日志格式

SpringBoot日志存储路径和设置日志格式 文章目录 SpringBoot日志存储路径和设置日志格式01、分析02、解决方案03、Springboot的日志的解决方案&#xff08;掌握&#xff09;04、查看springboot的日志的整个体系05、slf4j、logback和log4j三者的关系06、springboot的日志搭配07、…

nginx日志格式分析及修改

修改nginx日志打印格式 一. 打开终端&#xff0c;登录服务器并输入服务器密码 //ssh 用户名服务器ip ssh root192.168.0.132二. 切换到nginx目录 cd /var/log/nginx/三. 查看nginx日志 tail -f access.log日志说明&#xff1a; //默认的nginx标准日志格式 192.168.10.251 …

Nginx配置-日志格式配置

Nginx配置-日志格式配置 一、默认的日志格式二、我使用的日志格式三、参数四、测试效果 五一上线了一个小的预约程序&#xff0c;配置通过Nginx进行访问入口&#xff0c;默认的日志是没有请求时间的&#xff0c;因此需要配置一下&#xff0c;将每一次的请求的访问响应时间记录出…

Apache日志记录格式-LogFormat配置详解

Apache日志记录格式-LogFormat配置详解 前言 定制日志文件的格式涉及到三个指令&#xff0c;即LogFormat指令和CustomLog指令和ErrorLog指令&#xff0c;默认httpd.conf文件提供了关于这两个指令的几个示例。 格式设置 LogFormat LogFormat指令定义格式并为格式指定一个名…

springboot项目中日志使用----自定义日志格式(可直接使用)

springboot项目中日志使用 1、为什么加日志 1.1 日志是什么&#xff1f; 日志文件提供精确的系统记录&#xff0c;根据日志最终定位到错误详情和根源。日志的特点是&#xff0c;它描述一些离散的&#xff08;不连续的&#xff09;事件。例如&#xff1a;应用通过一个滚动的文…

python设置日志格式

# %(asctime)s 字符串形式的当前时间。 # %(levelname)s 文本形式的日志级别 # %(name)s Logger的名字 # %(filename)s 调用日志输出函数的模块的文件名 # %(funcName)s 调用日志输出函数的函数名 # %(lineno)d 调用日志输出函数的语句所在的代码行 # %(message)…