前面(《java8 Stream接口简介》),我们已经对stream这个接口,做了简单的介绍,下面,我们用几个案例,来看看流的几种创建方式
String[] dd = { "a", "b", "c" }; Arrays.stream(dd).forEach(System.out::print);// abc System.out.println(); Stream.of(dd).forEach(System.out::print);// abc System.out.println(); Arrays.asList(dd).stream().forEach(System.out::print);// abc System.out.println(); Stream.iterate(0, x -> x + 1).limit(10).forEach(System.out::print);// 0123456789 System.out.println(); Stream.generate(() -> "x").limit(10).forEach(System.out::print);// xxxxxxxxxx
1.Arrays.stream,我们可以通过Arrays的静态方法,传入一个泛型数组,创建一个流
2.Stream.of,我们可以通过Stream的静态方法,传入一个泛型数组,或者多个参数,创建一个流,这个静态方法,也是调用了Arrays的stream静态方法,如下
@SafeVarargs @SuppressWarnings("varargs") // Creating a stream from an array is safe public static<T> Stream<T> of(T... values) { return Arrays.stream(values); }
3.Collection.stream,可以用过集合的接口的默认方法,创建一个流;使用这个方法,包括继承Collection的接口,如:Set,List,Map,SortedSet 等等,详细的,可以看Collection接口上的定义注释,如下
/** * @author Josh Bloch * @author Neal Gafter * @see Set * @see List * @see Map * @see SortedSet * @see SortedMap * @see HashSet * @see TreeSet * @see ArrayList * @see LinkedList * @see Vector * @see Collections * @see Arrays * @see AbstractCollection * @since 1.2 */ public interface Collection<E> extends Iterable<E> { default Stream<E> stream() { return StreamSupport.stream(spliterator(), false); } }
4.Stream.iterate,是Stream接口下的一个静态方法,从名字也可以看出,这个静态方法,是以迭代器的形式,创建一个数据流,具体的静态方法定义如下:
public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) { Objects.requireNonNull(f); final Iterator<T> iterator = new Iterator<T>() { @SuppressWarnings("unchecked") T t = (T) Streams.NONE; @Override public boolean hasNext() { return true; } @Override public T next() { return t = (t == Streams.NONE) ? seed : f.apply(t); } }; return StreamSupport.stream(Spliterators.spliteratorUnknownSize( iterator, Spliterator.ORDERED | Spliterator.IMMUTABLE), false); }
静态方法定义以及代码中,可以看到,传入两个参数,一个泛型T对象,表示数据的起始,一个函数式接口UnaryOperator(不知道这个接口的,JAVA8 UnaryOperator接口,有详细介绍),从迭代器hasNext中,可以看到,返回一直为true,表示迭代器,会一直执行下去,创建的数据集合的值为泛型T对象;这样一直创建无限个对象的流,也成为无限流;
5.Stream.generate,也是stream中的一个静态方法,静态方法定义如下:
public static<T> Stream<T> generate(Supplier<T> s) { Objects.requireNonNull(s); return StreamSupport.stream( new StreamSpliterators.InfiniteSupplyingSpliterator.OfRef<>(Long.MAX_VALUE, s), false); }
从静态方法定义中,可以看到,传入一个函数式接口Supplier(不知道这个接口是什么意义的,可以移步这边,JAVA8 Supplier接口有详细介绍);这个静态方法,也是无限生成对象的集合流,也是一个无限流;
最后介绍下,1-3,是根据具体的数组或者集合对象,创建的流,在创建流之前,这些对象的大小(长度)已经确认,所以这个种方式的流,也被成为有限流,而4-5中,创建流的方式,是无限大小的流(generate 最大是Long.MAX_VALUE),也被成为无限流,那么我们不可能就这样放任对象被无限创建,直到内存溢出,这样的无限流,也是配合limit使用,指定这个流生成的元素的个数,对于无限流,下面再简单讲个案例,使用传统的方式和无限流的方式,创建一个固定大小的ArrayList,这样大家也会有比较清楚的认识;
应用场景:我们再做B端系统的时候,会遇到很多的统计类的需求,会用到百度的echarts插件,比如曲线图,在x抽,固定的况下(按月统计 1号-31号,或者按年统计1月-12月,或者按天24个小时的刻度),那么我就需要创建一个这个数组,或者集合,代码如下:
public static void main(String[] args) { System.out.println(buildList(100)); System.out.println(buildIterate(100)); } public static List<Integer> buildList(final int size) { List<Integer> list = new ArrayList<>(size); for (int i = 1; i <= size; i++) { list.add(i); } return list; } public static List<Integer> buildIterate(final int size) { return Stream.iterate(1, x -> ++x).limit(size).collect(Collectors.toList()); }可以看到,使用流,可以更加简便,也更加直观的表现出代码的功能