Stream使用小结
中间操作(无状态) | 中间操作(有状态) | 终端操作(短路) | 终端操作(非短路) |
---|---|---|---|
过滤(filter) | 去重(distinct) | 所有匹配(allMatch) | 遍历(forEach) |
映射(map) | 跳过(skip) | 任意匹配(anyMatch) | 归约(reduce) |
扁平化(flatMap) | 截断(limit) | 不匹配(noneMatch) | 最大值(max) |
遍历(peek) | 排序(sorted) | 查找首个(findFirst) | 聚合(collect) |
查找任意(findAny) | 最小值(min) | ||
计数(count) |
ArrayList
// 加入到购物车中的商品信息
private static List<Sku> cartSkuList =
new ArrayList<Sku>(){
{
add(new Sku(654032, "无人机",
4999.00, 1,
4999.00, SkuCategoryEnum.ELECTRONICS));
add(new Sku(642934, "VR一体机",
2299.00, 1,
2299.00, SkuCategoryEnum.ELECTRONICS));
add(new Sku(645321, "纯色衬衫",
409.00, 3,
1227.00, SkuCategoryEnum.CLOTHING));
add(new Sku(654327, "牛仔裤",
528.00, 1,
528.00, SkuCategoryEnum.CLOTHING));
add(new Sku(675489, "跑步机",
2699.00, 1,
2699.00, SkuCategoryEnum.SPORTS));
add(new Sku(644564, "Java编程思想",
79.80, 1,
79.80, SkuCategoryEnum.BOOKS));
add(new Sku(678678, "Java核心技术",
149.00, 1,
149.00, SkuCategoryEnum.BOOKS));
add(new Sku(697894, "算法",
78.20, 1,
78.20, SkuCategoryEnum.BOOKS));
add(new Sku(696968, "TensorFlow进阶指南",
85.10, 1,
85.10, SkuCategoryEnum.BOOKS));
}
};
forEach
/*
* terminal operation 终结方法(无返回值,终结方法后不能继续链式调用了)
* 将流中的每一个元素交给consumer函数式接口处理
*/
void forEach(Consumer<? super T> action);
@Test
public void filterTest() {
list.stream()
.forEach(item ->
System.out.println(
JSON.toJSONString(
item, true)));
}
filter
/*
* intermediate operation 中间操作,无状态,操作只会涉及到当前元素
* 通过predicate函数式接口过滤元素,通过对T元素判断,返回boolean值
*/
Stream<T> filter(Predicate<? super T> predicate);
@Test
public void filterTest() {
list.stream()
// filter
.filter(sku ->
SkuCategoryEnum.BOOKS
.equals(sku.getSkuCategory()))
.forEach(item ->
System.out.println(
JSON.toJSONString(
item, true)));
}
map
/*
* intermediate operation 中间操作,无状态,操作只会涉及到当前元素
* 通过function函数式接口操作当前元素,将元素T转为元素R
*/
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
@Test
public void mapTest() {
list.stream()
// map
.map(sku -> sku.getSkuName())
.forEach(item ->
System.out.println(
JSON.toJSONString(
item, true)));
}
flatMap
/*
* intermediate operation 中间操作,无状态,操作只会涉及到当前元素
* 该Function函数式接口接收一个T类型对象,返回一个包含R对象的新的流
* 作用是将一个对象转换成流
*/
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
@Test
public void flatMapTest() {
list.stream()
// flatMap
.flatMap(sku -> Arrays.stream(
sku.getSkuName().split("")))
.forEach(item ->
System.out.println(
JSON.toJSONString(
item, true)));
}
输出结果
"无"
"人"
"机"
"V"
"R"
"一"
"体"
"机"
"纯"
"色"
"衬"
"衫"
"牛"
"仔"
"裤"
"跑"
"步"
"机"
......
Process finished with exit code 0
感觉这个图片挺形象的
peek
/*
* intermediate operation 中间操作,无状态,操作只会涉及到当前元素
* 与forEach操作类似,但是不会销毁流
*/
Stream<T> peek(Consumer<? super T> action);
@Test
public void peek() {
list.stream()
// peek
.peek(sku -> System.out.println(sku.getSkuName()))
.forEach(item ->
System.out.println(
JSON.toJSONString(
item, true)));
}
由于peek是无状态的中间操作,每次操作peek中的元素不会对上次或下次的操作产生影响,所以执行顺序并不重要,stream流并不会等peek完全执行完再去执行forEach,而是交替执行
部分输出结果
无人机
{
"skuCategory":"ELECTRONICS",
"skuId":654032,
"skuName":"无人机",
"skuPrice":4999.0,
"totalNum":1,
"totalPrice":4999.0
}
VR一体机
{
"skuCategory":"ELECTRONICS",
"skuId":642934,
"skuName":"VR一体机",
"skuPrice":2299.0,
"totalNum":1,
"totalPrice":2299.0
}
......
sort
/*
* stateful intermediate operation 中间操作,有状态
* 对流中元素进行排序
*/
Stream<T> sorted(Comparator<? super T> comparator);
@Test
public void sortTest() {
list.stream()
.peek(sku -> System.out.println(sku.getSkuName()))
//sort
.sorted(Comparator.comparing(Sku::getTotalPrice))
.forEach(item ->
System.out.println(
JSON.toJSONString(
item, true)));
}
由于sort是有状态的操作,排序会对前后操作产生影响,所以需要先等peek执行结束后由sort做统一汇总排序,排完序再执行forEach操作
部分输出结果
无人机
VR一体机
纯色衬衫
牛仔裤
跑步机
Java编程思想
Java核心技术
算法
TensorFlow进阶指南
{
"skuCategory":"BOOKS",
"skuId":697894,
"skuName":"算法",
"skuPrice":78.2,
"totalNum":1,
"totalPrice":78.2
}
{
"skuCategory":"BOOKS",
"skuId":644564,
"skuName":"Java编程思想",
"skuPrice":79.8,
"totalNum":1,
"totalPrice":79.8
}
......
distinct
/*
* stateful intermediate operation 中间操作,有状态
* 对流中元素进行去重
*/
Stream<T> distinct();
@Test
public void distinctTest() {
list.stream()
.map(sku -> sku.getSkuCategory())
// distinct
.distinct()
.forEach(item ->
System.out.println(
JSON.toJSONString(
item, true)));
}
skip
/*
* short-circuiting stateful intermediate operation 中间操作 有状态
* 跳过前n条记录
*/
Stream<T> skip(long n);
@Test
public void skipTest() {
list.stream()
.sorted(Comparator.comparing(Sku::getTotalPrice))
// skip
.skip(3)
.forEach(item ->
System.out.println(
JSON.toJSONString(
item, true)));
}
limit
/*
* short-circuiting stateful intermediate operation 中间操作 有状态 短路操作
* 截断前n条记录
*/
Stream<T> limit(long maxSize);
@Test
public void limitTest() {
list.stream()
.sorted(Comparator.comparing(Sku::getTotalPrice))
// 通过skip和limit可以模仿分页操作
.skip(2 * 3)
// limit
.limit(3)
.forEach(item ->
System.out.println(
JSON.toJSONString(
item, true)));
}
allMatch
/*
* short-circuiting terminal operation. 短路终端操作 (返回值为boolean,后面不能再链式调用了)
* 短路操作---> 当发现第一个不满足条件的,就直接返回false
* 所有元素进行匹配,如果都满足就返回true,如果有一个不满足就返回false
*/
boolean allMatch(Predicate<? super T> predicate);
@Test
public void allMatchTest() {
boolean match = list.stream()
.peek(sku -> System.out.println(sku.getSkuName()))
// allMatch
.allMatch(sku -> sku.getTotalPrice() > 100);
System.out.println(match);
}
anyMatch
/*
* short-circuiting terminal operation. 短路终端操作 (返回值为boolean,后面不能再链式调用了)
* 短路操作 ---> 只要有一个元素满足了条件,就直接返回true
* 匹配流中的任一元素,只要有一个满足的就返回true,都不满足就返回false
*/
boolean anyMatch(Predicate<? super T> predicate);
@Test
public void anyMatchTest() {
boolean match = list.stream()
.peek(sku -> System.out.println(sku.getSkuName()))
// anyMatch
.anyMatch(sku -> sku.getTotalPrice() > 100);
System.out.println(match);
}
noneMatch
/*
* short-circuiting terminal operation. 短路终端操作 (返回值为boolean,后面不能再链式调用了)
* 短路操作 ---> 只要有一个满足条件的,就返回false
* 都不满足条件返回true
*/
boolean noneMatch(Predicate<? super T> predicate);
@Test
public void noneMatchTest() {
boolean match = list.stream()
.peek(sku -> System.out.println(sku.getSkuName()))
// noneMatch
.noneMatch(sku -> sku.getTotalPrice() > 10_000);
System.out.println(match);
}
findFirst
/*
* short-circuiting terminal operation. 短路终端操作(返回值为Optional,后面不能继续对流操作了)
* 短路操作 ---> 找到第一个元素就直接返回
*/
Optional<T> findFirst();
@Test
public void findFirstTest() {
Optional<Sku> optional = list.stream()
.peek(sku -> System.out.println(sku.getSkuName()))
// findFirst
.findFirst();
System.out.println(
JSON.toJSONString(optional.get(), true));
}
findAny
和上面的类似,找到任何一个,只要有就返回
max
/*
* terminal operation 终端操作
* 找到流中元素的最大值
*/
OptionalDouble max();
min
与 max 类似
OptionalDouble min();
count
long count();
获取任务流中所有元素的个数并返回
collect() 收集器
将流收集为一个集合
@Test
public void toList() {
List<Sku> list = CartService.getCartSkuList();
List<Sku> result = list.stream()
.filter(sku -> sku.getTotalPrice() > 100)
// 将流中元素收集为一个List集合
.collect(Collectors.toList());
System.out.println(
JSON.toJSONString(result, true));
}
分组
将现有集合按照某些属性进行分组
@Test
public void group() {
List<Sku> list = CartService.getCartSkuList();
// Map<分组条件,结果集合>
Map<Object, List<Sku>> group = list.stream() // key是分组条件,value是分组后的集合
.collect(
Collectors.groupingBy(
sku -> sku.getSkuCategory())); // 使用Category属性进行分组
System.out.println(
JSON.toJSONString(group, true));
}
groupingBy分组函数接收的是一个Function的函数式接口,传入T对象,然会R对象,按照R对象对流中数据进行分组
分区
@Test
public void partition() {
List<Sku> list = CartService.getCartSkuList();
Map<Boolean, List<Sku>> partition = list.stream()
.collect(Collectors.partitioningBy(
sku -> sku.getTotalPrice() > 100));
System.out.println(
JSON.toJSONString(partition, true));
}
分区函数 gartitioningBy接收的是个Predicate的函数式接口,返回true或false,按照返回的结果进行分区
reduce 归约
-
T reduce(T identity, BinaryOperator<T> accumulator);
-
Optional<T> reduce(BinaryOperator<T> accumulator);
-
<U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner);
-
identity 表示初始值,第二个接口没有指定初始值就采用默认初始值
-
BinaryOperator<T> accumulator 通过一个函数式接口接收具体的操作逻辑。BinaryOperation继承自BiFunction接口,由于泛型约束,BinaryOperator接口接收两个T类型参数,返回一个T类型对象。其中两个参数分别表示前一个操作的返回值和当前操作值,返回值作为下一次操作的参数
-
BinaryOperator<U> combiner 定义了并行计算时多个结果的合并方式
public class ReduceAndCollectTest {
@Test
public void reduceTest() {
/**
* 订单对象
*/
@Data
@AllArgsConstructor
class Order {
/**
* 订单编号
*/
private Integer id;
/**
* 商品数量
*/
private Integer productCount;
/**
* 消费总金额
*/
private Double totalAmount;
}
/*
准备数据
*/
ArrayList<Order> list = Lists.newArrayList();
list.add(new Order(1, 2, 25.12));
list.add(new Order(2, 5, 257.23));
list.add(new Order(3, 3, 23332.12));
/*
以前的方式:
1. 计算商品数量
2. 计算消费总金额
*/
/*
汇总商品数量和总金额
*/
Order order = list.stream()
.parallel()
.reduce(
// 初始化值
new Order(0, 0, 0.0),
// Stream中两个元素的计算逻辑
(Order order1, Order order2) -> {
System.out.println("执行 计算逻辑 方法!!!");
int productCount =
order1.getProductCount()
+ order2.getProductCount();
double totalAmount =
order1.getTotalAmount()
+ order2.getTotalAmount();
return new Order(0, productCount, totalAmount);
},
// 并行情况下,多个并行结果如何合并
(Order order1, Order order2) -> {
System.out.println("执行 合并 方法!!!");
int productCount =
order1.getProductCount()
+ order2.getProductCount();
double totalAmount =
order1.getTotalAmount()
+ order2.getTotalAmount();
return new Order(0, productCount, totalAmount);
});
System.out.println(JSON.toJSONString(order, true));
}
}