java8流(Stream API)使用详解:筛选、切片、映射、查找、匹配和归约等流操作

本文主要是介绍java8流(Stream API)使用详解:筛选、切片、映射、查找、匹配和归约等流操作,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

上一篇中介绍了集合操作的痛点并发现集合操作的这些痛点在java8流API面前基本都不是事,随后引出了流的定义并介绍了流操作的类型、特征,以及使用流的基本步骤,本篇将逐一介绍Stream Api中各种流操作及一些特殊流的使用。

用谓词筛选

关于筛选在该系列前面文章中已经出现多次了,这里再次列举如下,以求完整。
如下代码筛选出素食菜单:

 
  1. List<Dish> vegetarianMenu = menu.stream()
  2. .filter(Dish::isVegetarian)//方法引用检查是否为素食
  3. .collect(toList());

筛选去重:distinct()函数

去重是指去除筛选结果中的重复项,只需在fiter之后调用distinct()即可:

 
  1. List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4);
  2. numbers.stream().filter(i -> i % 2 == 0).distinct().forEach(System.out::println);

截短流:limit函数

截短流是指从流中截取部分数据,如取出热量大于300卡路里的前3道菜:

 
  1. List<Dish> dishes = menu.stream()
  2. .filter(d -> d.getCalories() > 300)
  3. .limit(3)//截短流
  4. .collect(toList());

跳过元素:skip(int)函数

跳过元素是指跳过流中指定数量的元素,对剩下的进行操作或取出,如下面的代码将跳过大于300卡路里的头3道菜:

 
  1. List<Dish> dishes = menu.stream()
  2. .filter(d -> d.getCalories() > 300)
  3. .skip(3)//跳过前3个元素
  4. .collect(toList());

当菜单流中热量大于300卡路里的菜不足3个时,上面的代码返回一个空的List<Dish>

映射:map

流的映射是指对流的每个元素应用一个指定的函数,使其映射成我们需要的新的元素。如从菜单中映射过菜名列表,代码如下:

 
  1. List<String> dishNames = menu.stream()
  2. .map(Dish::getName)//map映射
  3. .collect(toList());

菜单流Stream<Dish>经过map映射操作Dish::getName转换成了字符串流Stream<String>,即菜名流。

流的扁平化:flatMap

流的扁平化操作flatMap,通俗来将就是将多个流合并为一个流。
假如我们需要将给定的单词列表["Hello","World"]拆分为去重的字母列表["H","e","l", "o","W","r","d"],该怎么做?

尝试1:使用map与distinct

 
  1. //取得单词流Stream<String> 每个单词为一个字符串
  2. words.stream()
  3. //映射成Stream<String[]>,每个单词转换成了组成该单词的字符数组
  4. .map(word -> word.split(""))
  5. //去重,依然是String[]
  6. .distinct()
  7. //结果是List<String[]>
  8. .collect(toList());

尝试1宣告失败!

尝试2:使用map和Arrays.stream()

 
  1. //取得单词流Stream<String> 每个单词为一个字符串
  2. words.stream()
  3. //映射成Stream<String[]>,每个单词转换成了组成该单词的字符数组
  4. .map(word -> word.split(""))
  5. //Arrays::stream将每个字符数组转成字符流Stream<String>
  6. .map(Arrays::stream)
  7. .distinct()
  8. //结果是List<Stream<String>>
  9. .collect(toList());

尝试2宣告失败!

尝试3:使用flatMap

 
  1. List<String> uniqueCharacters =
  2. //取得单词流Stream<String> 每个单词为一个字符串
  3. words.stream()
  4. //映射成Stream<String[]>,每个单词转换成了组成该单词的字符数组
  5. .map(w -> w.split(""))
  6. //flatMap将每个字符数组转成的字符流Stream<String>扁平化为单个流Stream<String>
  7. .flatMap(Arrays::stream)
  8. //去除重复字符
  9. .distinct()
  10. //获取去重后的字符列表List<String>
  11. .collect(Collectors.toList());

尝试3宣告成功!

anyMatch:至少匹配一个元素

查找菜单中是否存在素食,一旦匹配到素食即退出并返回true

 
  1. if(menu.stream().anyMatch(Dish::isVegetarian)){
  2. System.out.println("找到素食!");
  3. }

allMatch:匹配所有元素

检测菜单中所有菜是不是都是健康食品(假设热量小于1000就是健康的):

 
  1. if(menu.stream().allMatch(d -> d.getCalories() < 1000)){
  2. System.out.println("所有菜都是健康的,因为热量都小于1000");
  3. }

noneMatch:所有元素都不匹配

 
  1. if(menu.stream().noneMatch(d -> d.getCalories() >= 1000)){
  2. System.out.println("所有菜都是健康的,因为热量都不大于1000");
  3. }

查找任意元素:findAny

例如找到菜单中的任何一样素食:

 
  1. Optional<Dish> dish = menu.stream().filter(Dish::isVegetarian).findAny();

findAny返回当前流中的任意一个元素。

java.util.Optional<T>是一个容器类,它包裹着T,如上面代码中的Optional<Dish>可以理解装着Dish的一个容器,且该Dish允许为空,可以通过optional.get()方法获取该容器装的东西,该系列后面的文章会详细介绍Optional类的用法。

查找第一个元素:findFirst()

找到第一个平方能被3整除的数:

 
  1. List<Integer> someNumbers = Arrays.asList(1, 2, 3, 4, 5);
  2. Optional<Integer> firstSquareDivisibleByThree =
  3. someNumbers.stream()
  4. .map(x -> x * x)
  5. .filter(x -> x % 3 == 0)
  6. .findFirst(); // 9

相比于findAny,findFirst在并行上有更多的限制,如果不关心找到哪个元素,推荐用findAny。

归约操作:利用reduce求和

归约操作是指将流中的所有元素反复组合起来,得到一个值。比如,将流中的元素求和:int sum = numbers.stream().reduce(0, (a, b) -> a + b);

为什么说是反复组合起来?
求和归约操作中是将指定的初始值0(reduce方法的第一个参数)与流中的第一个元素相加(表达为reduce的第二个参数BinaryOperator,我们传递是Lambda表达式(a, b) -> a + b)得到一个中间值后与流中的第二个元素相加,直至流中的所有元素都被累加完,得到最终的求和结果。

reduce只接受一个参数的重载函数

 
  1. Optional<Integer> sum = numbers.stream().reduce((a, b) -> (a + b));

区别是返回值变成了Optional。

归约操作:利用reduce求最大与最小值

 
  1. //求最大值
  2. Optional<Integer> max = numbers.stream().reduce(Integer::max);
  3. //求最小值
  4. Optional<Integer> min = numbers.stream().reduce(Integer::min);

注:reduce操作最重要的就是需要指定一个Lambda表达式或方法引用来将流中的两个元素依次结果来产生一个新值。

这篇关于java8流(Stream API)使用详解:筛选、切片、映射、查找、匹配和归约等流操作的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/372421

相关文章

SpringBoot全局域名替换的实现

《SpringBoot全局域名替换的实现》本文主要介绍了SpringBoot全局域名替换的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录 项目结构⚙️ 配置文件application.yml️ 配置类AppProperties.Ja

Java使用Javassist动态生成HelloWorld类

《Java使用Javassist动态生成HelloWorld类》Javassist是一个非常强大的字节码操作和定义库,它允许开发者在运行时创建新的类或者修改现有的类,本文将简单介绍如何使用Javass... 目录1. Javassist简介2. 环境准备3. 动态生成HelloWorld类3.1 创建CtC

JavaScript中的高级调试方法全攻略指南

《JavaScript中的高级调试方法全攻略指南》什么是高级JavaScript调试技巧,它比console.log有何优势,如何使用断点调试定位问题,通过本文,我们将深入解答这些问题,带您从理论到实... 目录观点与案例结合观点1观点2观点3观点4观点5高级调试技巧详解实战案例断点调试:定位变量错误性能分

使用Python批量将.ncm格式的音频文件转换为.mp3格式的实战详解

《使用Python批量将.ncm格式的音频文件转换为.mp3格式的实战详解》本文详细介绍了如何使用Python通过ncmdump工具批量将.ncm音频转换为.mp3的步骤,包括安装、配置ffmpeg环... 目录1. 前言2. 安装 ncmdump3. 实现 .ncm 转 .mp34. 执行过程5. 执行结

Python中 try / except / else / finally 异常处理方法详解

《Python中try/except/else/finally异常处理方法详解》:本文主要介绍Python中try/except/else/finally异常处理方法的相关资料,涵... 目录1. 基本结构2. 各部分的作用tryexceptelsefinally3. 执行流程总结4. 常见用法(1)多个e

Java实现将HTML文件与字符串转换为图片

《Java实现将HTML文件与字符串转换为图片》在Java开发中,我们经常会遇到将HTML内容转换为图片的需求,本文小编就来和大家详细讲讲如何使用FreeSpire.DocforJava库来实现这一功... 目录前言核心实现:html 转图片完整代码场景 1:转换本地 HTML 文件为图片场景 2:转换 H

Java使用jar命令配置服务器端口的完整指南

《Java使用jar命令配置服务器端口的完整指南》本文将详细介绍如何使用java-jar命令启动应用,并重点讲解如何配置服务器端口,同时提供一个实用的Web工具来简化这一过程,希望对大家有所帮助... 目录1. Java Jar文件简介1.1 什么是Jar文件1.2 创建可执行Jar文件2. 使用java

C#使用Spire.Doc for .NET实现HTML转Word的高效方案

《C#使用Spire.Docfor.NET实现HTML转Word的高效方案》在Web开发中,HTML内容的生成与处理是高频需求,然而,当用户需要将HTML页面或动态生成的HTML字符串转换为Wor... 目录引言一、html转Word的典型场景与挑战二、用 Spire.Doc 实现 HTML 转 Word1

PHP应用中处理限流和API节流的最佳实践

《PHP应用中处理限流和API节流的最佳实践》限流和API节流对于确保Web应用程序的可靠性、安全性和可扩展性至关重要,本文将详细介绍PHP应用中处理限流和API节流的最佳实践,下面就来和小编一起学习... 目录限流的重要性在 php 中实施限流的最佳实践使用集中式存储进行状态管理(如 Redis)采用滑动

SpringBoot实现不同接口指定上传文件大小的具体步骤

《SpringBoot实现不同接口指定上传文件大小的具体步骤》:本文主要介绍在SpringBoot中通过自定义注解、AOP拦截和配置文件实现不同接口上传文件大小限制的方法,强调需设置全局阈值远大于... 目录一  springboot实现不同接口指定文件大小1.1 思路说明1.2 工程启动说明二 具体实施2