Aggregate聚合操作之stream的抛砖引玉

Aggregate 聚合操作

嗯。项目开始小忙碌,最近一直没有更新。不能犯懒。。 JDK8中引进了Lambda表达式,Method Reference方法参照,以及default方法,static方法在interface中的使用。其实,这些也还都是铺垫,虽然说Lambda表达式的概念在JDK8没有出来的时候就开始炒作,但是我认为JDK8最引人注意的应该还是Aggregate 聚合操作的引入以及这个概念带来的一些思维方式的改变。 先不管写法是否丑陋效果是否有强加性,其实Aggregate的出现和实现方式都体现了当下一个简单著名算法的影子:MapReduce。

原创原文:blog.csdn.net/forevervip 下面开始依托javase的文档来粗粗了解一下聚合操作。

管道与数据流 pipelines and streams

在JDK8中,我们的collections后会“点”出来一个stream。

Person[] rosterAsArray = roster.toArray(new Person[roster.size()]);roster.stream()

这个stream即是这次的主角,数据流。 先看一个例子: 假设roster是一个List<Person>的list,那么我们如果循环这个list,可以采用下面的写法

for (Person p : roster) {System.out.println(p.getName());}

而,如果使用stream的数据流写法则:

roster.stream().forEach(e -> System.out.println(e.getName());

去掉回车的话,其实只有一行:

roster.stream().forEach(e -> System.out.println(e.getName());

stream后紧接着进行了一个forEach的操作,这个操作其实很多弱语言都有,比如javascript。而forEach中调用了一个Lambda表达式,表达式的内容很简单,其实就是一个打印。 forEach方法中使用的参数是:

forEach(Consumer<? super Integer>)

Consumer和上一篇中写到的Supplier类似,都是java.util.function中的函数式接口中的一员。 代码如下:

/* * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */package java.util.function;import java.util.Objects;/** * Represents an operation that accepts a single input argument and returns no * result. Unlike most other functional interfaces, {@code Consumer} is expected * to operate via side-effects. * * <p>This is a <a href=”package-summary.html”>functional interface</a> * whose functional method is {@link #accept(Object)}. * * @param <T> the type of the input to the operation * * @since 1.8 */<T> {/*** Performs this operation on the given argument.** @param t the input argument*/void accept(T t);/*** Returns a composed {@code Consumer} that performs, in sequence, this* operation followed by the {@code after} operation. If performing either* operation throws an exception, it is relayed to the caller of the* composed operation. If performing this operation throws an exception,* the {@code after} operation will not be performed.** @param after the operation to perform after this operation* @return a composed {@code Consumer} that performs in sequence this* operation followed by the {@code after} operation* @throws NullPointerException if {@code after} is null*/default Consumer<T> andThen(Consumer<? super T> after) {Objects.requireNonNull(after);return (T t) -> { accept(t); after.accept(t); };}}

可以看到,这里的accept方法即使我们的Lambda表达式要去实现的方法,这个实现以及方法很简单。不做多的说明。

继续看一个例子: 我们需要一个条件,符合条件的数据再进行打印的处理:

for (Person p : roster) {if (p.getGender() == Person.Sex.MALE) {System.out.println(p.getName());}}

OK,采用stream的写法如下(一行太长,采用多行的写法):

roster.stream().filter(e -> e.getGender() == Person.Sex.MALE).forEach(e -> System.out.println(e.getName()));

其中,forEach和上一个一样,而多出来的是filter的这个中间方法的调用。 可以看到,filter中也是一个Lambda表达式,filter的调用原型:

filter(Predicate<? super T> predicate)

是的,Predicate也是java.util.function的函数式接口,代码内部有兴趣可以去看看源码。

以上的方法调用即为管道聚合操作,这种操作有如下的特点

要有一个数据源。一般可以是collection,数组(array),函数生成器(generator function 其实这个的使用可能还是会归结到数组和collection),或者I/O数据通道。例子中我们使用了一个collection。0个或者多个的中间操作过程。例子中我们使用了一个filter,从而生成了一个新的stream数据流。 数据流是一系列的元素,和collection不同的是,它并不作为存储结构来存储数据,而形象点的形容,它就是一个可以传输数据的通道,,例子中的Predicate这个函数式接口的方法为boolean test(T t),所以Lambda表达式的e -> e.getGender() == Person.Sex.MALE 当性别是男性的时候可以返回一个true。filter根据返回值会重新生成一个性别都是男性的stream。一个结束操作。这个操作可以做成一个非stream的结果,也可以是一个java的原始数据类型,也可以是一个collection,也或者是例子中的forEach并不返回任何数据。例子中采用的是Lambda表达式打印名字。

再看一个例子:

double average = roster.stream().filter(p -> p.getGender() == Person.Sex.MALE).mapToInt(Person::getAge).average().getAsDouble();去追寻那飞翔的翅膀。落叶随风淡定了它漂泊的方向。

Aggregate聚合操作之stream的抛砖引玉

相关文章:

你感兴趣的文章:

标签云: