Java8出来有一年多的时间了,在最开始出来的时候,我只是简单的看了一下他的文档,并且看了一下其中的一些例子,并没有将自己的日常开发切换到Java8中,最近的项目开发中,公司要求将JDK的平台升级到Java8中,因此我觉得有必要逐渐梳理一下Java8中的一些新的特性,Java8其实在Java的发展过程中绝对是里程碑式的存在,有很多很多新颖的编程方式,可以这么说吧,Lambda的出现改变了Java的编程方式,使这门语法紧凑的纯纯面向对象的语言,开始兼容函数式编程的风格,我不想评价是不是进步(因为面向函数的语言其实已经很多了,并且很流行),但是最起码Java平台做出来改变,我更想说是一种演进和演变。
我们来一起学习一下Java8的新特性Stream,其中可能需要你具备一些Lambda的知识,一些Collections的知识,然后我们就快速上手吧,其中为了说明并行计算,我可能会介绍一下JDK7中的Fork Join和快速排序算法等。
一、Stream简单介绍
Stream是Java8中比较闪亮的一个新特性,但是它绝对不等同于IO包中的Stream和解析XML的Stream,JAVA 8中的Stream也不是一个容器,它绝对不是用来存储数据的,他是对JDK中Collections的一个增强,他只专注于对集合对象的便利,高效的聚合操作,它不仅支持串行的操作功能,而且还借助JDK1.7 中的Fork-Join机制支持了并行模式,你无需编写任何一行并行相关的代码,就能高效方便的写出高并发的程序,尤其在现在多核CPU的时代,最大程度的利用CPU的超快计算能力显得尤为重要。
二、Stream之Hello World
在开始介绍Stream的各个使用细节的时候,我们先来快速看一个入门的示例,先有一个简单的认识,为了能够体现出来Stream的便捷,我们同样的需求,分别使用传统的方式和Stream的方式各实现一次。
2.1 需求描述
在一个水果的集合中,获取苹果这一个单品并且以价格降序的方式形成一个新的集合,这个新的集合中只存放价格,也就是List<Integer>,虽然这个例子在实际中有些扯淡,但是我们为了简单演示一下如何使用Stream,所以重点关注用法,不用理会需求的严谨与否。
2.2 代码实现
Fruit类,代码如下:
package com.wangwenjun.stream; /** * Created by wangwenjun on 2015/8/8. */ public class Fruit { private final String name; private final double price; public Fruit(String name, double price) { this.name = name; this.price = price; } public String getName() { return name; } public double getPrice() { return price; } } |
FruitSelector类,代码如下
package com.wangwenjun.stream; import java.util.ArrayList; import java.util.List; /** * Created by wangwenjun on 2015/8/8. */ public abstract class FruitSelector { protected final static String CANDIDATE_FRUIT = "apple"; private List<Fruit> getData(){ final List<Fruit> data = new ArrayList<Fruit>(){ { add(new Fruit("apple",22.1)); add(new Fruit("apple",22.2)); add(new Fruit("apple",22.3)); add(new Fruit("apple",22.4)); add(new Fruit("apple",22.5)); add(new Fruit("apple",22.6)); add(new Fruit("apple",22.7)); add(new Fruit("orange",22.8)); add(new Fruit("orange",22.9)); add(new Fruit("orange",23.0)); add(new Fruit("orange",23.1)); add(new Fruit("orange",24.2)); add(new Fruit("orange",22.3)); add(new Fruit("banana",22.4)); add(new Fruit("banana",22.2)); add(new Fruit("banana",22.2)); add(new Fruit("banana",22.2)); add(new Fruit("banana",22.2)); } }; return data; } public List<Double> select() { List<Fruit> fruits= getData(); return doFilter(fruits); } protected abstract List<Double> doFilter(final List<Fruit> fruits); } |
IteratorFruitSelector类代码如下,他是使用我们传统迭代的方式去做这样的工作。
package com.wangwenjun.stream; import java.util.*; public class IteratorFruitSelector extends FruitSelector { @Override protected List<Double> doFilter(List<Fruit> fruits) { //get the fruit name is 'apple' List<Fruit> appleList = new ArrayList<>(); Iterator<Fruit> iterator = fruits.iterator(); for (; iterator.hasNext(); ) { Fruit fruit = iterator.next(); if (fruit.getName().equals(CANDIDATE_FRUIT)) { appleList.add(fruit); } } //do sort. Collections.sort(appleList, (o1, o2) -> { if (o1.getPrice() > o2.getPrice()) return 1; else if (o1.getPrice() == o2.getPrice()) return 0; else return -1; }); //do filter. List<Double> applePriceList = new ArrayList<>(); for (Fruit fruit : appleList) { applePriceList.add(fruit.getPrice()); } return applePriceList; } } |
我们使用Stream的方式看看,代码如何去写呢?
package com.wangwenjun.stream; import java.util.Comparator; import java.util.List; import static java.util.stream.Collectors.toList; /** * Created by wangwenjun on 2015/8/8. */ public class StreamFruitSelector extends FruitSelector { @Override protected List<Double> doFilter(List<Fruit> fruits) { return fruits.stream().filter(f -> f.getName().equals(CANDIDATE_FRUIT)) .sorted(Comparator.comparing(Fruit::getPrice)) .map(Fruit::getPrice) .collect(toList()); } } |
代码写完了,简单对照一下,你是不是能看出来,采用Stream的方式比传统的方式要简洁很多很多,代码量至少少了2/3.
2.3 简单测试
好了,我们写一下单元测试,看看是不是两者运行情况一样呢?当然我们并没有测试性能的意思,如果你想测试性能,可以把数据量改到很大,并且Stream采用并行的工作模式,差异还是蛮多的。
package com.wangwenjun.stream; import org.junit.Test; import java.util.List; /** * Created by wangwenjun on 2015/8/8. */ public class FruitSelectorTest { @Test public void testIterator() { FruitSelector selector = new IteratorFruitSelector(); List<Double> result = selector.select(); System.out.println(result); } @Test public void testStream() { FruitSelector selector = new StreamFruitSelector(); List<Double> result = selector.select(); System.out.println(result); } } |
运行结果不言而喻了吧
[22.1, 22.2, 22.3, 22.4, 22.5, 22.6, 22.7] [22.1, 22.2, 22.3, 22.4, 22.5, 22.6, 22.7] |
完整文档下载地址在: http://download.csdn.net/detail/wangwenjun69/8981633