当前位置: 首页 > article >正文

java中stream常用api介绍

stream相关api对于集合操作非常方便,可以通过链式编程完成数据的处理,有时候很复杂的数据处理通过使用stream的相关api可以非常方便的完成,使用lambda表达式更可以简化为一行代码,下面就介绍一下stream的相关api方法,感受一下如何使用。

一、构建stream操作流

构建stream流的方式有很多种,比较常见的两种方式:
一是通过集合的 .stream() 构建流或 .parallelStream() 构建并行流;二是通过Stream类的相关api构建流。

  1. 通过集合的stream()或parallelStream()方法构建:
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
Set<Integer> set = new HashSet<>(list);

// 构建普通流
Stream<Integer> stream1 = list.stream();
Stream<Integer> stream2 = set.stream();

// 构建并行流
Stream<Integer> pstream1 = list.parallelStream();
Stream<Integer> pstream2 = set.parallelStream();

这里的并行流要注意,它默认使用的是系统中的 ForkJoinPool.commonPool 线程池,这个线程池默认大小是CPU核数,如果要调整线程池大小,可以有两种方法调整系统变量:

System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "4");
或
-Djava.util.concurrent.ForkJoinPool.common.parallelism=4

添加一个打印逻辑验证处理线程名:

pstream1.forEach(item -> System.out.println(Thread.currentThread().getName() + " : " + item));

没有添加上面的参数打印输出内容是:

main : 7
main : 6
ForkJoinPool.commonPool-worker-18 : 2
ForkJoinPool.commonPool-worker-4 : 1
ForkJoinPool.commonPool-worker-18 : 10
main : 9
ForkJoinPool.commonPool-worker-4 : 4
ForkJoinPool.commonPool-worker-25 : 3
ForkJoinPool.commonPool-worker-11 : 8
ForkJoinPool.commonPool-worker-29 : 5

添加配置后的输出内容:

main : 7
main : 6
ForkJoinPool.commonPool-worker-1 : 3
ForkJoinPool.commonPool-worker-1 : 5
ForkJoinPool.commonPool-worker-2 : 9
ForkJoinPool.commonPool-worker-3 : 2
ForkJoinPool.commonPool-worker-1 : 4
ForkJoinPool.commonPool-worker-3 : 1
ForkJoinPool.commonPool-worker-0 : 8
ForkJoinPool.commonPool-worker-2 : 10

可见配置参数确实调整了系统线程池的大小,由于主线程也会参与计算,所以对于计算密集型的服务,线程池一般设置为CPU核数 - 1。

  1. 通过Stream的api构建
    通过stream的api构建,主要是Stream.of()方法构建:
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
stream.forEach(System.out::println);

对于特定类型的stream还有专门的api构建,比如IntStream的range()和rangeClosed()方法构建一个范围内的数据,其中range()方法包含开始数据不包含结束数据,rangeClosed()方法包含开始数据同时包含结束数据。

// 包括开始不包括结束
System.out.println("----------------stream1----------------");
IntStream stream1 = IntStream.range(1, 10);
stream1.forEach(System.out::println);

// 包括开始和结束
System.out.println("----------------stream2----------------");
IntStream stream2 = IntStream.rangeClosed(1, 10);
stream2.forEach(System.out::println);
  1. 通过Arrays的stream()方法构建:
int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
IntStream stream = Arrays.stream(arr);
stream.forEach(System.out::println);

上面就是几种常用的构建stream流方式,使用stream流主要是处理数据,处理数据又分为中间方法和终结方法,它们的主要区别就是中间方法处理完后还可以继续使用stream流进行接下来的处理;而终结方法执行后的流不能继续使用,要想继续使用就必须重新开启一个流再次执行。
下面所有的流使用的都是这个stream做演示:

List<Integer> list = new ArrayList<>(Arrays.asList(3, 6, 10, 5, 5, 2, 6, 4, 9, 7, 8, 1, 8, 9));
Stream<Integer> stream = list.stream();
二、中间方法

中间方法执行后获取到的仍然是一个可以使用的流,常用的中间方法如下:

  1. 过滤数据filter()
// 筛选大于3且小于8的数据
stream.filter(new Predicate<Integer>() {
    @Override
    public boolean test(Integer i) {
        return i > 3 && i < 8;
    }
}).forEach(item -> System.out.println(item));

// lambda表达式
stream.filter(i -> i > 3 && i < 8).forEach(System.out::println);
  1. 选择一个区间的数据:skip()是跳过的数据条数,limit()是返回的数据条数
// 跳过前2条数据返回5条数据
stream.skip(2).limit(5).forEach(System.out::println);
  1. 数据去重distinct()
stream.distinct().forEach(System.out::println);
  1. 数据排序sorted()
// 默认排序是升序排列
stream.sorted().forEach(System.out::println);

// 自定义排序:降序排列
stream.sorted(new Comparator<Integer>() {
    @Override
    public int compare(Integer o1, Integer o2) {
        return o1 > o2 ? -1 : (o1.intValue() == o2.intValue() ? 0 : 1);
    }
}).forEach(item -> System.out.println(item));

// lambda表达式
stream.sorted((o1, o2) -> o1 > o2 ? -1 : (o1.intValue() == o2.intValue() ? 0 : 1)).forEach(System.out::println);
  1. 修改数据类型map()
stream.map(new Function<Integer, String>() {
    @Override
    public String apply(Integer i) {
        return "i-" + i;
    }
}).forEach(item -> System.out.println(item));

// lambda表达式
stream.map(i -> "i-" + i).forEach(System.out::println);
  1. 修改数据类型flatMap()
stream.flatMap((Function<Integer, Stream<?>>) num -> {
    // 因式分解该整数
    if(num <= 2) {
        return Stream.of(num);
    }

    List<Integer> nums = new ArrayList<>();
    int i = num;
    while (i >= 2) {
        for(int j = 2; j <= i; j++) {
            if(i % j == 0) {
                nums.add(j);
                i /= j;
                break;
            }
        }
    }
    return nums.stream();
}).forEach(System.out::println);

注意:map()和flatMap()这两个方法都能实现改变数据类型,主要区别是map()方法修改类型后返回的是单个元素、flatMap()方法修改类型后返回的是一个stream流,主要用于修改类型后返回的是一个集合的场景。
7. 获取数据peek()方法
在数据流处理过程中,我们想查看一下当前数据的内容或记录数据信息到日志中,可以通过peek()方法执行,该方法只是对数据查看而不会改变数据的内容:

// 打印数据
stream.peek(System.out::println).forEach(System.out::println);

peek()方法与forEach()方法的区别是:peek()输出数据后不影响流的继续操作;而forEach()方法输出数据后流不能继续执行。peek()方法执行虽然不能修改元素,但是可以修改元素内属性的值而对流的执行不产生影响。

@Data
@Builder
public class DemoVo {

    private int id;
    private String name;
}

List<DemoVo> list = Arrays.asList(DemoVo.builder().build(), DemoVo.builder().build(), DemoVo.builder().build());
// 通过peek()方法设置对象的属性值
list.stream().peek(System.out::println).peek(c -> c.setName("name")).forEach(System.out::println);
三、终结方法

终结方法执行完后,这个流不能继续执行,常见的终结方法有下面这些:

  1. max()、min()、count()三个取值方法
// 最大值
Integer max = stream.max(Comparator.comparingInt(o -> o)).get();
System.out.println(max);

// 最小值
Integer min = stream.min(Comparator.comparingInt(o -> o)).get();
System.out.println(min);

// 计数
long count = stream.count();
System.out.println(count);
  1. forEach() 遍历流中的数据
stream.forEach(System.out::println);
  1. toArray()方法将流转换为数组
Integer[] arr = stream.toArray(new IntFunction<Integer[]>() {
    @Override
    public Integer[] apply(int value) {
        return new Integer[value];
    }
});

// lambda表达式
Integer[] arr = stream.toArray(value -> new Integer[value]);
System.out.println(Arrays.toString(arr));
  1. collect()将流收集到指定类型集合中
// 收集到list
List<Integer> list = stream.collect(Collectors.toList());

// 收集到set
Set<Integer> set = stream.collect(Collectors.toSet());

// 收集到map:两个函数分别用于键的生成规则和值的生成规则,要注意键不能重复,否则会抛出异常
Map<Integer, String> map = stream.collect(Collectors.toMap(new Function<Integer, Integer>() {
    @Override
    public Integer apply(Integer i) {
        return i;
    }
}, new Function<Integer, String>() {
    @Override
    public String apply(Integer i) {
        return "val-" + i;
    }
}));

// lambda表达式
Map<Integer, String> map = stream.collect(Collectors.toMap(i -> i, i -> "val-" + i));

http://www.kler.cn/a/137084.html

相关文章:

  • android EditText密码自动填充适配
  • stm32制作CAN适配器5--WinUsb上位机编写
  • Burp与其他安全工具联动及代理设置教程
  • 解锁移动设备管理新技能-RayLink远程控制手机
  • STM32单片机使用CAN协议进行通信
  • MySQL内查询
  • 鸿蒙原生应用/元服务开发-AGC分发如何配置版本信息(上)
  • Python try except 用法
  • Linux ps -ef|grep去除 grep --color=auto信息
  • windows对话框
  • 字节8年经验之谈 —— 10大自动化测试框架总结!
  • 深入 Django 的 URL 分发器
  • 国产化区块链平台-FISCO BCOS 区块链
  • 代码随想录算法训练营第25天|216.组合总和III 17.电话号码的字母组合
  • 关于“研发效能冷思考”的冷思考 | IDCF
  • 【Linux】 线程
  • CSS中常用的伪元素选择器
  • 机器学习第11天:降维
  • 场景中的解剖学方向标记_vtkAnnotatedCubeActor
  • 外贸干货|深度剖析外贸出口各国操作细节
  • 每日一题 2216. 美化数组的最少删除数(中等,贪心)
  • Foodpanda API连接的艺术:无代码开发如何集成营销系统和广告推广工具
  • 每日一练 | 华为认证真题练习Day134
  • SQL基础理论篇(七):多表关联的连接算法
  • 『亚马逊云科技产品测评』活动征文|借助AWS EC2搭建服务器群组运维系统Zabbix+spug
  • 软考高项知识点 安全技术