之前看一本关于JDK8的书,推荐stream的一个理由是,是stream经过优化的可以发挥多核处理器的优势(忘了,但大概印象是多核)充分利用设备资源。所以说stream除了简化编程代码,实际上也提高了效率。
在没看资料之前,我使用stream都是网上找例子,比如去搜索“如何List转换成map这种”。在梳理了资料后,感觉对stream的写法有了一个新的认识。
一 stream到底是什么
看起来stream像是一个数据结构来存数据的,实际并不是,就拿我们日常见得最多的List作比较。首先List你要创建后往里面赛数据,实际上他的大小不是无限的,因为不可能创建一个无穷大的队列。但stream可以装进去“无数个元素”。
比如我们说自然数是无穷无尽的,我们可以创建一个自然数的stream,当然这个创建自然数的规则暂时不具体实现
Stream<BigInteger> naturals = createNaturalStream();
但是你要输出这个的话,不可能让你无穷无尽的输出,你要给定一个范围才能输出。
Stream<BigInteger> naturals = createNaturalStream()limit(100) .forEach(System.out::println);
所以说stream相当于保存了一个规则,用的时候根据规则再计算。
说到这里,我还要知道一个概念就是,链式操作。有的地方也说是链式编程,说stream的写法很符合链式操作。所谓的链式操作,说的直白点就是所有的操作像一个链条一样,一个接一个的。
比如
obj.methodA().methodB().methodC().methodD()......;
二 Stream的创建
看了前面的部分,发现这个stream和我们之前使用的Collection集合压根是两回事,它类似一个公式,到用的时候直接根据公式输出,过滤或者其他操作,但是他不一定存储元素在里面。
(1)Stream.of()
这个方法其实类似我们刚开始初始化数组,或者集合一样,直接给定一些元素创建
Stream<String> stream = Stream.of("ZP_is_handsome", "ZP_is_smart", "ZP_is_best");
(2)基于数组和Collection
这种类似初始化的创建stream用到的机会很少,主要的还是要和数据和Collection打交道,比如说把某个数组,或者列表转换成一个stream。
String[] testArrays = { "ZP_is_handsome","ZP_is_clever","ZP_has_talent" };
Stream streamArray = Arrays.stream(testArrays);
List<String> list = Arrays.asList(testArrays);
Stream streamList = list.stream();
streamArray.forEach(System.out::println);
streamList.forEach(System.out::println);
(3)通过Supplier来生成
以上都是提供好元素,或者给个数组集合自己转换成stream。实际上这些都是有限的stream,我们之前说stream可以无限的,怎样生成一个“无限”大的stream,可以通过function包下面的Supplier来生成。
实际上这个Supplier是一个接口,具体怎么实现还要靠你如何定义实现。
Supplier的源码
package java.util.function;
/**
* Represents a supplier of results.
*
* <p>There is no requirement that a new or distinct result be returned each
* time the supplier is invoked.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #get()}.
*
* @param <T> the type of results supplied by this supplier
*
* @since 1.8
*/
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
以下是一个例子
@Test
public void createStreamBySupplier(){
Stream<Integer> natual = Stream.generate(new NatualSupplier());
// 注意:无限序列必须先变成有限序列再打印:
natual.limit(20).forEach(System.out::println);
}
class NatualSupplier implements Supplier<Integer> {
int n = 0;
public Integer get() {
n++;
return n;
}
}
一下是一个我该写的一个的斐波那契数列的demo
package com.example.zp.demo.testDemo;
import org.junit.jupiter.api.Test;
import java.util.function.LongSupplier;
import java.util.stream.LongStream;
public class FibonacciStream {
@Test
public void generateFibonacciStream(){
//实际上斐波那契:实际上就是a(n) = a(n-1) + a(n-2),非常递归的一个形式
LongStream fib = LongStream.generate(new FibSupplier());
// 打印Fibonacci数列:1,1,2,3,5,8,13,21...
fib.limit(10).forEach(System.out::println);
}
}
class FibSupplier implements LongSupplier {
int n = 0;
/**
* 用递归实现斐波那契数列
* @param i 需要得到的第i项
* @return 第i项内容
*/
public static int fibonaccis(int i){
if(i == 1 || i == 2){
return 1;
}else{
return fibonaccis(i-1) + fibonaccis(i - 2);
}
}
public long getAsLong() {
n++;
return fibonaccis(n);
}
}