Java : 聚集操作(2)

不像reduce操作,每处理一个元素就会产生一个新值,collect方法只更新已有的值。

还是假设要求背包的平均重量,你需要哪些值?总重量和总个数。你可以新建一个数据类型包含并追踪这两个变量。

class Averager implements IntConsumer
{
    private int total = 0;
    private int count = 0;

    public double average() {
        return count > 0 ? ((double) total)/count : 0;
    }

    public void accept(int i) { total += i; count++; }
    public void combine(Averager other) {
        total += other.total;
        count += other.count;
    }
}

IntCousumer接口接受一个int类型的参数,不返回任何值。Averager的accept是重写的。

下面就是管道如何使用Averager和collect完成求平均值。

Averager average =
         packages.stream()
         .map(Package::getWeight)
         .collect(Averager::new,
         	Averager::accept,Averager::combine)

这里使用的是函数引用,没有用Lambda表达式。注意,collect操作的容器必须是可变的。

先看collect的函数原型,

 <R> R collect(Supplier<R> supplier,
 	            BiConsumer<R,? super T> accumulator,
 	            BiConsumer<R,R> combine)

第一个参数Supplier表示结果集的装配类型。BiConsumer的接受两个参数,不返回结果的操作。

第二个参数和第三个参数都要是“可结合的”,“无状态的”,"非干涉的"。分别是“把一个元素加入结果”,“组合两个结果(就是一个merger过程)”。

“可结合性”前一篇文章已说明了。这里对后两个性质说明一下。

一个有状态的Lambda表达式是指其结果依赖于任何在管道执行中可能改变的状态。这个说法有点拗口,其英文原话是:

 A stateful lambda is one whose result depends on any state which might change during the execution of the stream pipeline

下面在map里的函数就是有状态的,

Set<Integer> seen = Collections.synchronizedSet(new HashSet<>());
     stream.parallel().map(e -> { if (seen.add(e)) return 0; else return e; })...

对于相同的输入,对多线程并发操作时,结果可能是不同的。

流操作允许你执行并行计算,即使是对ArrayList那样的非线程安全集合。这就要求我们要防止数据源的干涉。对大多数数据源,防止干涉就是指确保在管道操作时不能修改。有个例外是,当数据源是并行集合。注意,要求“非干涉”对所有管道都适合,不只是对并行计算。除了已经是并行集合(Current Collection),在执行时修改数据源是会导致异常的,或是错误的结果。对一个行为良好的流,对数据源的修改应该反映到所涉及的元素。

List<String> l = new ArrayList(Arrays.asList("one", "two"));
     Stream<String> sl = l.stream();
     l.add("three");
     String s = sl.collect(joining(" "));

我们去修改l,最后sl还是会变化的,只要这个修改发生在终结操作前。

它等价于,

 R result = supplier.get();
     for (T element : this stream)
         accumulator.accept(result, element);
     return result;

再来一个例子,完成字符串拼接,

String concat = stringStream.collect(StringBuilder::new, StringBuilder::append,
                                          StringBuilder::append)
                                 .toString();

collect操作最适合集合操作。下面是把所有背包的重量放入一个List<Integer>集合,

List<Integer> weights = packages.stream()
             .mapToInt(p -> p.getWeight())
             .collect(Collectors.toList());

这个版本的collect只有一个参数Collector,这个类封装了collect所需要的supplier,accumulator和combine。

Collectors包含很多有用的reduction操作,并都返回Collector。

上面的toList方法,会累积流的元素到一个新的List实例。

假设背包是由颜色的,有color属性,并有setter和getter。我们按颜色给它们分类:

Map<String color,List<Package> byColor
   = packages.stream()
    .collect(
         Collectors.groupingBy(Person::getColor)
    	);
时间: 2024-10-25 15:28:25

Java : 聚集操作(2)的相关文章

Java:聚集操作

你使用集合的目的是什么?当然不是为了简单的存储然后置之不理,你是为了从集合取数据和操作数据的. 再次考虑前一篇文章提到的背包类, 如果要打印所有背包的重量, for(Package p : packages) System.out.println(p.getWeight()); 遍历,可以使用"forEach"这一聚集操作, packages.stream() .forEach(e -> System.out.println(p.getWeigh()); 看不懂语法不要紧.我们再

单一目的聚集操作

聚集指的是,基于一个输入和特定程序来计算结果的数据操纵操作的广泛类别. MongoDB提供了大量在结果集上执行特定聚集操作的聚集操作方法. 尽量在使用范围上有限制,特别是和聚集管道.map-reduce相比较,但这些操作,为常规的数据处理提供了直接的语义. Count MongoDB可以返回符合一个query的文档数量.count命令,以及count()和cursor.count()方法提供访问mongo shell里面的计数(counts). 例子: 假设一个名叫records的集合,仅有下面

Java开发--操作MongoDB

http://www.cnblogs.com/hoojo/archive/2011/06/01/2066426.html介绍到了在MongoDB的控制台完成MongoDB的数据操作,通过前一篇文章我们对MongoDB有了全面的认识和理解.现在我们就用Java来操作MongoDB的数据. 开发环境: System:Windows IDE:eclipse.MyEclipse 8 Database:mongoDB 开发依赖库: JavaEE5.mongo-2.5.3.jar.junit-4.8.2.j

Java API操作HDFS

HDFS是存储数据的分布式文件系统,对HDFS的操作,就是对文件系统的操作,除了用HDFS的shell命令对文件系统进行操作,我们也可以利用Java API对文件系统进行操作,比如文件的创建.删除.修改权限等等,还有文件夹的创建.删除.重命名等等. 使用Java API对文件系统进行操作主要涉及以下几个类: 1.Configuration类:该类的对象封装了客户端或者服务端的配置. 2.FileSystem类:该类的对象是一个文件系统对象,可以利用该对象的一些方法来对文件进行操作,FileSys

JAVA批处理操作

批处理,可以大幅度提升大量增.删.改的速度,就是对大数据操作有很大的效率提升. 与上篇文章中提到的"连接池"相似.其实就是先将多次操作(增删改)打包,然后再一次发送执行 主要用到两个方法: ?  打包:PreparedStatement.addBatch(); ?  发送.执行:PreparedStatement.executeBatch(); 下面看做同一件事,用批处理和不用批处理的效率对比,源码如下: import java.sql.Connection; import java.

Java File操作汇总

作者:卿笃军 原文地址:http://blog.csdn.net/qingdujun/article/details/41223841 本文通过大量的示例,介绍和讲解了Java File操作. 1)创建文件  2)删除文件  3)判断文件是否存在  4)创建文件夹  5)文件类型判断  6)获取文件信息 7)获取目录下文件名  8)递归打印所有文件名  9)递归删除整个文件夹  10)Properties类 11)SequenceInputStream类:连接多个流  12)对象序列化实现Ser

Hadoop读书笔记(三)Java API操作HDFS

Hadoop读书笔记(一)Hadoop介绍:http://blog.csdn.net/caicongyang/article/details/39898629 Hadoop读书笔记(二)HDFS的shell操作:http://blog.csdn.net/caicongyang/article/details/41253927 JAVA URL 操作HDFS OperateByURL.java package hdfs; import java.io.InputStream; import jav

MongoDB 的聚集操作

聚合引言 聚集操作就是出来数据记录并返回计算结果的操作.MongoDB提供了丰富的聚集操作,能够检测和执行数据集上的计算.运行在mongod上的数据聚集简化了代码和资源限制. 像查询一样,在Mongo的聚合操作使用collections作为输入,并返回一个或多个document作为输出. 聚合模式 聚合管道 MongoDB2.2引入了一个新的聚合框架:聚合管道,这是基于数据处理管道概念的模型.文档输入一个多阶段的管道并将文档转化为一个聚合的结果. 最基本的管道阶段提供了过滤器(Filters)来

Java字节流操作

在java.io包中得操作主要有字节流与字符流两大类,两个类都有输入输出操作. 在字节流中,输出数据主要使用OutputStream类,输入使用的InputStream类. 在字符流中,输出数据使用Writer,输入数据使用Reader. 在Java中IO操作有相应的步骤,以文件的操作为例. (1)使用File类打开一个文件 (2)通过字节流或字符流的子类指定输出的位置. (3)进行读/写操作 (4)关闭输入/输出 字符流与字节流的区别: 字节流在操作时本身不会用到缓冲区(内存),是文件本身直接