Loading

Java-Stream流式计算

什么是 Stream流式计算

在 Java8 之前,如果我们想重新排序合并数据,一般是通过 for 循环或者 Iterator 迭代等方式进行操作。

但是这两种方式通常在数据量比较大的情况下,效率比较低。

在Java8中,添加了一个新的接口Stream,可以通过 Lambda 表达式对集合进行各种非常便利、高效的聚合操作(Aggregate Operation),或者大批量数据操作 (Bulk Data Operation)。

Stream流式计算:将要处理的元素看做一种流,流在管道中传输,并且可以在管道的节点上处理,包括过滤筛选、去重、排序、聚合等,并把结果发送到下一计算节点。

举例:对5个用户进行筛选

  • ID 必须是偶数
  • 年龄必须大于23岁
  • 用户名转为大写字母
  • 用户名字母倒着排序
  • 只输出一个用户!

User类

class User {
    int id, age;
    String name;
    public User() {}
    public User(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
    public int getId() {
        return id;
    }
    public int getAge() {
        return age;
    }
    public String getName() {
        return name;
    }
}

初始化的5个用户

User u1 = new User(1,"a",21);
User u2 = new User(2,"b",22);
User u3 = new User(3,"c",23);
User u4 = new User(4,"d",24);
User u5 = new User(6,"e",25);

使用传统的方式来实现

List<User> list = Arrays.asList(u1, u2, u3, u4, u5);
List<String> nameList = new ArrayList<String>();
for (User u : list) {
  if (u.getId() % 2 == 0)
    if (u.getAge() > 23)
      nameList.add(u.getName().toUpperCase());
}
nameList.sort(Comparator.reverseOrder());
System.out.println(nameList.get(0));

Stream进行实现

List<User> list = Arrays.asList(u1, u2, u3, u4, u5);
list.stream()
  .filter(u -> {
    return u.getId() % 2 == 0;
  })
  .filter(u -> {
    return u.getAge() > 23;
  })
  .map(u -> {
    return u.getName().toUpperCase();
  })
  .sorted((uu1, uu2) -> {
    return uu2.compareTo(uu1);
  })
  .limit(1)
  .forEach(System.out::println);

Stream 操作分类

Stream 的操作分为两大类:

  • 中间操作(Intermediate operations)

    • 只对操作进行了记录,即只会返回一个流,不会进行计算操作
    • 无状态(Stateless):元素的处理不受之前元素的影响
    • 有状态(Stateful):只有拿到所有元素之后才能继续下去
  • 终结操作(Terminal operations)

    • 终结操作是实现了计算操作
    • 短路(Short-circuiting):遇到某些符合条件的元素就可以得到最终结果
    • 非短路(Unshort-circuiting):必须处理完所有元素才能得到最终结果

串行处理和并行处理

  • 串行处理操作

    • Stream 在执行每一步中间操作时,并不会做实际的数据操作处理,而是将这些中间操作串联起来,生成一个数据处理链表,通过 Spliterator 迭代器进行数据处理。
    • 每执行一次迭代,就对所有的无状态的中间操作进行数据处理,而对有状态的中间操作,就需要迭代处理完所有的数据,再进行处理操作
    • 最后进行终结操作的数据处理。
  • 并行处理操作(parallel()):

    • Stream 对中间操作基本跟串行处理方式是一样的
    • 终结操作中,Stream 将结合ForkJoin对集合进行切片处理,ForkJoin 框架将每个切片的处理结果 Join 合并起来

建议

在循环迭代次数较少的情况下,常规的迭代方式性能其实更好,尤其是服务器CPU只有单核

服务器是多核 CPU 的情况下,Stream 的并行迭代优势明显。

所以在平时处理大数据的集合时,应该尽量考虑将应用部署在多核 CPU 环境下,并且使用 Stream 的并行迭代方式进行处理

posted @ 2021-01-18 17:02  阿dun  阅读(770)  评论(0编辑  收藏  举报