Java 8 (3) Stream 流 - 简介
什么是流?
流是Java API的新成员,它允许你以声明性方式处理数据集合(通过查询语言来表达,而不是临时编写一个实现)。就现在来说你可以先把它当做是一个遍历数据集的高级迭代器。此外,流还支持并行,你无需写任何多线程的代码!
定义一个实物类
public class Dish {
//菜名
private String Name;
//是否素食
private boolean vegetarian;
//热量
private Integer Calories;
//分类
private Type type;
}
public enum Type {
MEAT,//肉
FISH,//鱼
OTHER//其他
}
定义一个menu集合,以下栗子基于此menu
List<Dish> menu = Arrays.asList(
new Dish("猪肉炖粉条",false,800,Type.MEAT),
new Dish("小炒牛肉",false,700,Type.MEAT),
new Dish("宫保鸡丁",false,400,Type.MEAT),
new Dish("地三鲜",true,530,Type.OTHER),
new Dish("水煮菠菜",true,350,Type.OTHER),
new Dish("拔丝地瓜",true,120,Type.OTHER),
new Dish("火山下雪",true,550,Type.OTHER),
new Dish("水煮鱼",false,330,Type.FISH),
new Dish("于是乎",false,450,Type.FISH)
);
举个栗子:返回热量低的菜肴名称
//java7
List<Dish> lowCaloricDishes = new ArrayList<>();
for(Dish d : menu){
if(d.getCalories() < 400){
lowCaloricDishes.add(d);
}
}
Collections.sort(lowCaloricDishes, new Comparator<Dish>() {
@Override
public int compare(Dish o1, Dish o2) {
return Integer.compare(o1.getCalories(),o2.getCalories());
}
});
List<String> lowCaloricDishesName = new ArrayList<>();
for(Dish d : lowCaloricDishes){
lowCaloricDishesName.add(d.getName());
}
//java 8
List<String> lowCalorDishesNames = menu.stream()
.filter(s->s.getCalories() < 400)
.sorted(Comparator.comparing(Dish::getCalories))
.map(Dish::getName)
.collect(toList());
通过使用stream()流来完成这个功能,代码变的更简洁了,使用stream你可以把几个基础的操作连接起来,来表达复杂的数据处理流水线(在filter后面接上sorted、map和collect操作)。
只要将.stream()更换为parallelStream()就可以完成并行操作,并行会在后面将。
流简介
Java 8中的集合支持了一个新的stream方法,返回一个流。后面你会看到还有很多其他的方法可以得到流。一个简短的定义就是“从支持数据处理操作的源生成的元素序列”。
元素序列:就像集合一样,流也提供了一个接口,可以访问特定元素类型的一组有序值。但流的目的在于表达计算,集合讲的是数据。
源:流会使用一个提供数据的源,如集合、数组或输入/输出资源。从有序集合生成流时会保留原有的顺序。
数据处理操作:流的数据处理功能支持类似于数据库的操作,以及函数式编程语言中的常用操作(如filter、map、reduce、find、match、sort等),流可以顺序执行也可以并行执行。
流还有两个重要的特点:
流水线:很多流操作本身会返回一个流,这样多个操作就可以连接起来,形成一个大的流水线。
内部迭代:与使用迭代器显示迭代集合不同,流的迭代操作是在背后进行的。
代码解析:
menu.stream() :从menu源获得流
.filter(s->s.getCalories() < 400) : 过滤复合lambda表达式的数据
.map(Dish::getName) : 获取菜名
.limit(3) : 只取前三个
.collect(toList()); : 将结果保存在另一个List中
结果:[拔丝地瓜, 水煮鱼, 水煮菠菜]
流与集合
集合是一个内存中的数据结构,它包含数据结构中目前所有的值-集合中的每个元素都得先算出来才能添加到集合中,类似于存在DVD中的电影,从DVD上读出所有信息,
流是在概念上固定的数据结构(你不能添加或删除 集合可以),气元素是按需计算的,流就像是一个延迟创建的集合:只有在消费者需要的时候才会计算值,类似于在互联网上看电影。
只遍历一次
流和迭代器类似,只能遍历一次。遍历完之后,我们就说这个流已经被消费掉了。所以可以从原始数据源那里再获得一个新的流重新遍历一遍。
外部迭代与内部迭代
使用Collection接口需要用户去做迭代如foreach,这称为外部迭代。使用Streams库则是内部迭代-它帮你把迭代做了,还把得到的流值存在了某个地方,你只要给出一个函数即可。
List<String> lowCaloricDishesName = new ArrayList<>();
for (Dish d : lowCaloricDishes) {
lowCaloricDishesName.add(d.getName());
}
//for-each 内部其实是Iterator
Iterator<Dish> iterator = menu.iterator();
while(iterator.hasNext()){
Dish d = iterator.next();
lowCaloricDishesName.add(d.getName());
}
//没有迭代
List<String> lowCalorDishesNames = menu.stream()
.map(Dish::getName) //提取菜名
.collect(toList());
内部迭代与外部迭代的区别:
外部迭代一个集合时,显示的获取每个项目再加以处理。
(如:你:大儿子我们现在把地上的玩具都收起来吧,还有玩具吗?
女儿:“有,球”,
你:“好,把球放框里吧,还有吗?”
女儿:“有,还有积木”
你:“好,还有吗?”
女儿:“没了,没有了”
你:“ok,收好了”)
而内部迭代时,项目可以透明地并行处理,或者用更优化的顺序进行处理。
(如:你只需要说:“大儿子把地上所有的玩具都放进盒子里”就好了。 内部迭代的好处:第一、你大儿子可以左手拿一个球,右手拿一个积木,第二、你大儿子可以选择先拿离盒子比较近的东西,然后再拿别的。)
流操作
java.util.stream.Stream中的stream借口定义了许多操作。他们可以分为两大类:中间操作和终端操作。
中间操作:
如filter或sorted等中间操作会返回另一个流,这让多个操作可以连接起来形成一个查询,除非流水线上触发一个终端操作,否则中间操作不会执行任何处理。
终端操作:
如count,foreach终端操作会从流的流水线生成结果,其结果是任何不适流的值,比如List、Integer,甚至void。例如,下面的流水线中forEach是一个返回void的终端操作。
menu.stream().forEach(System.out::println);
获取所有热量高于300的菜去掉重复值的数量
long count = menu.stream().filter(s->s.getCalories()>300).distinct().count();
使用流
使用流一般包括三件事:一个数据源(执行查询)、一个中间操作连(形成一条流水线)、一个终端操作(执行流水线,并生成结果)。
到目前为止见过的流的 中间操作有:
filter:用于过滤集合 Lambda使用的函数式接口是Predicate<T> 函数描述符是T -> boolean
map:用于映射到一个新的类型 函数式接口是Function<T,R> 函数描述符是 T -> R
limit: 用于截断流 获取前几个
sorted:用于排序流 函数式接口是Comparator<T> 函数描述符是 (T,T) -> int
distinct: 用户去重
终端操作有:
forEach: 消费流中的每个元素并对其应用lambda表达式
count: 返回流中元素的个数,long
collect: 把流规约成一个集合,比如List、Map、Integer等
小结:
1.流是从支持数据处理操作的源生成的一系列元素
2.流利用内部迭代:迭代通过filter、map、sorted等操作被抽象掉了
3.流操作有两类:中间操作和终端操作
4.filter和map等中间操作会返回一个流,并可以连接一起,可以用他们来设置一条流水线,但不会生成任何结果
5.forEach和count等终端操作会返回一个非流的值,并处理流水线以返回结果
6.流中的元素是按需计算的
Java 8 (3) Stream 流 - 简介的更多相关文章
- Java 8创建Stream流的5种方法
不知不觉间,Java已经发展到13了,来不及感慨时间过得真的太快了,来不及学习日新月异的技术更新,目前大多数公司还是使用的JDK8版本,一方面是版本的稳定,另一方面是熟悉,所以很多公司都觉得不升级也挺 ...
- java中的Stream流
java中的Stream流 说到Stream便容易想到I/O Stream,而实际上,谁规定"流"就一定是"IO流"呢?在Java 8中,得益于Lambda所带 ...
- Java学习:Stream流式思想
Stream流 Java 8 API添加了一种新的机制——Stream(流).Stream和IO流不是一回事. 流式思想:像生产流水线一样,一个操作接一个操作. 使用Stream流的步骤:数据源→转换 ...
- 双层for循环用java中的stream流来实现
//双重for循环for (int i = 0; i < fusRecomConfigDOList.size(); i++) { for (int j = 0; j < fusRecomC ...
- Java 8 (5) Stream 流 - 收集数据
在前面已经使用过collect终端操作了,主要是用来把Stream中的所有元素结合成一个List,在本章中,你会发现collect是一个归约操作,就像reduce一样可以接受各种做法作为参数,将流中的 ...
- Java 8 (6) Stream 流 - 并行数据处理与性能
在Java 7之前,并行处理集合非常麻烦.首先你要明确的把包含数据的数据结构分成若干子部分,然后你要把每个子部分分配一个独立的线程.然后,你需要在恰当的时候对他们进行同步来避免竞争,等待所有线程完成. ...
- Java 8 (4) Stream 流 - 使用
在本节中将介绍Stream API支持的许多操作,这些操作可以完成更复杂的数据查询,如筛选.切片.映射.查找.匹配和归约.还有一些特殊的流如:数值流.来自文件和数组等多种来源的流. 筛选和切片 1.用 ...
- java 数据类型:Stream流 对象转换为集合collect(Collectors.toList()) ;常用方法count,limit,skip,concat,max,min
集合对象.stream() 获取流对象,对元素批处理(不改变原集合) 集合元素循环除了用for循环取出,还有更优雅的方式.forEach 示例List集合获取Stream对象进行元素批处理 impor ...
- Java8 Stream流API常用操作
Java版本现在已经发布到JDK13了,目前公司还是用的JDK8,还是有必要了解一些JDK8的新特性的,例如优雅判空的Optional类,操作集合的Stream流,函数式编程等等;这里就按操作例举一些 ...
随机推荐
- [bzoj1188][HNOI2007]分裂游戏_博弈论
分裂游戏 bzoj-1188 HNOI-2007 题目大意:题目链接. 注释:略. 想法: 我们发现如果一个瓶子内的小球个数是奇数才是有效的. 所以我们就可以将问题变成了一个瓶子里最多只有一个球球. ...
- Codeforces 803F(容斥原理)
题意: 给n个正整数,求有多少个GCD为1的子序列.答案对1e9+7取模. 1<=n<=1e5,数字ai满足1<=ai<=1e5 分析: 设f(x)表示以x为公约数的子序列个数 ...
- MyBatis实体属性与表的字段不对应的解决方案
1.通过在查询的SQL语句中定义字段名的别名,让字段名的别名和实体类的属性名一致,这样就可以表的字段名和实体类的属性名一一对应上,这种方式是通过在SQL语句中定义别名来解决字段名和属性名的映射关系的. ...
- Windows 10 S中的Device Guard详解(上篇)
本文探讨Windows 10 S(下称Win10S)中的Device Guard(设备保护,下称DG).我将提取策略,并弄清楚在默认Win10S系统上可以和不可以运行什么.我将在下一篇文章中介绍在不安 ...
- import与require的区别
载入一个模块import() 与 require() 功能相同,但具有一定程度的自动化特性.假设我们有如下的目录结构:~~~app/app/classes/app/classes/MyClass.lu ...
- 第6章1节《MonkeyRunner源代码剖析》Monkey原理分析-事件源-事件源概览
在上一章中我们有简要的介绍了事件源是怎么一回事.可是并没有进行详细的描写叙述.那么往下的这几个小节我们就须要把这方面的知识给补充完整. 这一节我们先主要环绕MonkeySourceNetwork这个事 ...
- ubuntu上跑python连接pg,报错 ImportError: No module named psycopg2
ubuntu上跑python连接pg,报错 ImportError: No module named psycopg2 root@pgproxy1:~# python /home/zxw/PGWri ...
- cocos2d-x 3.6版连连看版本号控制
为了以后的开发和管理.源代码开发必须要使用版本号控制.我们当然选择git来做版本号控制了. 假设你在终端输入git,提示不是一个命令的话.那就说明你的机器没有安装git工具.那就安装一个,百度之有非常 ...
- python爬虫实践
模拟登陆与文件下载 爬取http://moodle.tipdm.com上面的视频并下载 模拟登陆 由于泰迪杯网站问题,测试之后发现无法用正常的账号密码登陆,这里会使用访客账号登陆. 我们先打开泰迪杯的 ...
- for in、for和EnumerateObjectsUsingBlock遍历的区别
1.对于集合中对象数很多的情况下,for in 的遍历速度非常之快,但小规模的遍历并不明显(还没普通for循环快) 2. 如果在for in 循环里,对这个数组进行了修改的话,无论是增,删,修改数组元 ...