参考地址:
https://juejin.cn/post/6980135669368619045
https://juejin.cn/post/6844903830254010381
菜单
一、Stream简介
Stream 将要处理的元素集合看作一种流,在流的过程中,借助Stream API对流中的元素进行操作,比如:筛选、排序、聚合等
Stream的操作符大体上分为两种:中间操作符和终止操作符号
中间操作符
- map(mapToInt,mapToLong,mapToDouble) 转换操作符,把比如A->B,这里默认提供了转int,long,double的操作符。
- flatmap(flatmapToInt,flatmapToLong,flatmapToDouble) 拍平操作比如把 int[]{2,3,4} 拍平 变成 2,3,4 也就是从原来的一个数据变成了3个数据,这里默认提供了拍平成int,long,double的操作符。
- limit 限流操作,比如数据流中有10个 我只要出前3个就可以使用。 distint 去重操作,对重复元素去重,底层使用了equals方法。 filter 过滤操作,把不想要的数据过滤。
- peek 挑出操作,如果想对数据进行某些操作,如:读取、编辑修改等。
- skip 跳过操作,跳过某些元素。
- sorted(unordered) 排序操作,对元素排序,前提是实现Comparable接口,当然也可以自定义比较器。
终止操作符
- collect 收集操作,将所有数据收集起来,这个操作非常重要,官方的提供的Collectors 提供了非常多收集器,可以说Stream 的核心在于Collectors。
- count 统计操作,统计最终的数据个数。
- findFirst、findAny 查找操作,查找第一个、查找任何一个 返回的类型为Optional。
- noneMatch、allMatch、anyMatch 匹配操作,数据流中是否存在符合条件的元素 返回值为bool 值。
- min、max 最值操作,需要自定义比较器,返回数据流中最大最小的值。
- reduce 规约操作,将整个数据流的值规约为一个值,count、min、max底层就是使用reduce。
- forEach、forEachOrdered 遍历操作,这里就是对最终的数据进行消费了。
- toArray 数组操作,将数据流的元素转换成数组。
二、Stream例子:
2.1Stream的创建
2.1.1List<String>的创建方式
List<String> list = Arrays.asList("a", "b", "c");
// 创建一个顺序流
Stream<String> stream = list.stream();
// 创建一个并行流
Stream<String> parallelStream = list.parallelStream();
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 3).limit(4);
stream2.forEach(System.out::println); // 0 3 6 9
Stream<Double> stream3 = Stream.generate(Math::random).limit(3);
stream3.forEach(System.out::println);
2.1.2List<class>的创建方式
2.1.2.1首先创建一个MyUser类
package com.fcors.fcors;
import lombok.*;
@Builder
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class MyUser {
private String name;
private String sex;
private int age;
}
2.1.2.2创建List<class>
package com.fcors.fcors;
import org.junit.Test;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class StreamTest {
public List<MyUser> DefaultMyUser(){
MyUser user1 = MyUser.builder()
.name("fox1")
.sex("boy")
.age(18)
.build();
MyUser user2 = MyUser.builder()
.name("fox2")
.sex("boy")
.age(20)
.build();
MyUser user3 = MyUser.builder()
.name("fox3")
.sex("girl")
.age(16)
.build();
List<MyUser> UserList = new ArrayList<>();
UserList.add(user1);
UserList.add(user2);
UserList.add(user3);
return UserList;
}
@Test
public void testStream() {
List<MyUser> UserList = this.DefaultMyUser();
System.out.println(UserList);
// 创建一个顺序流
List<MyUser> streamList = UserList.stream().collect(Collectors.toList());;
System.out.println(streamList);
// 创建一个并行流
List<MyUser> streamList2 = UserList.parallelStream().collect(Collectors.toList());;
System.out.println(streamList);
}
}
2.2中间操作符
2.2.1映射(map/flatMap)
map:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
2.2.1.1List<String>型的Map
public class StreamTest {
public static void main(String[] args) {
String[] strArr = { "abcd", "bcdd", "defde", "fTr" };
List<String> strList = Arrays.stream(strArr).map(String::toUpperCase).collect(Collectors.toList());
System.out.println("每个元素大写:" + strList);
List<Integer> intList = Arrays.asList(1, 3, 5, 7, 9, 11);
List<Integer> intListNew = intList.stream().map(x -> x + 3).collect(Collectors.toList());
System.out.println("每个元素+3:" + intListNew);
}
}
2.2.1.2 List<class>的Map,遍历每个一个Class处理
@Test
public void testStream() {
List<MyUser> UserList = this.DefaultMyUser();
System.out.println(UserList);
// 创建一个顺序流
List<MyUser> streamList = UserList.stream()
.map(u ->{
u.setName(u.getName().toUpperCase());
return u;
})
.collect(Collectors.toList());;
System.out.println(streamList);
}
2.2.1.3利用Map提取class中的name并拼接成字符串
@Test
public void testStream() {
List<MyUser> UserList = this.DefaultMyUser();
System.out.println(UserList);
// 创建一个顺序流
String phrase = UserList
.stream()
.map(p -> p.getName()) // 提取名字
.collect(Collectors.joining(" and ", "In Germany ", " are of legal age.")); // 以 In Germany 开头,and 连接各元素,再以 are of legal age. 结束
System.out.println(phrase);
}
/**输出:In Germany fox1 and fox2 and fox3 are of legal age.**/
2.2.2flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
String poetry = "Where, before me, are the ages that have gone?\n" +
"And where, behind me, are the coming generations?\n" +
"I think of heaven and earth, without limit, without end,\n" +
"And I am all alone and my tears fall down.";
Stream<String> lines = Arrays.stream(poetry.split("\n"));
Stream<String> words = lines.flatMap(line -> Arrays.stream(line.split(" ")));
List<String> l = words.map( w -> {
if (w.endsWith(",") || w.endsWith(".") || w.endsWith("?"))
return w.substring(0,w.length() -1).trim().toLowerCase();
else
return w.trim().toLowerCase();
}).distinct().sorted().collect(Collectors.toList());
System.out.println(l);
//[ages, all, alone, am, and, are, before, behind, coming, down, earth, end, fall, generations, gone, have, heaven, i, limit, me, my, of, tears, that, the, think, where, without]
2.2.3 筛选(filter)
public static void main(String[] args) {
List<Integer> list = Arrays.asList(6, 7, 3, 8, 1, 2, 9);
Stream<Integer> stream = list.stream();
stream.filter(x -> x > 7).forEach(System.out::println);
}
public void testStream() {
List<MyUser> UserList = this.DefaultMyUser();
System.out.println(UserList);
List<MyUser> streamList = UserList.stream()
.filter(p -> p.getAge()>18 && p.getSex()=="girl")
.collect(Collectors.toList());;
System.out.println(streamList);
}
2.2.4limit 限流操作
@Test
public void StreamMapObj(){
List<MyUser> UserList = this.DefaultMyUser();
System.out.println("初始化Stream:"+UserList);
// 创建一个顺序流
List<MyUser> streamList = UserList.stream()
.filter(u ->{
return u.getName().contains("fox");
}).limit(2)
.collect(Collectors.toList());
System.out.println(streamList);
}
2.2.5 distinct 去重
整体去重
public void StreamMapObj(){
List<MyUser> UserList = this.DefaultMyUser();
System.out.println("初始化Stream:"+UserList);
// 创建一个顺序流
List<MyUser> streamList = UserList.stream()
.filter(u ->{
return u.getName().contains("fox");
}).distinct()
.collect(Collectors.toList());
System.out.println(streamList);
}
根据某个属性去重
static <T> Predicate<T> distinctByKey1(Function<? super T, ?> keyExtractor) {
val seen = new ConcurrentHashMap<>();
return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}
@Test
public void StreamMapObj(){
List<MyUser> UserList = this.DefaultMyUser();
System.out.println("初始化Stream:"+UserList);
UserList.stream().filter(distinctByKey1(s -> s.getSex()))
.forEach(System.out::println);
Concat流合并
@Test
public void StreamConcat(){
String[] arr1 = { "a", "b", "c", "d" };
String[] arr2 = { "d", "e", "f", "g" };
Stream<String> stream1 = Stream.of(arr1);
Stream<String> stream2 = Stream.of(arr2);
// concat:合并两个流 distinct:去重
List<String> newList = Stream.concat(stream1, stream2).distinct().collect(Collectors.toList());
System.out.println(newList);
}
skip 跳过操作
一维
@Test
public void StreamPage(){
int page = 2;
int pagesize = 3;
int pageSkip = page==1 ?0 :1*pagesize;
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<Integer> dataList = numbers.stream().sorted(Integer::compareTo).skip(pageSkip).limit(pagesize).collect(Collectors.toList());
System.out.println(dataList.toString());
}
数组型list
@Test
public void StreamPageList(){
int page = 2;
int pagesize = 2;
int pageSkip = page==1 ?0 :1*pagesize;
List<MyUser> UserList = this.DefaultMyUser();
List<MyUser> streamList = UserList.stream().skip(pageSkip).limit(pagesize).collect(Collectors.toList());
System.out.println(streamList);
}
排序
一维排序参看上面“skip 跳过操作 ”
数组型Stream
自然排序
@Test
public void StreamPageList(){
int page = 1;
int pagesize = 2;
int pageSkip = page==1 ?0 :1*pagesize;
List<MyUser> UserList = this.DefaultMyUser();
List<MyUser> streamList = UserList.stream().sorted(Comparator.comparing(MyUser::getName)).skip(pageSkip).limit(pagesize).collect(Collectors.toList());
System.out.println(streamList);
}
倒序排序
@Test
public void StreamPageList(){
int page = 1;
int pagesize = 2;
int pageSkip = page==1 ?0 :1*pagesize;
List<MyUser> UserList = this.DefaultMyUser();
List<MyUser> streamList = UserList.stream().sorted(Comparator.comparing(MyUser::getSex).reversed().thenComparing(MyUser::getName)).skip(pageSkip).limit(pagesize).collect(Collectors.toList());
System.out.println(streamList);
}
终止操作符
collect收集操作
@Test
public void StreamCollect(){
List<MyUser> UserList = this.DefaultMyUser();
List<MyUser> streamList = UserList.stream().collect(Collectors.toList());
System.out.println("List"+streamList);
Set<MyUser> streamSet = UserList.stream().collect(Collectors.toSet());
System.out.println("Set"+streamList);
Map<String, MyUser> map = UserList.stream()
.collect(Collectors.toMap(MyUser::getName, p -> p));
System.out.println("Map"+map);
}
统计操作(max/average/sum)
@Test
public void StreamMatch(){
List<MyUser> UserList = this.DefaultMyUser();
Double AvgeAge = UserList.stream().collect(Collectors.averagingInt(MyUser::getAge));
System.out.println("员工平均年龄:" + AvgeAge);
Optional<Integer> max = UserList.stream().map(MyUser::getAge).max(Integer::compare);
System.out.println("员工最大年龄:" + max.get());
int sum = UserList.stream().mapToInt(MyUser::getAge).sum();
System.out.println("员工年龄汇总:" + sum);
}
分组
- partitioningBy按是否满足条件分组
- groupingBy分组
@Test
public void StreamMatch(){
List<MyUser> UserList = this.DefaultMyUser();
// 将员工按年龄20岁分区
Map<Boolean, List<MyUser>> part = UserList.stream().collect(Collectors.partitioningBy(x -> {
return "boy".equals(x.getSex());
}));
System.out.println("part"+part);
//part{false=[MyUser(name=fox3, sex=girl, age=16)], true=[MyUser(name=fox1, sex=boy, age=18), MyUser(name=fox2, sex=boy, age=20), MyUser(name=fox19, sex=boy, age=18)]}
Map<String, List<MyUser>> group1 = UserList.stream().collect(Collectors.groupingBy(MyUser::getSex));
System.out.println("group"+group1);
//group{girl=[MyUser(name=fox3, sex=girl, age=16)], boy=[MyUser(name=fox1, sex=boy, age=18), MyUser(name=fox2, sex=boy, age=20), MyUser(name=fox19, sex=boy, age=18)]}
Map<String, Map<Integer, List<MyUser>>> group2 = UserList.stream().collect(Collectors.groupingBy(MyUser::getSex, Collectors.groupingBy(MyUser::getAge)));
System.out.println("group2"+group2);
//group2{girl={16=[MyUser(name=fox3, sex=girl, age=16)]}, boy={18=[MyUser(name=fox1, sex=boy, age=18), MyUser(name=fox19, sex=boy, age=18)], 20=[MyUser(name=fox2, sex=boy, age=20)]}}
}
遍历foreach/findFirst/findAny/anyMatch
List<Integer> list = Arrays.asList(7, 6, 9, 3, 8, 2, 1);
// 遍历输出符合条件的元素
list.stream().filter(x -> x > 6).forEach(System.out::println);
// 匹配第一个
Optional<Integer> findFirst = list.stream().filter(x -> x > 6).findFirst();
// 匹配任意(适用于并行流)
Optional<Integer> findAny = list.parallelStream().filter(x -> x > 6).findAny();
// 是否包含符合特定条件的元素
boolean anyMatch = list.stream().anyMatch(x -> x < 6);
System.out.println("匹配第一个值:" + findFirst.get());
System.out.println("匹配任意一个值:" + findAny.get());
System.out.println("是否存在大于6的值:" + anyMatch);
Stream的复用性
@Test
public void StreamMu(){
Stream<String> stream =
Stream.of("d2", "a2", "b1", "b3", "c")
.filter(s -> s.startsWith("a"));
stream.anyMatch(s -> true); // ok
stream.noneMatch(s -> true); // exception
}
改造办法
@Test
public void StreamMu(){
Supplier<Stream<String>> streamSupplier =
() -> Stream.of("d2", "a2", "b1", "b3", "c")
.filter(s -> s.startsWith("a"));
boolean bool1 = streamSupplier.get().anyMatch(s -> true); // ok callback true
System.out.println(bool1);
boolean bool2 = streamSupplier.get().noneMatch(s -> true); // ok callback false
System.out.println(bool2);
}
stream生成VO
@Test
public void StreamVo() {
List<MyUser> UserList = this.DefaultMyUser();
List<MyUserVO> UserVoList = (List<MyUserVO>) UserList.stream().map(User->{
MyUserVO myUserVO = new MyUserVO();
try {
BeanUtils.copyProperties(myUserVO,User );
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return myUserVO;
}).collect(Collectors.toList());
System.out.println(UserVoList);
}
reduce
private BigDecimal getSumByCategory(List<SkuOrderBO> skuOrderBOList, Long cid) {
BigDecimal sum = skuOrderBOList.stream()
.filter(sku -> sku.getCategoryId().equals(cid))
.map(SkuOrderBO::getTotalPrice)
.reduce(BigDecimal::add)
.orElse(new BigDecimal("0"));
return sum;