`

Java 8新特性探究(3):解开lambda最强作用的神秘面纱

    博客分类:
  • J2SE
 
阅读更多

文章源自:http://developer.51cto.com/art/201404/435591.htm

 

1.关于JSR335

JSR是Java Specification Requests的缩写,意思是Java 规范请求,Java 8 版本的主要改进是 Lambda 项目(JSR 335),其目的是使 Java 更易于为多核处理器编写代码。JSR 335=lambda表达式+接口改进(默认方法)+批量数据操作。加上前面两篇,我们已是完整的学习了JSR335的相关内容了。

2.外部VS内部迭代

以前Java集合是不能够表达内部迭代的,而只提供了一种外部迭代的方式,也就是for或者while循环。

 

List persons = asList(new Person("Joe"), new Person("Jim"), new Person("John"));  
for (Person p :  persons) {  
   p.setLastName("Doe");  
} 

 

上面的例子是我们以前的做法,也就是所谓的外部迭代,循环是固定的顺序循环。在现在多核的时代,如果我们想并行循环,不得不修改以上代码。效率能有多大提升还说定,且会带来一定的风险(线程安全问题等等)。 
要描述内部迭代,我们需要用到Lambda这样的类库,下面利用lambda和Collection.forEach重写上面的循环

 

persons.forEach(p->p.setLastName("Doe"));

 

现在是由jdk 库来控制循环了,我们不需要关心last name是怎么被设置到每一个person对象里面去的,库可以根据运行环境来决定怎么做,并行,乱序或者懒加载方式。这就是内部迭代,客户端将行为p.setLastName当做数据传入api里面。 

内部迭代其实和集合的批量操作并没有密切的联系,借助它我们感受到语法表达上的变化。真正有意思的和批量操作相关的是新的流(stream)API。新的java.util.stream包已经添加进JDK 8了。

3.Stream API

流(Stream)仅仅代表着数据流,并没有数据结构,所以他遍历完一次之后便再也无法遍历(这点在编程时候需要注意,不像Collection,遍历多少次里面都还有数据),它的来源可以是Collection、array、io等等。

3.1中间与终点方法

流作用是提供了一种操作大数据接口,让数据操作更容易和更快。它具有过滤、映射以及减少遍历数等方法,这些方法分两种:中间方法和终端方法,“流”抽象天生就该是持续的,中间方法永远返回的是Stream,因此如果我们要获取最终结果的话,必须使用终点操作才能收集流产生的最终结果。区分这两个方法是看他的返回值,如果是Stream则是中间方法,否则是终点方法。具体请参照Stream的api
简单介绍下几个中间方法(filter、map)以及终点方法(collect、sum)

3.1.1Filter

在数据流中实现过滤功能是首先我们可以想到的最自然的操作了。Stream接口暴露了一个filter方法,它可以接受表示操作的Predicate实现来使用定义了过滤条件的lambda表达式。

 

List persons = …  
Stream personsOver18 = persons.stream().filter(p -> p.getAge() > 18);//过滤18岁以上的人 

 

3.1.2Map

假使我们现在过滤了一些数据,比如转换对象的时候。Map操作允许我们执行一个Function的实现(Function<T,R>的泛型T,R分别表示执行输入和执行结果),它接受入参并返回。首先,让我们来看看怎样以匿名内部类的方式来描述它:

 

Stream adult= persons  
              .stream()  
              .filter(p -> p.getAge() > 18)  
              .map(new Function() {  
                  @Override 
                  public Adult apply(Person person) {  
                     return new Adult(person);//将大于18岁的人转为成年人  
                  }  
              }); 

 

现在,把上述例子转换成使用lambda表达式的写法:

 

Stream map = persons.stream()  
                    .filter(p -> p.getAge() > 18)  
                    .map(person -> new Adult(person)); 

 

 

3.1.3Count

count方法是一个流的终点方法,可使流的结果最终统计,返回int,比如我们计算一下满足18岁的总人数

 

int countOfAdult=persons.stream()  
                       .filter(p -> p.getAge() > 18)  
                       .map(person -> new Adult(person))  
                       .count(); 

 

 

3.1.4Collect

collect方法也是一个流的终点方法,可收集最终的结果

 

List adultList= persons.stream()  
                       .filter(p -> p.getAge() > 18)  
                       .map(person -> new Adult(person))  
                       .collect(Collectors.toList()); 

 

或者,如果我们想使用特定的实现类来收集结果:

 

List adultList = persons  
                 .stream()  
                 .filter(p -> p.getAge() > 18)  
                 .map(person -> new Adult(person))  
                 .collect(Collectors.toCollection(ArrayList::new)); 

 

篇幅有限,其他的中间方法和终点方法就不一一介绍了,看了上面几个例子,大家明白这两种方法的区别即可,后面可根据需求来决定使用。

3.2顺序流与并行流

每个Stream都有两种模式:顺序执行和并行执行。
顺序流:

 

List <Person> people = list.getStream.collect(Collectors.toList()); 

 

并行流:

 

List <Person> people = list.getStream.parallel().collect(Collectors.toList()); 

 

顾名思义,当使用顺序方式去遍历时,每个item读完后再读下一个item。而使用并行去遍历时,数组会被分成多个段,其中每一个都在不同的线程中处理,然后将结果一起输出。

3.2.1并行流原理:

 

List originalList = someData;  
split1 = originalList(0, mid);//将数据分小部分  
split2 = originalList(mid,end);  
new Runnable(split1.process());//小部分执行操作  
new Runnable(split2.process());  
List revisedList = split1 + split2;//将结果合并 

 

大家对hadoop有稍微了解就知道,里面的 MapReduce  本身就是用于并行处理大数据集的软件框架,其 处理大数据的核心思想就是大而化小,分配到不同机器去运行map,最终通过reduce将所有机器的结果结合起来得到一个最终结果,与MapReduce不同,Stream则是利用多核技术可将大数据通过多核并行处理,而MapReduce则可以分布式的。

3.2.2顺序与并行性能测试对比

如果是多核机器,理论上并行流则会比顺序流快上一倍,下面是测试代码

 

long t0 = System.nanoTime();  
 
//初始化一个范围100万整数流,求能被2整除的数字,toArray()是终点方法  
 
int a[]=IntStream.range(0, 1_000_000).filter(p -> p % 2==0).toArray();  
 
long t1 = System.nanoTime();  
 
//和上面功能一样,这里是用并行流来计算  
 
int b[]=IntStream.range(0, 1_000_000).parallel().filter(p -> p % 2==0).toArray();  
 
long t2 = System.nanoTime();  
 
//我本机的结果是serial: 0.06s, parallel 0.02s,证明并行流确实比顺序流快  
 
System.out.printf("serial: %.2fs, parallel %.2fs%n", (t1 - t0) * 1e-9, (t2 - t1) * 1e-9); 

 

 

3.3关于Folk/Join框架

应用硬件的并行性在java 7就有了,那就是 java.util.concurrent 包的新增功能之一是一个 fork-join 风格的并行分解框架,同样也很强大高效,有兴趣的同学去研究,这里不详谈了,相比Stream.parallel()这种方式,我更倾向于后者。

 

4.总结

如果没有lambda,Stream用起来相当别扭,他会产生大量的匿名内部类,比如上面的3.1.2map例子,如果没有default method,集合框架更改势必会引起大量的改动,所以lambda+default method使得jdk库更加强大,以及灵活,Stream以及集合框架的改进便是最好的证明。

 

 

分享到:
评论
发表评论

文章已被作者锁定,不允许评论。

相关推荐

    全网详解(波哥)Java8新特性(Lambda、Stream、LocalDate等)新特性

    全网详解(波哥)Java8新特性(Lambda、Stream、LocalDate等)新特性 自学java的同行们应该都要学习java8的新特性,譬如:(Lambda、Stream、LocalDate等)!本人在学习java的时候看的是波哥的视频,确实讲的不错,很...

    Java 8新特性之Lambda与函数式编程.pdf

    Java 8是Java语言发展史上一个重要的里程碑,它引入了多种新特性,旨在增强Java语言表达能力和提升开发效率。其中,Lambda表达式和函数式编程的支持是最具影响力的变化之一。 函数式编程是一种编程范式,它将计算视...

    java8新特性(Stream,lambda等)

    Java 8是Java语言的一个重要版本,引入了许多创新特性,极大地提升了开发效率和代码的可读性。其中,Stream API和Lambda表达式是最为显著的两大亮点,它们为处理集合数据提供了新的方式,并且简化了多线程编程。下面...

    Java8 新特性

    6. **日期与时间API**:Java8改进了日期和时间的处理,引入了新的java.time包,包含了LocalDate、LocalTime、LocalDateTime、ZonedDateTime等类,提供了更强大且易于使用的日期和时间操作。 7. **Optional类**:...

    Java8 新特性探究.pdf

    Java8是Java编程语言的一个重要版本,它在2014年3月发布,引入了许多新特性和改进,这些新特性旨在简化Java编程,提高开发效率,并扩展Java的用途。本文将详细介绍Java8的一些关键特性,特别是lambda表达式、函数式...

    Java 8 新特性之Stream 和 Lambda

    Java 8 新特性之Stream 和 Lambda

    Java8新特性之lambda的作用_动力节点Java学院

    Java8新特性之lambda的作用_动力节点Java学院,动力节点口口相传的Java黄埔军校

    Java系列JDK 1.8 新特性之 Lambda表达式.pdf

    Lambda表达式是Java 8中引入的一个重要新特性,它允许开发者以一种更加简洁的方式编写函数式接口实现代码。Lambda表达式本质上是一个匿名函数,能够作为一个参数传递给方法调用或存储在变量中,这使得Java支持了更高...

    java8源码-java8-sample:该项目仅用于学习java8

    解开lambda最强作用的神秘面纱 Chapter 4: 类型注解 复杂还是便捷 Chapter 5: 重复注解(repeating annotations) Chapter 6: 泛型的目标类型推断 Chapter 7: 深入解析日期和时间-JSR310 Chapter 8: 精简的JRE详解 ...

    探索Java 8的新世界:Lambda表达式全解析

    ### Java 8 中 Lambda 表达式的全解析 #### 引言 Java 8 自发布以来,便成为了 Java 发展史上的一大里程碑。...对于希望深入了解 Java 8 新特性的开发者而言,掌握 Lambda 表达式的使用技巧是必不可少的一步。

    黑马程序员_java8新特性详解笔记和源码

    本文将深入探讨Java 8的三大关键新特性:接口的默认方法实现、Lambda表达式以及一系列相关的变化。 一、接口的默认方法实现 在Java 8之前,接口只能定义抽象方法,而不能包含具体实现。Java 8引入了默认方法...

    java8新特性

    4. **流(Stream)**:Java 8引入了流API,它提供了一种对集合数据进行操作的新方式,特别适合于并行处理。流可以进行过滤、映射、聚合等操作,使代码更具有声明性。例如,`list.stream().filter(e -&gt; e &gt; 10).collect...

    java8新特性,Lambda表达式

    Java 8是Java编程语言的一个重大更新,引入了许多新特性,其中最为显著的就是Lambda表达式。Lambda表达式是函数式编程的关键元素,它允许我们以更简洁的方式编写匿名函数,从而简化了处理集合数据和事件驱动编程的...

    java8源码-javase8-sample:javase8-sample.git

    解开lambda最强作用的神秘面纱 Chapter 4: 类型注解 复杂还是便捷 Chapter 5: 重复注解(repeating annotations) Chapter 6: 泛型的目标类型推断 Chapter 7: 深入解析日期和时间-JSR310 Chapter 8: 精简的JRE详解 ...

    java8源码-javase8-sample:javase8-sample

    解开lambda最强作用的神秘面纱 Chapter 4: 类型注解 复杂还是便捷 Chapter 5: 重复注解(repeating annotations) Chapter 6: 泛型的目标类型推断 Chapter 7: 深入解析日期和时间-JSR310 Chapter 8: 精简的JRE详解 ...

    java8新特性-最新

    在Java 8中,最重要的两个新特性无疑是Lambda表达式和Stream API。这两个特性都与函数式编程思想密切相关,让Java开发者能够更加灵活地处理数据。 ### Lambda表达式 Lambda表达式是Java 8中最显著的新特性之一,它...

    Java 8 lambda表达式

    - **函数式编程**:Java 8引入了`java.util.Function`等接口,以及`Stream API`,允许开发者使用lambda表达式进行函数式编程,如映射、过滤、聚合等操作。 4. **并行处理**:通过`java.util.concurrent.ForkJoin...

    java8新特性代码

    总结起来,Java8的Lambda表达式、函数式接口、默认方法和静态方法这些新特性,极大地改进了Java的编程模型,让代码更加简洁、易读和高效。通过熟练掌握这些特性,开发者可以编写出更加优雅和强大的程序,同时也为...

Global site tag (gtag.js) - Google Analytics