Java8 Stream 流机制和 Lambda 表达式

一、Stream 流介绍与使用场景

Stream 流介绍

  • java8 中的stream 与InputStream和OutputStream是完全不同的概念, stream 是用于对集合迭代器的增强,使之完成能够完成更高效的聚合操作(过滤排序统计分组)或者大批量数据操作。
  • stream 与 Lambda 表达式结合后编码效率大大提高,可读性更强。
    举例如下:
// 获取所有红色苹果的总重量
appleStore.stream().filter(a -> "red".equals(a.getColor()))
.mapToInt(w -> w.getWeight()).sum()
// 基于颜色统计平均重量
appleStore.stream().collect(Collectors.groupingBy(a -> a.getColor(),Collectors.averagingInt(a -> a.getWeight()))).forEach((k, v) -> {System.out.println(k + ":" + v);
});

使用场景

场景一:跨库join的问题

查询一个店铺的订单信息,需要用到订单表与会员表 在传统数据库单一例中 可以通过jon 关联轻松实现,但在分布场景中 这两张表分别存储在于 交易库 和会员库 两个实例中,join不能用。只能在服务端实现其流程如下:

  1. 查询订单表数据
  2. 找出订单中所有会员的ID
  3. 根据会员ID查询会员表信息
  4. 将订单数据与会员数据进行合并

这用传统迭代方法非常繁琐,而这正是stream 所擅长的。示例代码如下:

// 获取所有会员ID 并去重
List<Integer> ids = orders.stream().map(o -> o.getMemberId()).distinct().collect(Collectors.toList());
//  合并会员信息 至订单信息
orders.stream().forEach(o -> {Member member = members.stream().filter(m -> m.getId() == o.getMemberId()).findAny().get();o.setMemberName(member.getName());
});

场景二:N+1 问题

二、Lambda 表达式

Lambda 简介:

  • Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。
  • Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。
  • Lambda 表达式可以使代码变的更加简洁紧凑。
    匿名类写法
new Thread(new Runnable() {@Overridepublic void run() {System.out.println("hello  world");}
}).start();

Lambda写法

new Thread(() -> System.out.println("hello  world")).start();

在上述例子中编译器会将 “System.out.println(“hello world”)” 编译成Runnable.run 的执行指令。因为 run 方法是Runnable接口的唯一方法,代码中我们无需指明Run方法。如果Runable有多个方法是不能使用Lambda表达示的。

函数式接口:

支持Lambda的接口统称函数式接口。
只有一个抽像方法的接口就是函数式接口,其详细特征如下:

  • 接口中标注了 @FunctionalInterface 注解
  • 接口中只有一个抽像方法会被编译器自动认识成函数式接口
  • 接口中有一个抽像方法,同时包含了Object类的其它抽像方法也会被识别成抽像接口

Lambda表达式三种编写方式:

  1. expression:单条语句表达式
  2. statement:语句块
  3. reference:方法引用

三、Stream 流执行机制

img

流的操作特性

  1. stream不存储数据
  2. stream不改变源数据
  3. stream 不可重复使用

流的操作类型

stream 所有操作组合在一起即变成了管道,管道中有以下两种操作:

  • 中间操作(intermediate): 调用中间操作方法会返回一个新的流。通过连续执行多个操作倒便就组成了Stream中的执行管道(pipeline)。需要注意的是这些管道被添加后并不会真正执行,只有等到调用终值操作之后才会执行。
  • 终值操作(terminal): 在调用该方法后,将执行之前所有的中间操作,获返回结果结束对流的使用
  • 流的执行顺序说明:其每个元素挨着作为参数去调用中间操作及终值操作,而不是遍历完一个方法,再遍历下一个方法。
  • 流的并行操作:调用Stream.parallel() 方法可以将流基于多个线程并行执行

Stream 中的常用API及场景

方法描述操作类型
filter接收一个Boolean表达示来过滤元素中间操作
map将流中元素 1:1 映谢成另外一个元素中间操作
mapToInt将流中元素映谢成int,mapToLong、mapToDouble操作类似目的减少 装箱拆箱带来的损耗中间操作
flatMap如map时返回的是一个List, 将会进一步拆分。详见flatMap示例中间操作
forEach遍历流中所有元素终值操作
sorted排序中间操作
peek遍历流中所有元素 ,如forEach不同在于不会结束流中间操作
toArray将流中元素转换成一个数组返回终值操作
reduce归约合并操作中间操作
collect采集数据,返回一个新的结果 参数说明:Supplier: 采集需要返回的结果BiConsumer<R, ? super T>:传递结果与元素进行合并。BiConsumer<R, R>:在并发执行的时候 结果合并操作。详见 collec示例终值操作
distinct基于equal 表达示去重中间操作
max通过比较函数 返回最大值终值操作
anyMatch流中是否有任一元素满足表达示终值操作
allMatch流中所有元素满足表达示返回true终值操作
noneMatch与allMatch 相反,都不满足的情况下返回 true终值操作
findFirst找出流中第一个元素终值操作
of生成流生成流操作
iterate基于迭代生成流生成流操作
generate基于迭代生成流,与iterate 不同的是不 后一元素的生成,不依懒前一元素生成流操作
concat合并两个相同类型的类生成流操作

举例:

@Testpublic void filterTest() {appleStore.stream().filter(a -> a.getColor().equals("red")).forEach(a -> {System.out.println(a.getColor());});}@Testpublic void mapTest() {appleStore.stream().map(a -> a.getOrigin()).forEach(System.out::println);}@Testpublic void flatMapTest() throws IOException {Stream<String> lines = Files.lines(new File("G:\\git\\tuling-			java8\\src\\main\\java\\com\\tuling\\java8\\stream\\bean\\Order.java").toPath());lines.flatMap(a -> Arrays.stream(a.split(" "))).forEach(System.out::println);}@Testpublic void sortedTest() {appleStore.stream().sorted((a, b) -> a.getWeight() - b.getWeight()).map(a -> a.getWeight()).forEach(System.out::println);}@Testpublic void peekTest() {appleStore.stream().peek(a -> {System.out.println(a.getId());}).map(a -> a.getOrigin()).peek(System.out::println).forEach(a -> {});}@Testpublic void reduceTest() {// 找出最重的那个苹果appleStore.stream().reduce((a, b) -> a.getWeight() > b.getWeight() ? a : b).ifPresent(a -> {System.out.println(a.getWeight());});}@Testpublic void collectTest() {// 将结果转换成id作为key map<Integer,Apple>HashMap<Integer, Apple> map = appleStore.stream().collect(HashMap::new, (m, a) -> m.put(a.getId(), a), (m1, m2) -> m1.putAll(m2));map.forEach((k, v) -> {System.out.println(k);System.out.println(v);});// Map<String,List<Apple>>// 基于颜色分组, 并获取其平均重量}

Collectors 中的常用API及场景

方法描述
toList转换成list
toMap转换成map
groupingBy统计分组
averagingInt求平均值
summingInt求总值
maxBy获取最大值

举例:

// 获得所有颜色苹果的平均重量
@Test
public void groupByTest() {Collector<Apple, ?, Map<String, Double>> groupCollect =Collectors.groupingBy((Apple a) -> a.getColor(), Collectors.averagingInt((Apple a) -> a.getWeight()));appleStore.stream().collect(groupCollect).forEach((k, v) -> {System.out.println(k + ":" + v);});}

流的关闭机制

一般情况使用完流之后不需要调用 close 方法进行关闭,除非是使用channel FileInputStream 这类的操作需要关闭,可调用 java.util.stream.BaseStream#onClose() 添加关闭监听。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/556779.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

嵌入式linux安装qt,树莓派上安装qt

在树莓派上安装了官方的raspbian系统。为了在能在上面开发程序&#xff0c;在系统上安装了qt4 。参考链接http://qt-project.org/wiki/apt-get_Qt4_on_the_Raspberry_Piapt-getFirstly I got the development tools needed by Qt Creator in the hope it would be less heavy f…

linux guide编译器,GUIDE编译器-GUIDE编程工具-GUIDE编译器下载 v1.0.2官方版-完美下载...

GUIDE编译器是款跨平台的开发环境编程工具&#xff0c;支持C/C 和 Pascal三种语言&#xff0c;具有跨平台、操作简单、跨编程语言和单文件编译调试等特点&#xff0c;为用户提供单文件编译、调试和运行的环境。GUIDE编译器特色1、跨平台&#xff1a; GUIDE 可在 linux 平台和 w…

MySQL事务隔离级别和实现原理

经常提到数据库的事务&#xff0c;那你知道数据库还有事务隔离的说法吗&#xff0c;事务隔离还有隔离级别&#xff0c;那什么是事务隔离&#xff0c;隔离级别又是什么呢&#xff1f;本文就帮大家梳理一下。 MySQL 事务 本文所说的 MySQL 事务都是指在 InnoDB 引擎下&#xff0…

Linux如何清除last信息,linux清除last、lastb和history记录

清除登录系统成功的记录&#xff0c;也就是last命令看到的记录[rootlocalhost root]# echo ""> /var/log/wtmp 此文件默认打开时乱码的&#xff0c;里面可以看到ip等等信息[rootlocalhost root]# echo "">/var/log/wtmp[rootlocalhost root]# last此…

超级全面的MySQL优化面试解析

推荐阅读(点击即可跳转阅读) 1. SpringBoot内容聚合 2. 面试题内容聚合 3. 设计模式内容聚合 4. Mybatis内容聚合 5. 多线程内容聚合 超级全面的MySQL优化面试解析 本文概要 概述 为什么要优化 系统的吞吐量瓶颈往往出现在数据库的访问速度上随着应用程序的运行&#…

mysql linux导入csv主键,MySQL导入csv文件内容到Table及数据库的自增主键设置

写在前面目的是测试将csv文件内容导入到表中, 同时记录一下自增主键的设置.测试采用MySQL8.0.新建表customer_info如下, 未设置主键.修改上表, 添加主键id, 并设置为自增.ALTER TABLE customer_info ADD COLUMN id INT AUTO_INCREMENT NOT NULL PRIMARY KEY;导入步骤1.为了模拟…

mysql 优化方法有哪些?

MySQL索引 MySQL支持诸多存储引擎&#xff0c;而各种存储引擎对索引的支持也各不相同&#xff0c;因此MySQL数据库支持多种索引类型&#xff0c;如BTree索引&#xff0c;哈希索引&#xff0c;全文索引等等。为了避免混乱&#xff0c;本文将只关注于BTree索引&#xff0c;因为这…

linux shell脚本判断文件行数,判断文件是否存在的shell脚本代码

实现代码一、#!/bin/sh# 判断文件是否存在# lilSzqFnk&#xff1a;www.jb51.net# date&#xff1a;2013/2/28myPath"/var/log/httpd/"myFile"/var /log/httpd/access.log"# 这里的-x 参数判断$myPath是否存在并且是否具有可执行权限if [ ! -x "$myPat…

Linux下多功能编辑器,Linux下的编辑器——vi大全

xp 交换两个字符位置ddp 上下两行调换J 上下两行合并dG 删除所有行d$ 从当前位置删除到行尾y$ 从当前位置复制到行尾, 如果要粘贴到其他地方 p就可以了:ab string strings例如 ":ab usa United States of America" ,当你在文见里插入 usa 时United States of America…

Mysql中几种插入效率的实例对比

前言 最近因为工作的需要&#xff0c;要在Mysql里插入大量的数据大约1000w&#xff0c;目测会比较耗时。所以现在就像测试一下到底用什么插入数据的方法比较快捷高效。 下面就针对每一种方法分别测试不同数据量下的插入效率。 测试数据库的基本与操作如下&#xff1a; mysq…

linux第三方模块参数,nginx 的第三方模块ngx_http_accesskey_module 来实现下载文件的防盗链步骤(linux系统下)...

nginx 的第三方模块ngx_http_accesskey_module 来实现下载文件的防盗链步骤(linux系统下)&#xff0c;安装Nginx和HttpAccessKeyModule模块(参考LNMP环境搭建&#xff1a;第一步&#xff1a;在/usr/local/src/下下载模块压缩包&#xff1a;wget http://wiki.nginx.org/images/5…

Java基础面试题与答案

八种基本数据类型以及包装类 八种基本数据类型默认值&#xff1f;大小&#xff1f;范围区间&#xff1f;包装类的缓存区间&#xff1f; 序号类型名称默认值大小最小值最大值包装类缓冲区间1booleanfalse1B0(false)1(true)Boolean无2byte(byte)01B-128127Byte-128 ~ 1273char‘…

学习vim的linux游戏,PacVim:一个学习 vim 命令的命令行游戏 | Linux 中国

作者 | Sk 译者 | geekpi &#x1f48e; &#x1f48e; 共计翻译&#xff1a;735 篇 贡献时间&#xff1a;1691 天你好&#xff0c;Vim用户&#xff01;今天&#xff0c;我偶然发现了一个很酷的程序来提高 Vim 的使用技巧。Vim 是编写和编辑代码的绝佳编辑器。然而&#x…

Java多线程面试题与答案

线程 线程与进程的区别是什么&#xff1f; 进程指的是应用程序在操作系统中执行的副本&#xff08;系统分配资源的最小单位&#xff09;&#xff0c;线程是程序执行的最小单位&#xff1b;进程使用独立的数据空间&#xff0c;而线程共享进程的数据空间。 线程状态图 多线程会…

用linux集成电路版图设计,集成电路版图设计报告.doc

集成电路版图设计报告集成电路版图设计实验报告班 级&#xff1a;微电子1302班学 号&#xff1a;1306090226姓 名&#xff1a;李根日 期&#xff1a;2016年1月10日一&#xff1a;实验目的&#xff1a;熟悉IC设计软件Cadence Layout Editor的使用方法&#xff0c;掌握集成电路原…

JVM面试题与答案

JVM内存布局 JVM在内存布局上可以分为哪些区域&#xff1f; 堆&#xff08;线程共享&#xff09;&#xff1a;GC的主要回收地&#xff0c;包含几乎所有的实例对象、字符串常量池&#xff1b;元空间&#xff08;线程共享&#xff09;&#xff1a;在本地内存分配&#xff0c;包…

md0和md1linux软raid,软RAID管理命令mdadm详解

mdadm是linux下用于创建和管理软件RAID的命令&#xff0c;是一个模式化命令。但由于现在服务器一般都带有RAID阵列卡&#xff0c;并且RAID阵列卡也很廉价&#xff0c;且由于软件RAID的自身缺陷(不能用作启动分区、使用CPU实现&#xff0c;降低CPU利用率)&#xff0c;因此在生产…

Spring、SpringBoot常见面试题与答案

Spring Spring Bean 的作用域有哪些&#xff1f;它的注册方式有几种&#xff1f; Spring 容器中管理一个或多个 Bean&#xff0c;这些 Bean 的定义表示为 BeanDefinition 对象&#xff0c;具体包含以下重要信息&#xff1a; Bean 的实际实现类&#xff1b;Bean 的引用或者依赖…

c语言本身有输入输出语句正确错误,C语言模拟选择题

导出试题1. 以下叙述正确的是。A) 在C程序中&#xff0c;main函数必须位于程序的最前面B) C程序的每行中只能写一条语句C) C语言本身没有输入输出语句D) 在对一个C程序进行编译的过程中&#xff0c;可发现注释中的拼写错误2. 以下叙述不正确的是。A) 一个C源程序可由一个或多个…

Dubbo常见面试题与答案

Dubbo的基础知识 Dubbo的核心架构是怎样的&#xff1f; Registry&#xff1a;注册中心。 负责服务地址的注册与查找&#xff0c;服务的 Provider 和 Consumer 只在启动时与注册中心交互。注册中心通过长连接感知 Provider 的存在&#xff0c;在 Provider 出现宕机的时候&#…