1、流的概念java
Java Se中对于流的操做有输入输出IO流,而Java8中引入的Stream 属于Java API中的一个新成员,它容许你以声明性方式处理数据集合,Stream 使用一种相似 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。 注意这里的流操做能够看作是对集合数据的处理。
最后,若是你们若是在自学遇到困难,想找一个java的学习环境,能够加入咱们的java学习圈,点击我加入吧,会节约不少时间,减小不少在学习中遇到的难题。sql
简单来讲,流是一种数据渠道,用于操做数据源(集合、数组、文件等)所生产的元素序列。数据库
源-流会使用一个提供数据的源,如集合、数组或输入|输出资源。
从有序集生成流时会保留原有的顺序。由列表生成的流,其元素顺序与列表一致编程
元素序列-就像集合同样,流也提供了一个接口,能够访问特定元素类型的一组有序值。
数据处理操做-流的数据处理功能支持相似于数据库的操做(数据筛选、过滤、排序等操做)。
流水线-多个流操做自己会返回一个流,多个操做就能够连接起来,成为数据处理的一道流水线。
2、流 & 集合数组
计算的时机架构
集合中数据都是计算完毕的数据,例如从数据库中查询用户记录 按用户id 查询 降序排列 而后经过list 接收用户记录,数据的计算已在放入集合前完成。dom
流中数据按需计算,按照使用者的须要计算数据,例如经过搜索引擎进行搜索,搜索出来的条目并非所有呈现出来的,并且先显示最符合的前 10 条或者前 20 条,只有在点击 “下一页” 的时候,才会再输出新的 10 条。流的计算也是这样,当用户须要对应数据时,Stream 才会对其进行计算处理。函数式编程
外部迭代与内部迭代函数
Java互联网架构-一篇文精通JDK8lambada表达式性能
Java互联网架构-一篇文精通JDK8lambada表达式
把集合比做一个工厂的仓库的话,一开始工厂硬件比较落后,要对货物做什么修改,此时工人亲自走进仓库对货物进行处理,有时候还要将处理后的货物转运到另外一个仓库中。此时对于开发者来讲须要亲自去作迭代,一个个地找到须要的货物,并进行处理,这叫作外部迭代。
当工厂发展起来后,配备了流水线做业,工厂只要根据需求设计出相应的流水线,而后工人只要把货物放到流水线上,就能够等着接收成果了,并且流水线还能够根据要求直接把货物输送到相应的仓库。这就叫作内部迭代,流水线已经帮你把迭代给完成了,你只须要说要干什么就能够了(即设计出合理的流水线)。至关于 Java8 引入的Stream 对数据的处理实现了”自动化”操做。
3、流操做过程
Java互联网架构-一篇文精通JDK8lambada表达式
整个流操做就是一条流水线,将元素放在流水线上一个个地进行处理。须要注意的是:不少流操做自己就会返回一个流,因此多个操做能够直接链接起来, 以下图这样,操做能够进行链式调用,而且并行流还能够实现数据流并行处理操做。
Java互联网架构-一篇文精通JDK8lambada表达式
总的来讲,流操做过程分为三个阶段:
建立
借助数据源建立流对象
中间处理
筛选、切片、映射、排序等中间操做
终止流
匹配、汇总、分组等终止操做
4、流的建立
对流操做首先要建立对应的流,流的建立集中形式以下:
Java互联网架构-一篇文精通JDK8lambada表达式
4.1 集合建立流
在 Java 8 中, 集合接口有两个方法来生成流:
stream() − 为集合建立串行流。
parallelStream() − 为集合建立并行流。
示例代码以下:
Java互联网架构-一篇文精通JDK8lambada表达式
public static void main(String[] args) {
/**
*/
List<String> l1 = Arrays.asList("周星驰", "周杰伦", "周星星", "周润发");
// 返回串行流
l1.stream();
// 返回并行流
l1.parallelStream();
}
Java互联网架构-一篇文精通JDK8lambada表达式
上述操做获得的流是经过原始数据转换过来的流,除了这种流建立的基本操做外,对于流的建立还有如下几种方式。
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[ ])
/**
*/
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:javajdbc.properties"));
System.out.println(stream.collect(Collectors.toList()));
// 指定字符集编码
stream = Files.lines(Paths.get("C:javajdbc.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));
5、流中间操做
流的中间操做分为三大类:筛选切片、映射、排序。
筛选切片:相似sql 中where 条件判断的意思,对元素进行筛选操做
映射:对元素结果进行转换 ,优势相似select 字段意思或者对元素内容进行转换处理
排序:比较好理解 ,经常使用sql 中按字段升序 降序操做
Java互联网架构-一篇文精通JDK8lambada表达式
Java互联网架构-一篇文精通JDK8lambada表达式
流中间操做数据准备(这里以订单数据处理为例)
Java互联网架构-一篇文精通JDK8lambada表达式
@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);
Java互联网架构-一篇文精通JDK8lambada表达式
6、筛选&切片
筛选有效订单
// 过滤有效订单
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);
7、映射
过滤有效订单,获取全部订单编号
//过滤有效订单,获取全部订单编号
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);
8、排序
过滤有效订单 根据用户id 进行排序
Java互联网架构-一篇文精通JDK8lambada表达式
//过滤有效订单 根据用户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);
Java互联网架构-一篇文精通JDK8lambada表达式
过滤有效订单 ,根据订单状态排序 若是订单状态相同根据订单建立时间排序
Java互联网架构-一篇文精通JDK8lambada表达式
//过滤有效订单 若是订单状态相同 根据订单建立时间排序 反之根据订单状态排序
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);
Java互联网架构-一篇文精通JDK8lambada表达式
9、流的终止操做
终止操做会从流的流水线生成结果。其结果是任何不是流的值,好比常见的List、 Integer,甚 至void等结果。对于流的终止操做,分为如下三类:
Java互联网架构-一篇文精通JDK8lambada表达式
Java互联网架构-一篇文精通JDK8lambada表达式
10、查找与匹配
筛选有效订单 匹配是否所有为已支付订单
// 筛选有效订单 匹配是否所有为已支付订单
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、归约&收集
11.1 归约
将流中元素反复结合起来,获得一个值的操做
计算有效订单总金额
Java互联网架构-一篇文精通JDK8lambada表达式
// 计算有效订单总金额
System.out.println("有效订单总金额:" +
ordersList.stream()
.filter((order) -> order.getIsValid() == 1)
.map(Order::getTotal)
.reduce(Double::sum)
.get()
);
Java互联网架构-一篇文精通JDK8lambada表达式
11.2 Collector数据收集
将流转换为其余形式,coollect 方法做为终端操做, 接收一个Collector接口的实现,用于给Stream中元素作汇总的方法。最经常使用的方法,把流中全部元素收集到一个 List, Set 或 Collection中
11.3 集合收集
经常使用集合收集方法 toList、toSet、toCollection、toMap等
筛选全部有效订单 并收集订单列表
// 筛选全部有效订单并收集订单列表
ordersList.stream()
.filter((order) -> order.getIsValid() == 1)
.collect(Collectors.toList())
.forEach(System.out::println);
筛选全部有效订单并收集订单号与订单金额
Java互联网架构-一篇文精通JDK8lambada表达式
// 筛选全部有效订单 并收集订单号 与 订单金额
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);
});
Java互联网架构-一篇文精通JDK8lambada表达式
12、汇总
汇总操做在Stream流操做比较常见,好比计算总数,求平均等操做,经常使用方法以下:
Java互联网架构-一篇文精通JDK8lambada表达式
Java互联网架构-一篇文精通JDK8lambada表达式
相关操做以下
筛选全部有效订单 返回订单总数
Java互联网架构-一篇文精通JDK8lambada表达式
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()
);
Java互联网架构-一篇文精通JDK8lambada表达式
返回订单总金额
Java互联网架构-一篇文精通JDK8lambada表达式
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()
);
Java互联网架构-一篇文精通JDK8lambada表达式
返回用户id=20 有效订单平均每笔消费金额
Java互联网架构-一篇文精通JDK8lambada表达式
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()
);
Java互联网架构-一篇文精通JDK8lambada表达式
筛选全部有效订单 并计算订单总金额
System.out.println("订单总金额:"+
ordersList.stream()
.filter((order) -> order.getIsValid() == 1)
.collect(Collectors.summingDouble(Order::getTotal))
);
十3、最值
筛选全部有效订单 并计算最小订单金额
System.out.println("最小订单金额:"+
ordersList.stream()
.filter((order) -> order.getIsValid() == 1)
.map(Order::getTotal)
.collect(Collectors.minBy(Double::compare))
);
筛选全部有效订单 并计算最大订单金额
Java互联网架构-一篇文精通JDK8lambada表达式
// 筛选全部有效订单 并计算最大订单金额
System.out.println("最大订单金额:"+
ordersList.stream()
.filter((order) -> order.getIsValid() == 1)
.map(Order::getTotal)
.collect(Collectors.maxBy(Double::compare))
);
Java互联网架构-一篇文精通JDK8lambada表达式
十4、分组&分区
14.1 分组
groupingBy 用于将数据分组,最终返回一个 Map 类型 ,groupingBy 第二参数用于实现多级分组
根据有效订单支付状态进行分组操做
Java互联网架构-一篇文精通JDK8lambada表达式
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);
});
Java互联网架构-一篇文精通JDK8lambada表达式
筛选有效订单,根据用户id 和 支付状态进行分组
Java互联网架构-一篇文精通JDK8lambada表达式
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("-----------------------");
});
Java互联网架构-一篇文精通JDK8lambada表达式
14.2 分区
分区与分组的区别在于,分区是按照 true 和 false 来分的,所以partitioningBy 接受的参数的 lambda 也是 T -> boolean
分区操做-筛选订单金额>1000 的有效订单
Java互联网架构-一篇文精通JDK8lambada表达式
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);
});
Java互联网架构-一篇文精通JDK8lambada表达式
拼接操做-筛选有效订单并进行拼接
String orderStr=ordersList.stream()
.filter((order) -> order.getIsValid() == 1)
.map(Order::getOrderNo)
.collect(Collectors.joining(","));
System.out.println(orderStr);
十5、流的应用
Java8引入Stream流操做,使得对元素的处理更加的方便快捷,经过Stream提供的相关方法很好的结合Lambda、函数式接口、方法引用等相关内容,使得流的处理相比较原始集合处理代码极大简化,Stream支持函数的链式调用,代码上更加紧凑同时Stream支持的元素的并行化处理提升了程序的执行性能。对于Stream流的应用一般在集合元素数据处理上特别是对元素须要进行屡次处理的状况,同时对于函数式编程的味道更加浓重,也是之后开发的一个趋势。