jdk1.8——Stream

x33g5p2x  于2022-01-11 转载在 其他  
字(4.1k)|赞(0)|评价(0)|浏览(328)

Stream是jdk1.8提供的新的流式编程,它不是集合也不保存任何内容,可以像build对象一样,一直点点点最后跟一个终结语句;

研究Stream之前需要先了解:

  • 新的接口定义:jdk1.8——接口新的默认方法和静态方法_FlyLikeButterfly的博客-CSDN博客
  • 函数式接口:jdk1.8——函数式接口_FlyLikeButterfly的博客-CSDN博客
  • Lambda表达式:jdk1.8——Lambda表达式_FlyLikeButterfly的博客-CSDN博客
  • 方法引用:jdk1.8——方法引用_FlyLikeButterfly的博客-CSDN博客

Stream的特性:

• 不是数据结构,不保存数据;

• 不修改原始数据,会将产生的新数据保存到新对象中;
• 延迟操作,中间的操作只会记录,直到它弄清楚了最后需要多少数据才会开始执行;

• 拥有并行能力(基于Fork/Join框架);
• 数据源可以是无限的;

• 消费性,用完了不能再拿来用,只能重新生成新的stream;

注:对于基本数据类型,另外有三个包装Stream类型:IntStream、LongStream、DoubleStream,这三个类型跟Stream类稍微有些差别,例如不需要泛型、特有的方法等;

生成Stream的方式:

  • 用Collection的stream()和parallelStream()


 

  • Arrays的stream()

  • Stream类的静态方法of()、iterate()、generate()

  • BufferedReader.lines()


 

  • Pattern的splitAsStream()


 

  • IntStream.range()

  • Files.walk()


 

  • Random的ints()

  • BitSet.stream()

  • JarFile.stream()

  • 通过Stream.builder()的builde()

Stream的操作类型:

  • Intermediate(中间操作)​​​​​​

一个流后面可以跟0个或多个中间操作,主要是对数据做一些过滤映射操作,然后返回流交给下一个操作,中间操作是惰性的,只会记录操作过程,不会真正开始遍历数据;中间操作分无状态和有状态两种操作,无状态的每个元素可单独处理,跟其他元素无关联(filter,map),有状态的元素需要知道其他元素(distinct,sorted);在并行时,某些有状态的操作可能回遍历数据多次或者缓冲大量数据(sorted不适合用并行);

  • Terminal(终止操作)

一个流只能有一个终止操作,必定是最后一个操作,执行完后流就被用完了不能再被使用,终止操作执行的时候才会真正开始遍历数据,返回数据或者执行一段代码;

  • 还有一种short-circuiting(短路操作,是处理无限流时的必要不充分条件)

中间操作的短路,会产生有限的流;终止操作的短路,会在有限时间内终止;

Stream类的方法详解:

  • 静态方法

builder(), concat(Stream<? extends T>, Stream<? extends T>), empty(), generate(Supplier<T>), iterate(T, UnaryOperator<T>), of(T), of(T...)

  • allMatch(Predicate<? super T>)

(短路终止)元素都匹配返回true,否则false;(中间遇到不匹配立即返回flase)

  • anyMatch(Predicate<? super T>)

(短路终止)存在匹配返回true,否则flase;(中间存在一个匹配立即返回true)

  • collect(Supplier<R>, BiConsumer<R, ? super T>, BiConsumer<R, R>)
  • collect(Collector<? super T, A, R>)

(终止)将流转换成集合和聚合元素;

  • count()

(终止)返回流的元素数量;

  • distinct()

(状态中间)去重,对于有序流保留第一个,无序流是随机的;

  • filter(Predicate<? super T>)

(中间)过滤元素;


 

  • findAny()

(短路终止)返回流中任意一个元素;

  • findFirst()

(短路终止)返回流中第一个元素;


 

  • forEach(Consumer<? super T>)
  • forEachOrdered(Consumer<? super T>)

(终止)遍历,有序流ordered保证顺序(并行);


 

  • flatMap(Function<? super T, ? extends Stream<? extends R>>)
  • flatMapToDouble(Function<? super T, ? extends DoubleStream>)
  • flatMapToInt(Function<? super T, ? extends IntStream>)
  • flatMapToLong(Function<? super T, ? extends LongStream>)

(中间)扁平映射,一个映射多个;

  • isParallel()

是否是并行流(继承方法);

  • iterator()

返回流的迭代器(继承方法);

  • limit(long)

(短路状态中间)截断流的最大长度;

  • map(Function<? super T, ? extends R>)
  • mapToDouble(ToDoubleFunction<? super T>)
  • mapToInt(ToIntFunction<? super T>)
  • mapToLong(ToLongFunction<? super T>)

(中间)映射,一对一;


 

  • max(Comparator<? super T>)

(终止)根据比较规则返回最大值

  • min(Comparator<? super T>)

(终止)根据比较规则返回最小值(compare返回<=0则返回第一个)

  • noneMatch(Predicate<? super T>)

(短路终止)没有相匹配的返回true,一旦匹配立即返回false;


 

  • close()

关闭流(继承方法);

  • onClose(Runnable)

(中间)调用close()的时候触发,所有的onClose定义的runnable都会按添加顺序执行(即使有的runnable抛出异常),run中抛出的第一个异常将在close()方法中抛出,其他异常会作为抑制异常被添加到该抛出异常中(继承方法);

  • parallel()

(中间)将流变成并行流(继承方法);

  • sequential()

(中间)将流变成串行流(继承方法);

  • peek(Consumer<? super T>)

(中间)元素在结果流中被消耗时,额外对每个元素执行该操作;

  • reduce(BinaryOperator<T>)
  • reduce(T, BinaryOperator<T>)
  • reduce(U, BiFunction<U, ? super T, U>, BinaryOperator<U>)

(终止)对元素进行累加操作;

  • skip(long)

(状态中间)丢弃前n个元素,可能返回空流;

  • sorted()

(状态中间)按自然元素排序;

  • sorted(Comparator<? super T>)

(状态中间)根据比较器排序;

注:reversed()反向排序是对当前整个Comparator定义的排序取反;

  • spliterator()

(终止)返回流元素的拆分器(继承方法);

  • toArray()
  • toArray(IntFunction<A[]>)

(终止)返回A[]元素数组(IntFunction的参数为元素个数);


 

  • unordered()

(中间)返回一个无序的流(继承方法);

IntStream的其他特有方法:

  • range(int, int)

返回一个整数序列,不包括最后一个(静态方法);

  • rangeClosed(int, int)

返回一个整数序列,包括最后一个(静态方法);


 

  • asDoubleStream()

(中间)转换成DoubleStream;

  • asLongStream()

(中间)转换成LongStream;

  • average()

(终止)返回算数平均值的OptionalDouble对象;

  • boxed()

(中间)每个元素装箱成Integer对象,返回Stream<Integer>;


 

  • sum()

(终止)求和;

  • summaryStatistics()

(终止)返回一个IntSummaryStatistics对象,该对象包括流元素的概要数据;

注:

  • IntStream只有一个collect(Supplier<R> supplier, ObjIntConsumer<R> accumulator, BiConsumer<R, R> combiner)方法,需要boxed转成Stream<Integer>在用其他的collect;
  • DoubleStream没有IntStream里的range、rangeClosed、asDoubleStream、asLongStream方法,其他除了类型基本一致;
  • LongStream没有IntStream里的asLongStream方法,其他除了类型基本一致;

注意事项:

一个小Demo:


 

从Stream.of也能看得出区别:

  1. 基本数据类型不是对象,基本数据类型的包装类型是对象,基本数据类型是在栈上分配的,包装类型是new出来的,在堆上分配;
  2. 关于数组,栈上分配的一个指向堆的指针,数组是一个对象,基本数据类型的数组就只是一个数组对象(数组内的元素直接是值),而包装类型的数组里的元素也是指针(指向包装类型的对象);

相关文章