Java:聚集操作

你使用集合的目的是什么?当然不是为了简单的存储然后置之不理,你是为了从集合取数据和操作数据的。

再次考虑前一篇文章提到的背包类,

如果要打印所有背包的重量,

for(Package p : packages)
    System.out.println(p.getWeight());

遍历,可以使用"forEach"这一聚集操作,

packages.stream()
             .forEach(e -> System.out.println(p.getWeigh());

看不懂语法不要紧。我们再来个稍微复杂一点的,

我们只打印“重量大于20的背包重量”,

packages.stream()
             .filter(e -> e.getWeight() > 20)
             .forEach(e - > System.out.println(e.getWeight());

分析其结构,

packages是个集合,stream()方法是获取其“流”,能产生流的不只是集合,数组,I/O通道都可以。下面就是管道操作(和MongoDB或是Linux下的管道类似)了。即有0个或若干个中间操作,如这里的filter,来产生新的流,然后有一个终结操作,它可以有返回值(不再是一个流),也可以没有返回值。

其中,filter的函数原型是:

Stream<T> filter<Predicate<? super T> p)

接受一个谓词参数(条件)。

查看java.util.strem下面的API,其操作时很多的,部分如下,

具体用法不一一介绍。

我们再看一个需求,求“重量大于20的背包的平均重量”。

double average = packages
       .stream()
       .filter(e -> e.getWeight() > 20)
       .mapToInt(e -> e.getWeigh())
       .average()
       .getAsDouble();

除了filter表示过滤,还有maptoInt,返回一个IntStream。

函数原型是,

IntStream maptoInt(toIntFunction<? super T> mapper)

其参数是一个返回Int的lambda表达式。

average()是IntStream的方法,很明显,是取平均值的,返回一个OptionalDouble,你可以回想OptionalDouble是什么?怎么不直接返回Double!!OptionalDouble是java8新加的,类似的API很多,它的特点是该对象可能包含也可能不包含一个值。作用在于:传统方法返回一个为Null的值,继续操作会报NullException,如果OptionalXX没有值,是可以继续操作的(当然没有值getAsDouble会报NoSuchElement异常。

另外,average这个终结操作也是reduction 操作。

在JDK里面,像average,sum,min等都是通过组合流的内容返回一个值,这些操作称为reduction操作。当然,有点reduction操作返回一个集合而不是一个值。值得一提的是,JDK还提供了两个一般化的操作:reduce和collect。

假设我们需要对背包容量求和,

Integer total = packages
        .stream()
        .mapToInt(e -> e,getWeight())
        .sum();

如果要用reduce对它改造,

Integer total = packages
        .stream()
        .mapToInt(e -> e,getWeight())
        .reduce(0,(a,b) -> a + b);

如果使用函数引用,

Integer total = packages
        .stream()
        .mapToInt(e -> e,getWeight())
        .reduce(0,Integer::sum);

查看reduce的函数原型:

T reduce(T indentidy,BinaryOperator<T> accumulator)

这可能比较费解,

API是这样介绍的,using the provided identity value and an associative accumulation function。

先看是associative,“结合性”,就是说要满足,

a op b op c = a op (b op c)

像加法,最小值,最大值,字符拼接都有这个性质。

API 还说,reduce函数等价于,

 T result = identity;
     for (T element : this stream)
         result = accumulator.apply(result, element)
     return result;

那identy是什么呢?对于操作的集合的所有t,应该有

accumulator.apply(identity, t) = t

是的,它就是离散数学里面提到的1元。对加法而言,1元就是0。

reduce操作总会返回新的值。然而,累积函数在每次处理流中的一个元素时也返回一个新的值。假设你要把流“reduce”成一个集合,你每添加一个元素处理就会产生一个新的结合,这显然是个性能上的缺憾,是很低效的。这时,你可以考虑更新已有的集合。这就是collect方法做的事情。

下一篇再介绍collect的使用细节。

时间: 09-09

Java:聚集操作的相关文章

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)关闭输入/输出 字符流与字节流的区别: 字节流在操作时本身不会用到缓冲区(内存),是文件本身直接

HDFS基础和java api操作

1. 概括 适合一次写入多次查询情况,不支持并发写情况 通过hadoop shell 上传的文件存放在DataNode的block中,通过linux shell只能看见block,看不见文件(HDFS将客户端的大文件存放在很多节点的数据块中,Block本质上是一个逻辑概念,它是hdfs读写数据的基本单位) HDFS中,如果一个文件小于一个数据块的大小,并不占用整个数据块存储空间 2. fs 可以使用hdfs shell操作hdfs,常用 fs命令如下: eg: hadoop fs -cat fi

java PreparedStatement操作oracle数据库

import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; //import java.sql.Statement; import java.sql.PreparedStatement; public class lx02{ public static void main(String[] args) throws SQLException, ClassNotFoundException

HDFS的Java客户端操作代码(HDFS的查看、创建)

1.HDFS的put上传文件操作的java代码: 1 package Hdfs; 2 3 import java.io.FileInputStream; 4 import java.io.FileNotFoundException; 5 import java.io.IOException; 6 import java.net.URI; 7 8 import org.apache.hadoop.conf.Configuration; 9 import org.apache.hadoop.fs.F