用Java 8 增加的 Stream API 能实现哪些优雅的算法

Python013

用Java 8 增加的 Stream API 能实现哪些优雅的算法,第1张

Java 8引入了全新的Stream API。这里的Stream和I/O流不同,它更像具有Iterable的集合类,但行为和集合类又有所不同。

Stream API引入的目的在于弥补Java函数式编程的缺陷。对于很多支持函数式编程的语言,map()、reduce()基本上都内置到语言的标准库中了,不过,Java 8的Stream API总体来讲仍然是非常完善和强大,足以用很少的代码完成许多复杂的功能。

创建一个Stream有很多方法,最简单的方法是把一个Collection变成Stream。我们来看最基本的几个操作:

public static void main(String[] args) {

List<Integer>numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

Stream<Integer>stream = numbers.stream()

stream.filter((x) ->{

return x % 2 == 0

}).map((x) ->{

return x * x

}).forEach(System.out::println)

}

集合类新增的stream()方法用于把一个集合变成Stream,然后,通过filter()、map()等实现Stream的变换。Stream还有一个forEach()来完成每个元素的迭代。

为什么不在集合类实现这些操作,而是定义了全新的Stream API?Oracle官方给出了几个重要原因:

一是集合类持有的所有元素都是存储在内存中的,非常巨大的集合类会占用大量的内存,而Stream的元素却是在访问的时候才被计算出来,这种“延迟计算”的特性有点类似Clojure的lazy-seq,占用内存很少。

二是集合类的迭代逻辑是调用者负责,通常是for循环,而Stream的迭代是隐含在对Stream的各种操作中,例如map()。

要理解“延迟计算”,不妨创建一个无穷大小的Stream。

如果要表示自然数集合,显然用集合类是不可能实现的,因为自然数有无穷多个。但是Stream可以做到。

自然数集合的规则非常简单,每个元素都是前一个元素的值+1,因此,自然数发生器用代码实现如下:

class NaturalSupplier implements Supplier<Long>{

long value = 0

public Long get() {

this.value = this.value + 1

return this.value

}

}

反复调用get(),将得到一个无穷数列,利用这个Supplier,可以创建一个无穷的Stream:

public static void main(String[] args) {

Stream<Long>natural = Stream.generate(new NaturalSupplier())

natural.map((x) ->{

return x * x

}).limit(10).forEach(System.out::println)

}

对这个Stream做任何map()、filter()等操作都是完全可以的,这说明Stream API对Stream进行转换并生成一个新的Stream并非实时计算,而是做了延迟计算。

当然,对这个无穷的Stream不能直接调用forEach(),这样会无限打印下去。但是我们可以利用limit()变换,把这个无穷Stream变换为有限的Stream。

利用Stream API,可以设计更加简单的数据接口。例如,生成斐波那契数列,完全可以用一个无穷流表示(受限Java的long型大小,可以改为BigInteger):

class FibonacciSupplier implements Supplier<Long>{

long a = 0

long b = 1

@Override

public Long get() {

long x = a + b

a = b

b = x

return a

}

}

public class FibonacciStream {

public static void main(String[] args) {

Stream<Long>fibonacci = Stream.generate(new FibonacciSupplier())

fibonacci.limit(10).forEach(System.out::println)

}

}

如果想取得数列的前10项,用limit(10),如果想取得数列的第20~30项,用:

List<Long>list = fibonacci.skip(20).limit(10).collect(Collectors.toList())

最后通过collect()方法把Stream变为List。该List存储的所有元素就已经是计算出的确定的元素了。

用Stream表示Fibonacci数列,其接口比任何其他接口定义都要来得简单灵活并且高效。

打开Oracle网站,拖动到网站最后,点击“Download Java for Developers”。

怎么在官网上下载JDK1.8 API Documentation?

这时我们就来到了“Oracle Technology Network / Java / Java SE / Downloads”界面,界面上方可以看到下载JDK的按钮。

怎么在官网上下载JDK1.8 API Documentation?

拖动到该界面下方,可以看到Java10和java8 API documentation下载按钮,点击它。

怎么在官网上下载JDK1.8 API Documentation?

点击“Accept License Agreement”。

怎么在官网上下载JDK1.8 API Documentation?

点击图示中的zip包,开始下载啦。

怎么在官网上下载JDK1.8 API Documentation?

下载完,解压这个压缩包,打开它,就会看到如下的文件和文件夹。

怎么在官网上下载JDK1.8 API Documentation?

双击“index.html”或将它拖动到浏览器上,就可以查看离线API文档啦。

怎么在官网上下载JDK1.8 API Documentation?

Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。Stream API 借助于同样新出现的 Lambda 表达式,极大的提高编程效率和程序可读性。同时它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势,使用 fork/join 并行方式来拆分任务和加速处理过程。通常编写并行代码很难而且容易出错, 但使用 Stream API 无需编写一行多线程的代码,就可以很方便地写出高性能的并发程序。所以说,Java 8 中首次出现的 java.util.stream 是一个函数式语言+多核时代综合影响的产物。 (摘自某博客)

Stream 就如同一个迭代器(Iterator),单向,不可往复,数据只能遍历一次

Stream不是ORM (对象关系映射)

linq有自己的语法,和lambda表达式不同。LINQ,语言集成查询(Language Integrated Query)是一组用于c#和Visual Basic语言的扩展,然后linq能访问多种类型的对象

lin的运用有多种:linq to 集合,linqtoxml,txt,doc,sql。。。等等,(ORM组件)

然后Stream中的lambda和.net里面的lambda有点类似