惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Recent Announcements
Recent Announcements
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Last Week in AI
Last Week in AI
Scott Helme
Scott Helme
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
L
LINUX DO - 最新话题
S
Security @ Cisco Blogs
Webroot Blog
Webroot Blog
S
Security Affairs
H
Hacker News: Front Page
TaoSecurity Blog
TaoSecurity Blog
W
WeLiveSecurity
G
GRAHAM CLULEY
T
Tenable Blog
Schneier on Security
Schneier on Security
S
Securelist
Cyberwarzone
Cyberwarzone
P
Privacy International News Feed
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
S
Schneier on Security
Hacker News - Newest:
Hacker News - Newest: "LLM"
Recent Commits to openclaw:main
Recent Commits to openclaw:main
O
OpenAI News
N
News and Events Feed by Topic
AWS News Blog
AWS News Blog
C
Cisco Blogs
T
Threat Research - Cisco Blogs
S
Secure Thoughts
大猫的无限游戏
大猫的无限游戏
C
Check Point Blog
The GitHub Blog
The GitHub Blog
G
Google Developers Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
美团技术团队
Martin Fowler
Martin Fowler
Microsoft Security Blog
Microsoft Security Blog
L
LangChain Blog
Apple Machine Learning Research
Apple Machine Learning Research
爱范儿
爱范儿
D
DataBreaches.Net
博客园_首页
MyScale Blog
MyScale Blog
博客园 - 叶小钗
博客园 - 三生石上(FineUI控件)
P
Proofpoint News Feed
J
Java Code Geeks
SecWiki News
SecWiki News
P
Palo Alto Networks Blog
Know Your Adversary
Know Your Adversary
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org

犀利豆的博客

《SRE google 运维解密》读书笔记 (六) 《SRE google 运维解密》读书笔记 (五) 《SRE google 运维解密》读书笔记 (四) 《SRE google 运维解密》读书笔记 (三) 《SRE google 运维解密》读书笔记 (二) 《SRE google 运维解密》读书笔记 (一) 2021 总结 终于有一个 Java 可以用的微信机器人了 Vertx入门到实战—实现钉钉机器人内网穿透代理 钉钉机器人回调内网穿透代理--使用篇 周末补习(一)trie 树 那些有趣的代码(三)--勤俭持家的 ArrayList 那些有趣的代码(二)--偏不听父母话的 Tomcat 类加载器 那些有趣的代码(一)--有点萌的 Tomcat 的线程池 从需求第三定律说起--为什么知乎的回答质量下降了 如何利用 Spring Hibernate 高级特性设计实现一个权限系统 居然有人能忘记吃饭?写个微信机器人提醒他 我的2018年总结 从 LongAdder 中窥见并发组件的设计思路 徒手撸框架--实现 RPC 远程调用 我的写作工具链 Java 渲染 docx 文件,并生成 pdf 加水印 撸码的福音--变量名生成器的实现 Raft 协议学习笔记 dubbo 源码学习(一)开篇 Redis 命令的执行过程 Redis 中的事件驱动模型 Redis 数据库、键过期的实现 Redis 的基础数据结构(三)对象 Redis 的基础数据结构(二) 整数集合、跳跃表、压缩列表 Redis 的基础数据结构(一) 可变字符串、链表、字典 线程池 execute() 的工作逻辑 JAVA 中的 CAS 徒手撸框架--高并发环境下的请求合并 徒手撸框架--实现Aop 徒手撸框架--实现IoC 2017个人总结 最近遇到的几个问题集合 Redis RedLock 完美的分布式锁么? JAVA 8入门(一)Lambda表达式 有道 Alfred Workflow 威力加强版 Kafka实现原理笔记 《交易系统:更新与跨越》读后笔记 Netty-Apns接入实现 Future研究 Hystrix入门研究 Redis实现分布式锁
JAVA 8入门(二)流
Zhengxin Diao · 2017-10-25 · via 犀利豆的博客

1.简单使用

书接上回,我们这一讲要讨论 JAVA 8 的新的 API 流。如果我们有这样一个需求,需要挑选出菜谱里面卡路里小于1000,且卡路里排名前三的菜品的名称。

如果使用JAVA 7的传统写法我们应该这样写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public List<String> findDish(List<Dish> menu){
List<Dish> lowCaloricDishes = new ArrayList<>();
for (Dish dish : lowCaloricDishes) {
if(dish.getCalories() < 1000 ){
lowCaloricDishes.add(dish);
}
}

Collections.sort(lowCaloricDishes, new Comparator<Dish>() {
@Override
public int compare(Dish o1, Dish o2) {
return Integer.compare(o1.getCalories(),o2.getCalories());
}
});

List<Dish> result = lowCaloricDishes.subList(0,3);
List<String> resultName = new ArrayList<>();

for (Dish dish : result) {
resultName.add(dish.getName());
}
return resultName;
}

通过上面的例子我们可以看到我们使用了很多的中间变量,来存储中介结果,lowCaloricDishes、result、resultName。相当繁琐。如果我们使用 JAVA 8的流的方式来实现代码是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14

public List<String> findDishWithSteam(List<Dish> menu){


List<String> resultName = menu.stream()
.filter(dish -> dish.getCalories()<1000)
.sorted(Comparator.comparing(Dish::getCalories))
.limit(3)
.map(Dish::getName)
.collect(Collectors.toList());

return resultName;
}

如果我们把 steam() 变换为 parallelStream(),整个操作就变成并行的。代码十分优雅,想到每天我们处理那么多的集合,反正我已经迫不及待的想使用上`JAVA 8了。

2. 流的定义

到底什么是流?书上给的定义是 “从支持数据处理操作的源生成的元素序列”

  • 元素序列 和集合一样,我们可以理解为是一堆有序的值。但是集合侧重的是数据,流侧重的是计算。
  • 源 流会使用一个提供数据的源。比如 menu.stream()中,meun就是这个流的源。
  • 数据处理操作 流的数据处理功能类似,数据库的操作,同时也支持函数式编程中的操作。

我们看看接口java.util.stream.Stream都有一些什么方法:

stea

我们可以看到,之前我们在上一个例子里面使用的方法,filter()sorted()limit()map() 的返回值也是一个流Stream,也就是说我们可以,把所有的操作串起来。这个是流的一个特点流水线

还有一个特点就是内部迭代,与集合的迭代不同,流的迭代不是显式的迭代。

3. 流的基本操作

1. 筛选和切片

  1. 筛选filter()

    所谓筛选就是找出符合条件的元素,filter()接受一个返回boolean类型的函数。
    比如:

    1
    filter(dish -> dish.getCalories()<1000)
  2. 去重distinct()

    去重的方法我们可以类比SQL 语句中的 distinct

  3. 截断limit()

    同样类似 SQL里面的 limit,接受一个 Long 值。返回流中的前n个元素。

  4. 跳过skip()

    跳过前n个元素。很好理解

2. 映射

  1. map()

    map对流中的每一个元素应用函数,可以理解为将元素转化为另一个元素。

    1
    .map(Dish::getName)
  2. flatmap()

    flatmap方法就是把流中的每一个元素都装换为另外一个流,然后合并为一个流。

    1
    2
    3
    4
    5

    List<List<String>> lists = new ArrayList<>();
    lists.add(Arrays.asList("apple", "click"));
    lists.add(Arrays.asList("boss", "dig", "qq", "vivo"));
    lists.add(Arrays.asList("c#", "biezhi"));

找出所有大于两个字符的元素:

1
2
3
4
lists.stream()
.flatMap(Collection::stream)
.filter(str -> str.length() > 2)
.count();

3. 查找匹配

match、anyMatch、allMatch、noneMatch
以上方法都能返回一个boolean类型。

1
boolean hasLowCalories = mune.stream().anyMatch(dish -> dish.getCalories()<1000)

4. 归约

reduce(T,BinaryOperator<T>)

reduce 操作是 反复结合每一个元素,直到流被归约成一个值。其中:

  • T 指的是初始值;
  • BinaryOperator<T> 两个元素结合起来获得一个元素,举个例子:
    Lamdba: (a,b)-> a + b

所以给定一个 List<Integer> 计算出和所有int 的和:

1
int sum = list.stream().reduce(0,(a,b)-> a + b);

或者:

1
int sum = list.stream().reduce(0,Integer::sum);

5. 收集数据

一顿操作之后,我们需要把数据收集起来。就需要使用collect()方法。

1
2
Map<String, Integer> map = meun.stream()
.collect(Collectors.toMap(Dish::getName, Dish::getCalories));