Java 8: Lambdas和新的集合Stream API

13-06-20 banq
Lambda是Java8的主要特色,Java 8: Lambdas & Java Collections | zeroturnaround.com一文介绍了使用Lambda集合处理大量数据的方法。

首先Java集合引入了内部遍历,原来 LambdaJ下面这种方法也可以在Java8中实现:

List<Person> persons = asList(new Person("Joe"), new Person("Jim"), new Person("John"));
forEach(persons).setLastName("Doe");
<p class="indent">

Java8类似这种遍历方式如下:
persons.forEach(p -> p.setLastName("Doe"))

Java8 JDK主要引入了一个新的API: Stream API来处理大数据,可以用集合执行filter/map/reduce-之类的操作。

使用Stream APIk可以对一个数据流实现顺序或并行操作。

ist<Person> persons = … 
 
// sequential version
Stream<Person> stream = persons.stream();
 
//parallel version 
Stream<Person> parallelStream = persons.parallelStream();
<p class="indent">


java.util.stream.Stream提供了一种操作大量数据接口,当得到一个stream实例后,能够实现下面有趣的集合操作:

1.Filter

过滤操作是首先很自然的一个操作(类似SQL where查询语句)

List<Person> persons = …
Stream<Person> personsOver18 = persons.stream().filter(p -> p.getAge() > 18);
<p class="indent">

(banq注:有了这样强大过滤功能,以后过滤查询别老是惦记着用SQL语句了,负载都集中到数据库上了,如果数据量再大就用Hadoop/hive)。

2. MAP
当我们有了过滤好的数据,我们能够实现业务操作,比如对象迁移。如果使用内部类是如下代码:

Stream<Student> students = persons.stream()
      .filter(p -> p.getAge() > 18)
      .map(new Function<Person, Student>() {
                  @Override
                  public Student apply(Person person) {
                     return new Student(person);
                  }
              });
<p class="indent">


但是使用lambda语法很简单:

Stream<Student> map = persons.stream()
        .filter(p -> p.getAge() > 18)
        .map(person -> new Student(person));
<p class="indent">

因为mao方法参数是一种函数参数consumer,因此我们还可以传入方法如下:

Stream<Student> map = persons.stream()
        .filter(p -> p.getAge() > 18)
        .map(Adult::new);
<p class="indent">



banq
2013-06-20 08:22
前面我们已经实现对数据流的操作,最后我们需要收集总结这些数据结果,collect() 让我们实现这点:

List<Student> students = persons.stream()
        .filter(p -> p.getAge() > 18)
        .map(Adult::new)
        .collect(new Collector<Student, List<Student>>() { … });
<p class="indent">

上面实现了自己的Collector接口,大部分情况下可能不需要:

List<Student> students = persons.stream()
        .filter(p -> p.getAge() > 18)
        .map(Student::new)
        .collect(Collectors.toList());
<p class="indent">


也可以指定集合具体类型:

List<Student> students = persons.stream()
        .filter(p -> p.getAge() > 18)
        .map(Student::new)
        .collect(Collectors.toCollection(ArrayList::new));

<p class="indent">


有关顺序和并行操作:
Stream API并不需要显式声明顺序或并行,在进行consumer时是并行,然后切换到顺序:

List<Student> students = persons.stream()
        .parallel()
        .filter(p -> p.getAge() > 18)  // filtering will be performed concurrently
        .sequential()
        .map(Student::new)
        .collect(Collectors.toCollection(ArrayList::new));
<p class="indent">

filter函数默认是并行操作。

gameboyLV
2013-06-20 22:00
Linq笑了,呵呵。。。。

JasonMing
2014-06-21 01:05
Java委员会终于撑不住了,之前一直说lambda没用的,用那个内部匿名类就够了。。。
结果,开发个android的程序,简单的弹个toast,轻松10行代码,呵呵~~~
这里出的东西都没啥激动人心的,C里面linq extension就把这里的所谓的stream api覆盖完全了,而且还可以随意扩展自己的代码库,不用加入任何包装类。
这里的stream就是给原来个包装,自己开发个类库,呵呵,继续包装,想想都开心。

而且期待这么久的真实泛型还是没有啊,就是擦除也留点信息给运行时啊,到现在还是只能用匿名实现子类的恶心方法来拿T在运行时的值。