Stream API

一、Stream概述

Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。

Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。

Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。

这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。

元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。
在这里插入图片描述



二、Stream 常用创建方法

1.stream(串行流)

为集合创建串行流

//串行
Stream<User> stream = list.stream();

2.parallelStream(并行流)

为集合创建并行流

//并行
Stream<User> stream = list.parallelStream();

在这里插入图片描述
无需等待上游类型 filter | map | flatMap | peek |
需要等待上游类型 skip | distinct | limit | sorted



三、Stream 常用中间方法

都会返回一个新的 stream 流。

1. filter(过滤)

对流中的元素进行条件过滤在这里插入图片描述
参数为一个Predicate(断定函数),函数返回值类型为boolean的方法。

//实现接口
Predicate<Object> predicate = new Predicate<>() {

    @Override
    public boolean test(Object o) {
        return false;
    }
};

//使用lambda表达式
Predicate<Integer> predicate = x -> x>5;

实例:

//筛选出年龄在21~25之间的用户
List<User> collect = userList.stream()
                .filter(user -> user.getAge() > 20 && user.getAge() <= 25)
                .collect(Collectors.toList());

2. map(映射)

改变流中每一个元素的值。
在这里插入图片描述
参数为了一个Function(函数) 有固定返回类型的方法。

//实现接口
Function<User, User> function = new Function<>() {
   
    @Override
    public User apply(User user) {
        return null;
    }
};

//使用lambda表达式
Function<User, User> function = user -> user.setName(user.getName()+" Nb");

实例:

//给每个用户名字后面加上“Nb”
List<User> collect = list.stream()
                .map(user -> user.setName(user.getName()+" Nb"))
                .collect(Collectors.toList());

3. flatMap(平铺映射)

通过某种方法将元素变成 stream,再将所有的 stream 组装成一个 stream,实现对元素的平铺操作。
在这里插入图片描述
参数为一个 返回结果为 Stream 对象的 Function
实例:

//将两个 list 中的全部用户名字后面加上“Nb”
List<List<User>> list = new ArrayList<>();

List<User> collect = list.stream()
                .flatMap(Collection::stream)
                .map(user -> user.setName(user.getName()+" Nb"))
                .collect(Collectors.toList());

4. peek(镜像)

类似于 map ,对每个元素执行一个动作
在这里插入图片描述
参数为一个Consumer(消费函数),一个无返回的方法。

//实现接口
Consumer<User> consumer1 = new Consumer<>() {
    
    @Override
    public void accept(User user) {
    }
};

//使用lambda表达式
Consumer<User> consumer = (User user) -> System.out.println("name:" + user.getName() + " phone:" + user.getPhone());

实例:

//输出用户名的手机号信息
List<User> collect = userList.stream()
                .peek((User user) -> System.out.println("name:" + user.getName() + " phone:" + user.getPhone()))
                .collect(Collectors.toList());

5. skip(跳跃)

跳过前 n 个元素,只保留剩下的元素。
在这里插入图片描述

参数为一个 Long 类型,要跳过的元素个数。

实例:

//跳过前2个用户
List<User> collect = userList.stream().skip(2).collect(Collectors.toList());

6. distinct(去重)

将流中的元素进行去重,只保留没有重复的元素。
在这里插入图片描述
无参数。

实例:

//用户列表进行去重
List<User> collect = userList.stream().distinct().collect(Collectors.toList());

7. limit(限制)

保留 n 个元素。
在这里插入图片描述
参数为一个 Long 类型,要保留的元素个数。

实例:

//只保留 2 个用户
List<User> collect = userList.stream().limit(2).collect(Collectors.toList());

limit 搭配 skip 进行分页处理:

//分页操作
List<User> collect = userList.stream()
                .skip((long) pageNum * pageSize)
                .limit(pageSize).collect(Collectors.toList());

8. sorted(排序)

对流中的元素按照一定条件进行排序

参数为一个 Comparator 比较接口,返回排序规则。

//实现接口
Comparator<User> comparator = new Comparator<>() {
    @Override
    public int compare(User o1, User o2) {
        return Integer.compare(o2.getAge(), o1.getAge());
    }
};

//比较器
Comparator<User> comparator = Comparator.comparingInt(User::getAge);

实例:

//按照用户名进行排序
List<User> collect = userList.stream()
                .sorted(Comparator.comparing(User::getName))
                .collect(Collectors.toList());



四、Stream 常用收集方法

1. count(统计)

对最后 stream 中的元素进行统计

无参数。会返回一个 long 类型数值。

实例:

//年龄大于21的人数
long count = userList.stream().filter(user -> user.getAge() > 21).count();

2. sum(求和)

对元素的某个属性进行求和

无参数。会返回一个 Integer 类型数值。

实例:

//年龄总和
Integer sum = userList.stream().mapToInt(User::getAge).sum();

3. max(最大值)

取出 stream 流中的最大值

参数为一个 Comparator 比较接口,返回比较大小的规则。

返回值为 public final class Optional<T>

//如果有值,可以执行一个 Consumer 消费函数
public void ifPresent(Consumer<? super T> action) {
    if (value != null) {
        action.accept(value);
    }
}

//如果有值,执行一个消费函数,如果没有值执行另一个线程方法
public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) {
    if (value != null) {
        action.accept(value);
    } else {
        emptyAction.run();
    }
}

实例:

//年龄最大的用户
Optional<User> min = userList.stream().max(Comparator.comparing(User::getAge));
max.ifPresent(System.out::println);

4. min(最小值)

取出 stream 流中的最小值

参数为一个 Comparator 比较接口,返回比较大小的规则。

返回值为 public final class Optional<T>

实例:

//年龄最小的用户
Optional<User> min = userList.stream().min(Comparator.comparing(User::getAge));
min.ifPresentOrElse(System.out::println, () -> System.out.println("isNull"));

5. collect(收集)

5.1 toList/toSet/toMap(归集)

因为流不存储数据,那么在流中的数据完成处理后,需要将流中的数据重新归集到新的集合里。toListtoSettoMap比较常用,另外还有toCollectiontoConcurrentMap等复杂一些的用法。

实例:

//将排序后的流收集为一个 list 集合
List<User> list = userList.stream()
        .sorted(Comparator.comparing(User::getAge))
        .collect(Collectors.toList());
        
//将结果收集为 用户名:用户 类型的 map 集合
Map<String, User> map = userList.stream()
        .collect(Collectors.toMap(User::getName, user -> user));
        
//将结果收集为一个无序的 set 集合
Set<User> set = userList.stream()
        .filter(user -> user.getAge()>21)
        .collect(Collectors.toSet());

5.2 count/averaging(统计)

Collectors 提供了一系列用于数据统计的静态方法:

  • 计数:count
  • 平均值:averagingIntaveragingLongaveragingDouble
  • 最值:maxByminBy
  • 求和:summingIntsummingLongsummingDouble
  • 统计以上所有:summarizingIntsummarizingLongsummarizingDouble

实例:

//用户年龄的平均值
Double averagingIn = userList.stream().collect(Collectors.averagingInt(User::getAge));

//计数、求和、最小值、平均值、最大值
IntSummaryStatistics summarizingInt = userList.stream().collect(Collectors.summarizingInt(User::getAge));

System.out.println("平均值: "+averagingIn);
System.out.println("计数、求和、最小值、平均值、最大值: "+summarizingInt);

输出:

平均值: 21.4
求和: IntSummaryStatistics{count=5, sum=107, min=20, average=21.400000, max=22}


5.3 partitioningBy/groupingBy(分组)

  • 分区:将 stream 按条件分为两个 Map
  • 分组:将集合分为多个Map。有单级分组和多级分组。

在这里插入图片描述
实例:

//根据性别进行分组
Map<Integer, List<User>> groupingBy = userList.stream().collect(Collectors.groupingBy(User::getSex));

//将年龄根据条件分为两组(一组为满足条件的,一组为不满足条件的)
Map<Boolean, List<User>> partitioningBy = userList.stream().collect(Collectors.partitioningBy(user -> user.getAge() > 21)

System.out.println("groupingBy: "+groupingBy);
System.out.println("partitioningBy: "+partitioningBy);

输出:

groupingBy: {0=[User(id=2, name=Zhao, age=22, phone=18137525590, sex=0)], 1=[User(id=1, name=Hou, age=22, phone=15136449091, sex=1)]}
partitioningBy: {false=[User(id=3, name=Shi, age=21, phone=15103832393, sex=1)], true=[User(id=1, name=Hou, age=22, phone=15136449091, sex=1)]}


5.4 joining(接合)

joining 可以将stream中的元素用特定的连接符(没有的话,则直接连接)连接成一个字符串。

实例:

//将用户的名字用 - 连接
String joining = userList.stream().map(User::getName).collect(Collectors.joining("-"));

System.out.println("joining: "+joining);

输出:

joining: Hou-Zhao-Shi-Wang-Lv


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值