乐字节-Java8核心特性实战之Stream(流)


一、流的概念
- 源-流会使用一个提供数据的源,如集合、数组或输入|输出资源。
- 元素序列-就像集合一样,流也提供了一个接口,可以访问特定元素类型的一组有序值。
- 数据处理操作-流的数据处理功能支持类似于数据库的操作(数据筛选、过滤、排序等操作)。
- 流水线-多个流操作本身会返回一个流,多个操作就可以链接起来,成为数据处理的一道流水线。
二、流 & 集合
- 计算的时机


- 外部迭代与内部迭代


三、流操作过程


- 创建
- 中间处理
- 终止流
四、流的创建

4.1 集合创建流
- stream() − 为集合创建串行流。
- parallelStream() − 为集合创建并行流。
public static void main(String[] args) {
/**
* 定义集合l1 并为集合创建串行流
*/
List<String> l1 = Arrays.asList("周星驰", "周杰伦", "周星星", "周润发");
// 返回串行流
l1.stream();
// 返回并行流
l1.parallelStream();
}
4.2 值创建流
//值创建流 生成一个字符串流
Stream<String> stream = Stream.of("java8", "Spring", "SpringCloud");
stream.forEach(System.out::println);
4.3 数组创建流
- Arrays.stream(T[ ])
- Arrays.stream(int[ ])
- Arrays.stream(double[ ])
- Arrays.stream(long[ ])
/**
* 这里以int 为例 long double 不再举例
*/
Stream stream = Arrays.stream(Arrays.asList(10, 20, 30, 40).toArray());
// 根据数组索引范围创建指定Stream
stream = Arrays.stream(Arrays.asList(10, 20, 30, 40).toArray(), 0, 2);
4.4 文件生成流
stream = Files.lines(Paths.get("C:\\java\\jdbc.properties"));
System.out.println(stream.collect(Collectors.toList()));
// 指定字符集编码
stream = Files.lines(Paths.get("C:\\java\\jdbc.properties"), Charset.forName("utf-8"));
System.out.println(stream.collect(Collectors.toList()));
4.5 函数生成流
- iterate : 依次对每个新生成的值应用函数
- generate :接受一个函数,生成一个新的值
// 重100 开始 生成偶数流
Stream.iterate(100, n -> n + 2);
// 产生1-100 随机数
Stream.generate(() ->(int) (Math.random() * 100 + 1));
五、流中间操作


@Data
public class Order {
// 订单id
private Integer id;
// 订单用户id
private Integer userId;
// 订单编号
private String orderNo;
// 订单日期
private Date orderDate;
// 收货地址
private String address;
// 创建时间
private Date createDate;
// 更新时间
private Date updateDate;
// 订单状态 0-未支付 1-已支付 2-待发货 3-已发货 4-已接收 5-已完成
private Integer status;
// 是否有效 1-有效订单 0-无效订单
private Integer isValid;
//订单总金额
private Double total;
} Order order01 = new Order(1, 10, "20190301",
new Date(), "上海市-浦东区", new Date(), new Date(), 4, 1, 100.0);
Order order02 = new Order(2, 30, "20190302",
new Date(), "北京市四惠区", new Date(), new Date(), 1, 1, 2000.0);
Order order03 = new Order(3, 20, "20190303",
new Date(), "北京市-朝阳区", new Date(), new Date(), 4, 1, 500.0);
Order order04 = new Order(4, 40, "20190304",
new Date(), "北京市-大兴区", new Date(), new Date(), 4, 1, 256.0);
Order order05 = new Order(5, 40, "20190304",
new Date(), "上海市-松江区", new Date(), new Date(), 4, 1, 1000.0);
ordersList = Arrays.asList(order01, order02, order03, order04, order05);
六、筛选&切片
筛选有效订单
// 过滤有效订单
ordersList.stream().filter((order) -> order.getIsValid() == 1)
.forEach(System.out::println);
筛选有效订单 取第一页数据(每页2条记录)
// 过滤有效订单 取第一页数据(每页2条记录)
ordersList.stream().filter((order) -> order.getIsValid() == 1)
.limit(2)
.forEach(System.out::println);
筛选订单集合有效订单 取最后一条记录
// 过滤订单集合有效订单 取最后一条记录
ordersList.stream().filter((order) -> order.getIsValid() == 1)
.skip(ordersList.size() - 2) // 跳过前ordersList.size()-2 记录
.forEach(System.out::println);
筛选有效订单 取第3页数据(每页2条记录)
// 过滤有效订单 取第3页数据(每页2条记录) 并打印到控制台
ordersList.stream().filter((order) -> order.getIsValid() == 1)
.skip((3 - 1) * 2)
.limit(2)
.forEach(System.out::println);
筛选无效订单去除重复订单号记录
// 过滤无效订单 去除重复订单号记录 重写Order equals 与 hashCode 方法
ordersList.stream().filter((order) -> order.getIsValid() == 0)
.distinct()
.forEach(System.out::println);
七、映射
过滤有效订单,获取所有订单编号
//过滤有效订单,获取所有订单编号
ordersList.stream().filter((order) -> order.getIsValid() == 1)
.map((order) -> order.getOrderNo())
.forEach(System.out::println);
过滤有效订单 ,并分离每个订单下收货地址市区信息
ordersList.stream().map(o -> o.getAddress()
.split("-"))
.flatMap(Arrays::stream)
.forEach(System.out::println);
八、排序
- 过滤有效订单 根据用户id 进行排序
//过滤有效订单 根据用户id 进行排序
ordersList.stream().filter((order) -> order.getIsValid() == 1)
.sorted((o1, o2) -> o1.getUserId() - o2.getUserId())
.forEach(System.out::println); //或者等价写法
ordersList.stream().filter((order) -> order.getIsValid() == 1)
.sorted(Comparator.comparingInt(Order::getUserId))
.forEach(System.out::println);
- 过滤有效订单 ,根据订单状态排序 如果订单状态相同根据订单创建时间排序
//过滤有效订单 如果订单状态相同 根据订单创建时间排序 反之根据订单状态排序
ordersList.stream().filter((order) -> order.getIsValid() == 1)
.sorted((o1, o2) -> {
if (o1.getStatus().equals(o2.getStatus())) {
return o1.getCreateDate().compareTo(o2.getCreateDate());
} else {
return o1.getStatus().compareTo(o2.getStatus());
}})
.forEach(System.out::println); // 等价形式
ordersList.stream().filter((order) -> order.getIsValid() == 1)
.sorted(Comparator.comparing(Order::getCreateDate)
.thenComparing(Comparator.comparing(Order::getStatus)))
.forEach(System.out::println);
九、流的终止操作


十、查找与匹配
筛选有效订单 匹配是否全部为已支付订单
// 筛选有效订单 匹配是否全部为已支付订单
System.out.println("allMatch匹配结果:" +
ordersList.stream()
.filter((order) -> order.getIsValid() == 1)
.allMatch((o) -> o.getStatus() != 0)
);
筛选有效订单 匹配是否存在未支付订单
// 筛选有效订单 匹配是否存在未支付订单
System.out.println("anyMatch匹配结果:" +
ordersList.stream()
.filter((order) -> order.getIsValid() == 1)
.anyMatch((o) -> o.getStatus() == 0)
);
筛选有效订单 全部未完成订单
// 筛选有效订单 全部未完成订单
System.out.println("noneMatch匹配结果:" +
ordersList.stream()
.filter((order) -> order.getIsValid() == 1)
.noneMatch((o) -> o.getStatus() == 5)
);
筛选有效订单 返回第一条订单
// 筛选有效订单 返回第一条订单
System.out.println("findAny匹配结果:"+
ordersList.stream()
.filter((order) -> order.getIsValid() == 1)
.findAny()
.get()
);
筛选所有有效订单 返回订单总数
// 筛选所有有效订单 返回订单总数
System.out.println("count结果:" +
ordersList.stream()
.filter((order) -> order.getIsValid() == 1)
.count()
);
筛选有效订单 返回金额最大订单金额
// 筛选有效订单 返回金额最大订单金额
System.out.println("订单金额最大值:" +
ordersList.stream()
.filter((order) -> order.getIsValid() == 1)
.map(Order::getTotal)
.max(Double::compare)
.get()
);
筛选有效订单 返回金额最小订单金额
// 筛选有效订单 返回金额最小订单金额
System.out.println("订单金额最小值:" +
ordersList.stream()
.filter((order) -> order.getIsValid() == 1)
.map(Order::getTotal)
.min(Double::compare)
.get()
);
十一、归约&收集
11.1 归约
- 计算有效订单总金额
// 计算有效订单总金额
System.out.println("有效订单总金额:" +
ordersList.stream()
.filter((order) -> order.getIsValid() == 1)
.map(Order::getTotal)
.reduce(Double::sum)
.get()
);
11.2 Collector数据收集
11.3 集合收集
- 筛选所有有效订单 并收集订单列表
// 筛选所有有效订单并收集订单列表
ordersList.stream()
.filter((order) -> order.getIsValid() == 1)
.collect(Collectors.toList())
.forEach(System.out::println);
- 筛选所有有效订单并收集订单号与订单金额
// 筛选所有有效订单 并收集订单号 与 订单金额
Map<String,Double> map=ordersList.stream().filter((order) -> order.getIsValid() == 1).
collect(Collectors.toMap(Order::getOrderNo, Order::getTotal));
// java8 下对map进行遍历操作 如果 Map的Key重复,会报错
map.forEach((k,v)->{
System.out.println("k:"+k+":v:"+v);
});
十二、汇总


- 筛选所有有效订单 返回订单总数
System.out.println("count结果:"+
ordersList.stream()
.filter((order) -> order.getIsValid() == 1)
.collect(Collectors.counting())
);
System.out.println("count结果:"+
ordersList.stream()
.filter((order) -> order.getIsValid() == 1)
.count()
);
- 返回订单总金额
System.out.println("订单总金额:"+
ordersList.stream()
.filter((order) -> order.getIsValid() == 1)
.collect(Collectors.summarizingDouble(Order::getTotal))
);
System.out.println("订单总金额:"+
ordersList.stream()
.filter((order) -> order.getIsValid() == 1)
.mapToDouble(Order::getTotal)
.sum()
);
System.out.println("订单总金额:"+
ordersList.stream()
.filter((order) -> order.getIsValid() == 1)
.map(Order::getTotal)
.reduce(Double::sum)
.get()
);
- 返回用户id=20 有效订单平均每笔消费金额
System.out.println("用户id=20 有效订单平均每笔消费金额:"+
ordersList.stream()
.filter((order) -> order.getIsValid() == 1)
.filter((order -> order.getUserId()==20))
.collect(Collectors.averagingDouble(Order::getTotal))
);
System.out.println("用户id=20 有效订单平均每笔消费金额:"+
ordersList.stream()
.filter((order) -> order.getIsValid() == 1)
.filter((order -> order.getUserId()==20))
.mapToDouble(Order::getTotal)
.average()
.getAsDouble()
);
System.out.println("用户id=20 有效订单平均每笔消费金额:"+
ordersList.stream()
.filter((order) -> order.getIsValid() == 1)
.filter((order -> order.getUserId()==20))
.collect(Collectors.summarizingDouble(Order::getTotal))
.getAverage()
);
- 筛选所有有效订单 并计算订单总金额
System.out.println("订单总金额:"+
ordersList.stream()
.filter((order) -> order.getIsValid() == 1)
.collect(Collectors.summingDouble(Order::getTotal))
);
十三、最值
筛选所有有效订单 并计算最小订单金额
System.out.println("最小订单金额:"+
ordersList.stream()
.filter((order) -> order.getIsValid() == 1)
.map(Order::getTotal)
.collect(Collectors.minBy(Double::compare))
);
筛选所有有效订单 并计算最大订单金额
// 筛选所有有效订单 并计算最大订单金额
System.out.println("最大订单金额:"+
ordersList.stream()
.filter((order) -> order.getIsValid() == 1)
.map(Order::getTotal)
.collect(Collectors.maxBy(Double::compare))
);
十四、分组&分区
14.1 分组
- 根据有效订单支付状态进行分组操作
Map<Integer,List<Order>> g01=ordersList.stream()
.filter((order) -> order.getIsValid() == 1)
.collect(Collectors.groupingBy(Order::getStatus));
g01.forEach((status,order)->{
System.out.println("----------------");
System.out.println("订单状态:"+status);
order.forEach(System.out::println);
});
- 筛选有效订单,根据用户id 和 支付状态进行分组
Map<Integer,Map<String,List<Order>>> g02= ordersList.stream()
.filter((order) -> order.getIsValid() == 1)
.collect(Collectors.groupingBy(Order::getUserId,
Collectors.groupingBy((o)->{
if(o.getStatus()==0){
return "未支付";
}else if (o.getStatus()==1){
return "已支付";
}else if (o.getStatus()==2){
return "待发货";
}else if (o.getStatus()==3){
return "已发货";
}else if (o.getStatus()==4){
return "已接收";
} else{
return "已完成";
}
}
))
);
g02.forEach((userId,m)->{
System.out.println("用户id:"+userId+"-->有效订单如下:");
m.forEach((status,os)->{
System.out.println("状态:"+status+"---订单列表如下:");
os.forEach(System.out::println);
});
System.out.println("-----------------------");
});
14.2 分区
- 分区操作-筛选订单金额>1000 的有效订单
Map<Boolean,List<Order>> g03= ordersList.stream()
.filter((order) -> order.getIsValid() == 1)
.collect(Collectors.partitioningBy((o)->o.getTotal()>1000));
g03.forEach((b,os)->{
System.out.println("分区结果:"+b+"--列表结果:");
os.forEach(System.out::println);
});
- 拼接操作-筛选有效订单并进行拼接
String orderStr=ordersList.stream()
.filter((order) -> order.getIsValid() == 1)
.map(Order::getOrderNo)
.collect(Collectors.joining(","));
System.out.println(orderStr);
十五、流的应用
乐字节-Java8核心特性实战之Stream(流)的更多相关文章
- 乐字节-Java8核心特性实战之Lambda表达式
大家好,小乐又来给大家分享Java8核心特性了,上一篇文章是<乐字节|Java8核心实战-接口默认方法>,这次就来讲Java8核心特征之Lambda表达式. Java8 引入Lambda表 ...
- 乐字节-Java8核心特性实战-接口默认方法
JAVA8已经发布很久,是自java5(2004年发布)之后Oracle发布的最重要的一个版本.其中包括语言.编译器.库.工具和JVM等诸多方面的新特性,对于国内外互联网公司来说,Java8是以后技术 ...
- 乐字节-Java8核心特性实战之函数式接口
什么时候可以使用Lambda?通常Lambda表达式是用在函数式接口上使用的.从Java8开始引入了函数式接口,其说明比较简单:函数式接口(Functional Interface)就是一个有且仅有一 ...
- 乐字节Java8核心特性之方法引用
大家好,我是乐字节的小乐,上一次我们说到了Java8核心特性之函数式接口,接下来我们继续了解Java8又一核心特性--方法引用. Java8 中引入方法引用新特性,用于简化应用对象方法的调用, 方法引 ...
- 乐字节Java8核心特性之Optional类
大家好啊,上次小乐给大家介绍了Java8最最重要的一个特性——Stream流,点击可以回顾哦. Optional<T>类(java.util.Optional)是一个容器类,代表一个值存在 ...
- 乐字节-Java8新特性-接口默认方法
总概 JAVA8 已经发布很久,而且毫无疑问,java8是自java5(2004年发布)之后的最重要的版本.其中包括语言.编译器.库.工具和JVM等诸多方面的新特性. Java8 新特性列表如下: 接 ...
- 乐字节-Java8新特性之Base64和重复注解与类型注解
上一篇小乐给大家说了<乐字节-Java8新特性之Date API>,接下来小乐继续给大家说一说Java8新特性之Base64和重复注解与类型注解. 一.Base64 在Java 8中,内置 ...
- 乐字节-Java8新特性-接口默认方法之Stream流(下)
接上一篇:<Java8新特性之stream>,下面继续接着讲Stream 5.流的中间操作 常见的流的中间操作,归为以下三大类:筛选和切片流操作.元素映射操作.元素排序操作: 操作 描述 ...
- 乐字节-Java8新特性之Stream流(上)
上一篇文章,小乐给大家介绍了<Java8新特性之方法引用>,下面接下来小乐将会给大家介绍Java8新特性之Stream,称之为流,本篇文章为上半部分. 1.什么是流? Java Se中对于 ...
随机推荐
- DOM相关操作的案例
1 . 模态框案例 示例 : 打开网页时有一个普通的按钮,点击当前按钮显示一个背景图,中心并弹出一个弹出框,点击X的时候会关闭当前的模态框 <!DOCTYPE html> <htm ...
- Spring Boot2.0之 原理—创建内置Tomcat容器
前面所述的https://www.cnblogs.com/toov5/p/9823728.html 中的第一条先不赘述了,就是玩了maven 重点介绍后两条 首先内置Tomcat: SpringBoo ...
- 国画经典之梅花PSD素材
国画经典之梅花图片PSD素材,由huiyi8素材网提供. 地址:http://www.huiyi8.com/meihua/
- RQNOJ 429 词链:单调栈
题目链接:https://www.rqnoj.cn/problem/429 题意: 如果一张由一个词或多个词组成的表中,每个单词(除了最后一个)都是排在它后面的单词的前缀,则称此表为一个词链. 如:i ...
- mysql七:视图、触发器、事务、存储过程、函数
阅读目录 一 视图 二 触发器 三 事务 四 存储过程 五 函数 六 流程控制 一 视图 视图是一个虚拟表(非真实存在),其本质是[根据SQL语句获取动态的数据集,并为其命名],用户使用时只需使用[名 ...
- myBatis 如何接受 返回count(*),sum()得到的int值
<select id="selectRemainder" resultType="java.lang.Integer"> SELECT SUM(aw ...
- spring2.5和struts1.3.8整合
第一步:导入对应jar文件 第二步: 1.在web容器中实例化spring容器 <!-- 指定spring的配置文件,默认从web根目录寻找配置文件,我们可以通过spring提供的classpa ...
- listen 78
Struggling Young Readers Like Kindles Kindles, Nooks and other e-readers catch flack for threatening ...
- hashlib加密
一.hashlib的基本组成: 1.hashlib库是python3的标准库,主要用于数据的加密,以下是hashlib的方法及属性. >>> import hashlib>&g ...
- AtCoder Regular Contest E - Or Plus Max
Time limit : 2sec / Memory limit : 1024MB Score : 700 points Problem Statement There is an integer s ...