Stream
定义:流实际就是一批数据的集合,大大简化开发过程
方法解释
- filter 过滤操作:类似于if,将满足条件的数据保留下来
//给一个原数据,返回一个Boolean值
//满足布尔值的数据保留
Stream<T> filter(Predicate<? super T> predicate);
//Predicate可缩写为
A -> {
//比较操作
//例如:
return A == B
}
- map 转换操作:将一个实体转换为另一个实体(A->B)
//接收一个转换方法。函数式接口之Function
//返回值:属于实体B的Stream
<R> Stream<R> map(Function<? super T, ? extends R> mapper)
//Function可缩写为
A -> {
B result = new B();
//转换逻辑
return B
}
衍生转换家族:限定了转换结果,与map最明显的区别:仅仅能返回固定类型的实体
1. mapToInt: 限制转换结果为int
2. mapToLong:限制转换结果为 long
3. mapToDouble:限制转换结果为 double
存在的意义:可进行一些数学运算,比如sum,max,min等等。比如求出一批订单数据的招总金额
//其中有amount属性,金额
List<Order> data = ......;
//求出id最大的数据
double totalAmount = data
.stream()
.mapToDoule(e -> return e.getAmount())
//可简写为
//.mapToDoublle(Order::getAmount)
.sum();
- flatMap 集合转换操作(最难理解):将一个集合流平铺
//接收一个属于A的集合流
//返回一个属于A的流
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
//举例
//有一个被分组或者通过多线程读取到的一组订单数据
List<List<Order>> orderGroup = new ArrayList<>();
//现在要获取所有的数据
List<Order> totalOrder = orderGroup
.stream()
.flatMap(orders -> {
return orders.stream;
})
//可简写为
//.flatMap(List::stream)
.collect(Collectors.toList());
衍生家族同上:
1. flatMapToLong
2. flatMapToDouble
3. flatMapToInt
- distinct 去重:将流中重复数据去重,类似于MySQL的distinct
//去重规则为:A.equals(B)
//所以如果是对象流进行去重,一定要重写equals方法
Stream<T> distinct();
//有一组字符串数字数据,将其去重后求和
List<String> numbers = new ArrayList<>();
int total = numbers
.stream()
//过滤掉为空串的
.filter(e -> e != null && e != "")
//转化为int流
.mapToInt(Integer::valueOf)
.distinct()
.sum();
- sorted 排序:将流中的数据进行一定规则的排序
//比较器 必须为Comparator的子类,可使用lamda表达式
//可理解为 Collections.sorted();
Stream<T> sorted(Comparator<? super T> comparator)
//将订单集合按照各个订单的金额大小排序
List<Order> orders = new ArrayList<>();
List<Order> result = orders
.stream()
.sorted(order -> Comparator.comparingDouble(Order::getAmount).reversed())
.collect(Collectors.toList());
- peek 处理:将流中的数据进行处理,不进行转换
//与map的区别:
//map是将一个实体转换为另一个实体:A->B
//peek仅对原数据处理,对实体类型没有影响。
//如果不需要流处理结果,也就是规约操作,相当于foreach
//所以一般用于流过程调试或实体转换后赋值
Stream<T> peek(Consumer<? super T> action);
//举例
//有一个被分组或者通过多线程读取到的一组订单数据
List<List<Order>> orderGroup = new ArrayList<>();
//现在我需要获取所有的订单数据,我需要得到订单当前确切的结果
List<Order> result = orderGroup
.stream()
.flatMap(List::stream)
.peek(order -> {
order.setStatus("已支付");
})
.collect(Collector.toList());
- limit 限制集合个数:类似于MySQL的分页limit,返回指定个数的数据
Stream<T> limit(long maxSize);
//将order按金额大小排序,并返回金额最高的十单
List<Order> result = orders
.stream()
.sorted(e -> Comparator.compareDouble(Order::getAmount).reversed())
.limit(10)
.collect(Collectors.toList());
- skip 跳过:跳过指定个数的元素,类似于MySQL的分页第一个参数
Stream<T> skip(long n);
//获取order订单列表的第二页数据,每页数据为10条
int currentPage = 2,size = 10;
List<Order> result = orders
.stream()
.skip((currentPage - 1) * size)
.limit(size)
.collect(Collector.toList());
- forEach 遍历:类似于集合的foreach,基本不用
- forEachOrdered 顺序遍历:按照集合原本定义数据遍历,一般用于并行流中
void forEachOrdered(Consumer<? super T> action);
① 在并行流中forEach不保证按顺序执行。
Stream.of("A","B","C", "D")
.parallel()
.forEach(e -> System.out.println(e));
输出可能是C B A D,输出不一定是按顺序执行。
② forEachOrdered方法总是保证按顺序执行。
Stream.of("A","B","C", "D")
.parallel()
.forEachOrdered(e -> System.out.println(e));
输出为A B C D。
- toArray 终端规约操作:将流转为数组
<A> A[] toArray(IntFunction<A[]> generator);
//将order转为orderVo数组
OrderVo[] result = orders
.stream()
.map(order -> return transferVo(order))
.toArray(OrderVo[]::new);
- reduce 规约:使用累积函数对元素进行处理,最后返回一个值
//给予一个初始值,在该值基础上进行累计函数
T reduce(T identity, BinaryOperator<T> accumulator);
//不给予初始值,进行累积,与上述的区别在于返回值。因为如果没有初始值并且
//流中没有元素,那么就会返回空。
Optional<T> reduce(BinaryOperator<T> accumulator);
//使用reduce实现求和
List<Integer> numbers = Arrays.asList(1,2,3,4,5);
int sum = numbers
.stream()
.reduce(0L,(a,b) -> a + b);
//给予另一个类型的初始值,进行累积
//与上述的区别是,初始值的类型可以与流类型不同,类似于map+reduce的功能
//用的不多
<U> U reduce(U identity,
BiFunction<U, ? super T, U> accumulator,
BinaryOperator<U> combiner);
//对一个数字集合累乘,最后结果可能大于int的取值范围,所以需要转为long
List<Integer> numbers = Arrays.asList(9999,8888,7777,6666,5555);
Long reduce = numbers
.stream()
.reduce(1L, (a, b) -> a * b, (a, b) -> 1L);
- min 最小值:根据比较器获取流中最小的元素
- max 最大值:根据比较器获取流中最大的元素
- count 计数:获取流中有多少个元素
- anyMatch 任意匹配:根据比较规则,流中元素如果有任意一个符合就返回true
//与filter的区别为
//filter:过滤掉不符合条件的数据
//match:判断流中是否存在符合条件的元素
boolean anyMatch(Predicate<? super T> predicate);
- allMatch 全部匹配 :流中元素是否全部符合条件
- noneMatch 是否没有元素匹配条件:allMatch反过来
- findFirst 返回流中的第一个元素
//一般只需获取某种满足条件的第一条元素
Optional<T> findFirst();
//获取张三最近的第一条订单
List<Order> orders = new ArrayList<>();
Optional<Order> result = orders
.stream()
.sorted(e -> Compartor.compare(Order::getPayTime).reversed())
.findFirst();
- findAny 返回流中任意一个元素
- collect 收集: 一般用Collectors静态方法
- toCollection:收集为指定的集合
- toList:toCollection的具体化,收集为List集合
- toSet:toCollection的具体化,收集为Set集合
- joining:类似于String.join方法
public static Collector<CharSequence, ?, String> joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix) //获取订单付款人并以逗号分隔 String payUsers = orders .stream() .map(Order::getPayUserName) .joining(",")
- groupBy 根据指定规则分组
//根据订单付款人分组 Map<String,List<Order>> result = orders .stream() .collect(Collectors.groupBy(Order::getPayUserId));