Java8 新特性——流式操作

2023-11-15

流式操作

流(Stream):Java8新增 , 用来处理我们集合的数据(与IO包里的流是完全不同的概念),倒是和Spark Streaming很像(反正是抄的)

如何处理集合中的数据呢(为什么引入流)?

  1. 声明式处理数据;(元素的内部迭代,不需要做外部迭代)【流可以把一些基础操作连接起来,用于表达更加复杂的数据处理的流水线】【类似自然语言,类似sql】
  2. 流内部可以做并行操作。(内部迭代)【底层帮我们,多线程来处理数据,不需要我们来控制】

先看一个小案例:

public class Dish { //菜单

  private final String name; // 菜名
  private final boolean vegetarian; // 素食
  private final int calories; //卡路里
  private final Type type; // MEAT(肉), FISH(鱼), OTHER(其它)

  public Dish(String name, boolean vegetarian, int calories, Type type) {
    this.name = name;
    this.vegetarian = vegetarian;
    this.calories = calories;
    this.type = type;
  }

  public String getName() {
    return name;
  }

  public boolean isVegetarian() {
    return vegetarian;
  }

  public int getCalories() {
    return calories;
  }

  public Type getType() {
    return type;
  }

  public enum Type { MEAT, FISH, OTHER }

  @Override
  public String toString() {
    return name;
  }

  public static final List<Dish> menu =
          Arrays.asList( new Dish("猪肉", false, 1100, Dish.Type.MEAT),
                  new Dish("牛肉", false, 1700, Dish.Type.MEAT),
                  new Dish("鸡肉", false, 1400, Dish.Type.MEAT),
                  new Dish("薯条", true, 430, Dish.Type.OTHER),
                  new Dish("米饭", true, 350, Dish.Type.OTHER),
                  new Dish("沙拉", true, 120, Dish.Type.OTHER),
                  new Dish("披萨", true, 450, Dish.Type.OTHER),
                  new Dish("虾", false, 600, Dish.Type.FISH),
                  new Dish("大马哈鱼", false, 650, Dish.Type.FISH));

}

需求:从我们的集合中筛选卡路里<400的菜,然后按照卡路里进行排序,返回一个排序好的菜的名字

1.Java8之前所用的方法:遍历集合 使用 外部迭代

  @Test
  public void test1(){
    List<String> names = getNamesInJava7(Dish.menu);
    System.out.println(names);
  }
 public static List<String> getNamesInJava7(List<Dish> dishes){
    //筛选卡路里小于400的,存入新集合
    List<Dish> lowCaloricDishs = new ArrayList();
    for(Dish dish : dishes){
      if(dish.getCalories() < 400){
        lowCaloricDishs.add(dish);
      }
    }

    //对筛选过的新集合进行排序
    Collections.sort(lowCaloricDishs, new Comparator<Dish>() {
      @Override
      public int compare(Dish o1, Dish o2) {
        return Integer.compare(o1.getCalories(),o2.getCalories());
      }
    });
     //lambda表达式写法,但是其实java8之前还没有lambda表达式
	//Collections.sort(lowCaloricDishs, (o1, o2)->{
	//return Integer.compare(o1.getCalories(),o2.getCalories());
	//});

    //返回菜名的集合
    ArrayList<String> lowCaloricDishName = new ArrayList<>();
    for(Dish dish : lowCaloricDishs){
      lowCaloricDishName.add(dish.getName());
    }

    return lowCaloricDishName;
 }

Java8:集合转化为流(创建流)的api:集合对象.stream()

  //集合:List<Dish> dishes  |  集合转化为流:dishes.stream()
  //集合转化为流,就可以做流式操作
  // lambda --- 流
  public static List<String> getNamesInJava8(List<Dish> dishes){
    //声明式处理数据
    Stream<Dish> stream = dishes.stream();
    Stream<Dish> dishStream = stream 
            .filter(d -> d.getCalories() < 400);
    Stream<Dish> sorted = dishStream 
            .sorted(Comparator.comparing(Dish::getCalories));
    Stream<String> map = sorted.map(Dish::getName);
    List<String> collect = map.collect(Collectors.toList());
    return collect;
    //算子  并行的处理  上面的代码可以直接写成下面的方式
//    return dishes.stream() // 1,2,3,4,5->2,3,4,5->3,4,5->4,5->5
//            .filter(d->d.getCalories()<400)//1->2->3->4->5
//            .sorted(Comparator.comparing(Dish::getCalories))//1->2->3->4->5
//            .map(Dish::getName)//1->2->3->4->5
//            .collect(Collectors.toList());//1->1,2->1,2,3->1,2,3,4,->1,2,3,4,5

  }
  @Test
  public void test2(){
    //Consumer<String> action
    Stream<String> stream = getNamesInJava8(Dish.menu).stream();
    stream.forEach(System.out::println);
  }

可以声明式的编程(不需要我们显示的迭代数据,外部迭代数据)(内部迭代数据) ,【stream()集合变成了流,Stream类有很多api(即算子),链式操作】

并行的数据处理 (简单的并行 | 分布式并行)


在这里插入图片描述

流(Stream):算子(api、方法)算子是指过程(上图中的大矩形是指集合)

​ 算子分为两种:(java8和spark都有这两种概念)

中间操作 :所有Stream类里面的算子中,当一个流调用了一个算子的时候,如果能返回另外一个流那么则是中间操作,否则就是一个终端操作。中间操作是具有延迟加载的

终端操作:所有Stream类里面的算子中,当一个流调用了一个算子的时候,不能返回流。

中间操作具有延迟加载,程序执行由谁来触发呢?------由终端操作来进行触发

所有没有终端操作的流式操作,都不会进行程序的执行(即所谓的延迟加载)

@org.junit.Test
public void test2(){
   Stream<Dish> distinctList = Dish.menu.stream()
		   		.filter(d->{
		   			System.out.println("我有没有输出");
		   			return d.getCalories()>300;
                  })
		   		.distinct();//去重
//	   distinctRDD.forEach(System.out::println);
//这里没有终端操作,中间操作的程序不会执行,控制台不会输出
}

为什么流要做延迟加载?

Stream<Dish> stream = Dish.menu.stream();
stream.map(d->{
	System.out.println("map->"+d);
	return d ;
})
.filter(d->{
	System.out.println("filter->"+d);
	return d.getCalories() < 500 ;
})
.limit(2) //限制
.forEach(System.out::println);
//输出
map->猪肉
filter->猪肉
map->牛肉
filter->牛肉
map->鸡肉
filter->鸡肉
map->薯条
filter->薯条
薯条
map->米饭
filter->米饭
米饭
//单线程,先处理1,处理完后处理2,再3,limit(2)截断作用,所有4、5不执行
//stream()-->parallelStream()
//输出
map->牛肉
filter->牛肉
map->虾
filter->虾
map->鸡肉
filter->鸡肉
map->沙拉
filter->沙拉
map->薯条
filter->薯条
map->大马哈鱼
filter->大马哈鱼
map->猪肉
filter->猪肉
map->披萨
filter->披萨
map->米饭
filter->米饭
薯条
米饭

在这里插入图片描述

stream()单线程(确切的说是PC中默认的最大线程数,单核/多核)

parallelStream()并行的


总结:

中间操作:(.)表示传入的是一个接口

操作 返回类型 函数式接口 函数描述符 作用
filter(.) Stream Predicate T -> boolean 过滤
map(.) Stream Function<T,R> T -> R 映射(转换)
limit(数字) Stream 限制
sorted(.) Stream Comparator (T,T)->int 排序
distinct() Stream 去重(对流里的每个元素去重)
skip(数字) Stream 跳过
终端操作 注: 收集器就是把流中的所有数据收集起来(list,set)
forEach() 遍历流中每一个元素
count() 返回流中元素的个数【long】
collect() 里面接收一个收集器(toList())

补充一下(网上很多说的都不准确):函数式接口是只有一个有效的抽象方法的接口。函数式接口中还可以有默认方法、静态方法。


集合和流的关系:

​ 集合描述的是数据集【数据的整体】, 流主要描述的是计算方式,就是把一个集合的状态转变为另外一个状态)

流血缘关系链:

​ java8流式操作里面 血缘关系链形成的流不具有重复消费功能

spark血缘关系链是可以重复消费的

@org.junit.Test
public void test2(){
   Stream<Dish> distinctList = Dish.menu.stream()
		   		.filter(d->d.getCalories()>300)
		   		.distinct();
   distinctList.forEach(System.out::println);
   distinctList.forEach(System.out::println);    //这行会产生错误
   //若想再终端操作,只能重新进行中间操作,再终端操作,费时【不具有重复消费功能】
}

skip(n)算子:跳过n个元素 -------- (中间操作)Stream skip(long n)

总结:

1.如果大家在写代码的时候能够使用匿名内部类的地方,那么就可以尝试使用lambda表达式,方法引用

2.假如大家要对集合做一些数据分析,那么就可以考虑用流

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java8 新特性——流式操作 的相关文章

  • Eclipse 中的 Java 构建路径问题

    在 Eclipse 中 我有一个与我的构建路径相关的错误 错误 Project XX is missing required library middlegen 2 1 jar 但该库在构建路径配置之前被删除 是不是缓存或者其他方面有问题
  • 将 Java 对象图保存为 XML 文件

    将任意 Java 对象图保存为 XML 文件 并能够在以后重新水合对象 的最简单易用的技术是什么 这里最简单的方法是序列化对象图 Java 1 4 内置了对 XML 序列化的支持 我成功使用的一个解决方案是 XStream http x s
  • 使用 java 从 XML 元素中删除空格

    我有一个 JSON 如下 String str Emp name JSON Emp id 1 Salary 20997 00 我想使用 java 将此 JSON 转换为 XML 我的 java 代码在这里 JSON json JSONSer
  • 如何使用 Jsoup 获取包含非 ASCII 字符(ą、ś ...)的 URL?

    我正在使用 jsoup 解析一些波兰网站 但我对 URL 中的 等特殊字符有问题example com k t读起来像example com k 每个没有这个特殊字符的查询都可以完美运行 我努力了Document doc Jsoup par
  • 检查两个日期周期是否重叠[重复]

    这个问题在这里已经有答案了 我有两个日期范围 start1 end1 gt gt date1 start2 end2 gt gt date2 我想检查两个日期是否重叠 我的流程图我假设 运算符对于比较是有效的 boolean isOverL
  • 将 Swing 集成到简单的文本冒险游戏中

    我对 Java 中的一些中级概念相当陌生 最近 我制作了一款名为 DazzleQuest 的文本冒险游戏 它完全在开发者控制台 终端中运行 它涉及到我的朋友作为角色 所以我想向他们展示它 并通过将命令行的功能和控制台的输出转移到一个简单的
  • JAVA 签名对象 - 没有安装的提供程序支持此密钥:sun.security.rsa.RSAPrivateCrtKeyImpl

    我想使用密钥工具和以下命令创建的一对 RSA 密钥对我创建的文件进行签名 keytool genkeypair alias key keyalg RSA keysize 2048 sigalg SHA256withRSA validity
  • 使用 PowerMock 和 TestNG 模拟单个静态方法

    class StaticClass public static String a return a public static String ab return a b 我想嘲笑StaticClass a以便它返回 x 并致电StaticC
  • 无法从 PDFA1-a 格式文档中提取图像

    我正在使用以下代码从 PDFA1 a 格式的 pdf 中提取图像 但我无法获取图像 List
  • 在字节数组上进行右位旋转/循环移位的最快方法是什么

    如果我有数组 01101111 11110000 00001111 111 240 15 移位 1 位的结果是 10110111 11111000 00000111 183 248 7 数组大小不固定 移位范围为 1 到 7 含 目前我有以
  • Jetty 提供静态内容所需的最少文件集?

    背景 免责声明 I have veryJava 经验很少 我们之前在 Ant 构建期间使用了 Jetty 6 的包装版本来处理按需静态内容 JS CSS 图像 HTML 因此我们可以使用 PhantomJS 针对 HTTP 托管环境运行单元
  • 在 XSSF 工作簿上设置密码保护

    我想为使用 poi 3 14 创建的 xlsx 文件添加密码保护 该文档声称 这是可能的 http poi apache org cryption html http poi apache org encryption html 使用我尝试
  • BODMAS系统的加法和减法

    我一直在构建一个简单的公式计算器 但一直被加法和减法困扰 正如您应该知道的 在计算方程时 您遵循优先级算术规则 即括号 顺序 幂函数 除法 乘法 加法和减法 问题是加法和减法具有相同的优先级 因此您可以从左到右阅读 到目前为止 这是我的代码
  • 错误:类 kotlin.reflect.jvm.internal.FunctionCaller$FieldSetter

    我已尝试一切方法来消除此错误 但它不断出现 Class kotlin reflect jvm internal FunctionCaller FieldSetter can not access a member of class com
  • 使用会话空闲超时进行轮询

    我对 Tomcat 中的所有应用程序使用单点登录 我的要求是 我必须轮询应从后端获取的事务状态 但它也不应该影响会话的空闲超时 有人可以建议是否可以做点什么吗 Thanx 我不知道是否有标准方法可以做到这一点 如果没有 你可以写一个过滤器
  • 尝试用Java实现基于文本的Hangman游戏

    我需要检查用户输入的字母以及他们猜测的空格是否位于隐藏单词的特定位置 变量one等于用户猜测的空间索引 而letterGuess是他们猜测的字母 我的代码怎么错了 示例 秘密词是你好 hidden word is 用户猜测h 0 1 2 3
  • 在服务器上创建 Zip 文件并使用 java 下载该 zip

    我从 mkyong 获得了以下代码 用于在本地压缩文件 但是 我的要求是在服务器上压缩文件并需要下载它 任何人都可以帮忙吗 代码写入zip文件 public void zipFiles File contentFile File navFi
  • 避免加密和编码的 URL 字符串中的换行符

    我正在尝试实现一个简单的字符串编码器来混淆 URL 字符串的某些部分 以防止它们被用户弄乱 我使用的代码几乎与示例中的相同JCA指南 http docs oracle com javase 6 docs technotes guides s
  • 在android中测量不规则多边形的面积

    我正在开发一个应用程序 在其中我在地图上绘制多边形 并且我使用的地图不是谷歌 它的Mapsforge开源离线地图库 我可以通过将地理点转换为像素点来轻松在地图上绘制多边形 但在这里我想发现是不规则的多边形 为此我做了很多尝试 但它让我失败了
  • Java编程编译jar

    我有一个文本文件中的java源代码 必须在源代码中输入一些自定义的硬编码变量 然后将其转换为 jar 这是可行的 但是当我运行 jar 时 找不到 Main 类 当我用 WinRAR 解压 jar 文件时 我似乎找不到错误 当我通过 cmd

随机推荐

  • 【Windows】win10电脑Miracast投屏到电视

    Miracast 是一项无线技术 你的电脑可以使用它来将你的屏幕投影到电视 投影仪和同样支持 Miracast 的流媒体播放器 你可以使用此技术共享你在电脑上执行的操作 展示幻灯片放映 甚至在更大的屏幕上玩你喜爱的游戏 为你的设备做好准备
  • 目前最受欢迎的12个Python开源框架,你用过几个?

    今天给大家带来了12个在GitHub等开源网站中最受欢迎的Python开源框架 如果你正在学习python 那么这12个开源框架 千万别错过 这些框架包括事件I O OLAP Web开发 高性能网络通信 测试 爬虫等 虽说不上是全都有 但也
  • UE4 导航网格的使用

    在使用导航网格前 应先设置项目导航系统支持的导航代理者 Agents 在项目设置中 找到导航系统页面 DirtyAreasUpdateFreq 表示导航网格变化时 检测变化并更新的频率 这里可以设置导航系统的一些参数 包括是否允许客户端导航
  • DT下重新定义设置发布发布条数后的跳转页面

    destoon系统有些地方还是做得不够细致 今天给大家分享一个重新定义发布条数满了以后的页面跳转 正常逻辑跳转应该是会员升级页面而不是会员中心首页 修改方法如下 感谢DT朋友提供的修改方案 打开根目录文件 module article my
  • el-tree 阻止点击节点的时候自动展开或者收缩

    expand on click node 是否在点击节点的时候展开或者收缩节点 默认值为 true 如果为 false 则只有点箭头图标的时候才会展开或者收缩节点 但设置的时候 要加上 不然无效
  • 点选文字验证码识别

    最近在学习爬虫 碰到很多验证登录 今天分享一个点选文字验证码识别以及我在使用的验证码识别平台 上篇文章有涉及滑块验证 首先 注册一个超级鹰账号 选择充值0 5 1元即可 进入用户中心 gt 软件ID 生成一个用来接入接口的软件ID 下载示例
  • Acwing-二叉树的镜像

    遍历树中的所有点 每次遍历完之后把左右儿子swap一下 Definition for a binary tree node struct TreeNode int val TreeNode left TreeNode right TreeN
  • 线程池七大参数

    线程池的七大参数是指使用 ThreadPoolExecutor 创建线程池时所设置的 7 个参数 分别为 public ThreadPoolExecutor int corePoolSize int maximumPoolSize long
  • VScode for c++

    VScode for c VScode for c launch json version 0 2 0 configurations name gdb Launch type cppdbg request launch program wo
  • java集合之Map

    java集合之Map Map接口概述 将键映射到值的对象 一个映射不能包含重复的键 每个键最多只能映射到一个值 Map接口和Collection接口的不同 Map是双列的 Collection是单列的 Map的键唯一 Collection的
  • Linux Rsync服务详解(二)——Rsync服务实战

    今天继续给大家介绍Linux运维相关内容 本文主要内容是Rsync服务详解 一 Rsync实战 接下来 我们选择使用两台设备进行Rysnc的备份实战 设备一IP地址 192 168 136 101 设备二IP地址 192 168 136 2
  • 【openGL2021版】天空盒

    openGL2021版 天空盒 大家好 我是Lampard猿奋 欢迎来到船新的openGL基础系列的博客 今天主要实现的是天空盒 1 什么是天空盒 上周我们已经实现了FPS式的摄像机控制 键盘的 WSAD 可以控制摄像头的前后左右移动 鼠标
  • FPGA面试题【Verilog实现一个2位带进位全加器,画出门级电路】

    目录 题目 核心思路 答案 FPGA全貌 题目 Verilog实现一个2位带进位全加器 画出门级电路 核心思路 思路见代码注释 答案 2位加法器顶层模块 module top s cout a b cin 输入输出端口及变量定义 outpu
  • MySQL的 timze_zone 和 SpringBoot 的 serverTimezone 的设置

    查看和修改 MySQL 的时区 system time zone 系统时区 在MySQL启动时会检查当前系统的时区并根据系统时区设置全局参数system time zone的值 system time zone 变量只有全局值没有会话值 不
  • thinkphp5学习路程 四 模板调用及视图渲染

    继承 think Controller 类 以下类可以直接使用 fetch 渲染模板输出 display 渲染内容输入 assign 模板变量赋值 engine 初始化模板引擎
  • Mockjs模拟登录接口数据

    一丶安装mockjs cnpm install mockjs save dev 二丶创建Mock文件 Mock文件下包含index js mock服务 和user js mock数据 index js 首先引入Mock const Mock
  • Symbol类型

    如何定义symbol类型 2种方式 let id1 Symbol console log typeof id1 如果我们将 id 定义为数字类型 当他们id相同时 判断它们是否相等 结果肯定是相等的 let id1 666 let id2
  • 从recat源码角度看setState流程

    setState setState 将对组件 state 的更改排入队列批量推迟更新 并通知 React 需要使用更新后的 state 重新渲染此组件及其子组件 其实setState实际上不是异步 只是代码执行顺序不同 有了异步的感觉 使用
  • requests库get方法

    例 r requests get url r 一个包含服务器资源的Response对象 requests get url 构造一个想服务器请求资源的Request对象 Response 包含爬虫返回的全部内容 requests get ur
  • Java8 新特性——流式操作

    流式操作 流 Stream Java8新增 用来处理我们集合的数据 与IO包里的流是完全不同的概念 倒是和Spark Streaming很像 反正是抄的 如何处理集合中的数据呢 为什么引入流 声明式处理数据 元素的内部迭代 不需要做外部迭代