zoukankan      html  css  js  c++  java
  • 【Java8新特性】面试官问我:Java8中创建Stream流有哪几种方式?

    写在前面

    先说点题外话:不少读者工作几年后,仍然在使用Java7之前版本的方法,对于Java8版本的新特性,甚至是Java7的新特性几乎没有接触过。真心想对这些读者说:你真的需要了解下Java8甚至以后版本的新特性了。

    今天,一名读者出去面试,面试官问他:说说Java8中创建Stream流有哪几种方式?他竟然没回答上来!!

    Stream概述

    Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另外一个则是 Stream API(java.util.stream.*)。

    Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。

    何为Stream?

    流(Stream) 到底是什么呢?

    可以这么理解流:流就是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。

    “集合讲的是数据,流讲的是计算! ”

    注意:

    ①Stream 自己不会存储元素。

    ②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。

    ③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

    Stream操作步骤

    1.创建 Stream

    一个数据源(如: 集合、数组), 获取一个流。

    2.中间操作

    一个中间操作链,对数据源的数据进行处理。

    3.终止操作(终端操作)

    一个终止操作,执行中间操作链,并产生结果 。

    在这里插入图片描述

    如何创建Stream流?

    这里,创建测试类TestStreamAPI1,所有的操作都是在TestStreamAPI1类中完成的。

    (1)通过Collection系列集合提供的stream()方法或者parallelStream()方法来创建Stream。

    在Java8中,Collection 接口被扩展,提供了两个获取流的默认方法,如下所示。

    default Stream<E> stream() {
        return StreamSupport.stream(spliterator(), false);
    }
    default Stream<E> parallelStream() {
        return StreamSupport.stream(spliterator(), true);
    }
    

    其中,stream()方法返回一个顺序流,parallelStream()方法返回一个并行流。

    我们可以使用如下代码方式来创建顺序流和并行流。

    List<String> list = new ArrayList<>();
    list.stream();
    list.parallelStream();
    

    (2)通过Arrays中的静态方法stream()获取数组流。

    Java8 中的 Arrays类的静态方法 stream() 可以获取数组流 ,如下所示。

    public static <T> Stream<T> stream(T[] array) {
        return stream(array, 0, array.length);
    }
    

    上述代码的的作用为:传入一个泛型数组,返回这个泛型的Stream流。

    除此之外,在Arrays类中还提供了stream()方法的如下重载形式。

    public static <T> Stream<T> stream(T[] array) {
        return stream(array, 0, array.length);
    }
    
    public static <T> Stream<T> stream(T[] array, int startInclusive, int endExclusive) {
        return StreamSupport.stream(spliterator(array, startInclusive, endExclusive), false);
    }
    
    public static IntStream stream(int[] array) {
        return stream(array, 0, array.length);
    }
    
    public static IntStream stream(int[] array, int startInclusive, int endExclusive) {
        return StreamSupport.intStream(spliterator(array, startInclusive, endExclusive), false);
    }
    
    public static LongStream stream(long[] array) {
        return stream(array, 0, array.length);
    }
    
    public static LongStream stream(long[] array, int startInclusive, int endExclusive) {
        return StreamSupport.longStream(spliterator(array, startInclusive, endExclusive), false);
    }
    
    public static DoubleStream stream(double[] array) {
        return stream(array, 0, array.length);
    }
    
    public static DoubleStream stream(double[] array, int startInclusive, int endExclusive) {
        return StreamSupport.doubleStream(spliterator(array, startInclusive, endExclusive), false);
    }
    

    基本上能够满足基本将基本类型的数组转化为Stream流的操作。

    我们可以通过下面的代码示例来使用Arrays类的stream()方法来创建Stream流。

    Integer[] nums = new Integer[]{1,2,3,4,5,6,7,8,9};
    Stream<Integer> numStream = Arrays.stream(nums);
    

    (3)通过Stream类的静态方法of()获取数组流。

    可以使用静态方法 Stream.of(), 通过显示值创建一个流。它可以接收任意数量的参数。

    我们先来看看Stream的of()方法,如下所示。

    public static<T> Stream<T> of(T t) {
        return StreamSupport.stream(new Streams.StreamBuilderImpl<>(t), false);
    }
    @SafeVarargs
    @SuppressWarnings("varargs") 
    public static<T> Stream<T> of(T... values) {
        return Arrays.stream(values);
    }
    

    可以看到,在Stream类中,提供了两个of()方法,一个只需要传入一个泛型参数,一个需要传入一个可变泛型参数。

    我们可以使用下面的代码示例来使用of方法创建一个Stream流。

    Stream<String> strStream = Stream.of("a", "b", "c");
    

    (4)创建无限流

    可以使用静态方法 Stream.iterate() 和Stream.generate(), 创建无限流。

    先来看看Stream类中iterate()方法和generate()方法的源码,如下所示。

    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);
    }
    
    public static<T> Stream<T> generate(Supplier<T> s) {
        Objects.requireNonNull(s);
        return StreamSupport.stream(
            new StreamSpliterators.InfiniteSupplyingSpliterator.OfRef<>(Long.MAX_VALUE, s), false);
    }
    

    通过源码可以看出,iterate()方法主要是使用“迭代”的方式生成无限流,而generate()方法主要是使用“生成”的方式生成无限流。我们可以使用下面的代码示例来使用这两个方法生成Stream流。

    • 迭代
    Stream<Integer> intStream = Stream.iterate(0, (x) -> x + 2);
    intStream.forEach(System.out::println);
    

    运行上述代码,会在终端一直输出偶数,这种操作会一直持续下去。如果我们只需要输出10个偶数,该如何操作呢?其实也很简单,使用Stream对象的limit方法进行限制就可以了,如下所示。

    Stream<Integer> intStream = Stream.iterate(0, (x) -> x + 2);
    intStream.limit(10).forEach(System.out::println);
    
    • 生成
    Stream.generate(() -> Math.random()).forEach(System.out::println);
    

    上述代码同样会一直输出随机数,如果我们只需要输出5个随机数,则只需要使用limit()方法进行限制即可。

    Stream.generate(() -> Math.random()).limit(5).forEach(System.out::println);
    

    (5)创建空流

    在Stream类中提供了一个empty()方法,如下所示。

    public static<T> Stream<T> empty() {
        return StreamSupport.stream(Spliterators.<T>emptySpliterator(), false);
    }
    

    我们可以使用Stream类的empty()方法来创建一个空Stream流,如下所示。

    Stream<String> empty = Stream.empty();
    

    写在最后

    如果觉得文章对你有点帮助,请微信搜索并关注「 冰河技术 」微信公众号,跟冰河学习Java8新特性。

    最后,附上Java8新特性核心知识图,祝大家在学习Java8新特性时少走弯路。

  • 相关阅读:
    Linux 下安装配置 JDK7
    win7下virtualbox装linux共享win7文件问题(已测试可用)
    Linix常用命令
    JAVA命令大全
    virtualbox 不能为虚拟电脑打开一个新任务/VT-x features locked or unavailable in MSR.
    VirtualBox下安装rhel5.5 linux系统
    redhat RHEL 5.5 下载地址
    ios开发@selector的函数如何传参数/如何传递多个参数
    U盘10分钟安装linux系统
    史上最浅显易懂的Git分布式版本控制系统教程
  • 原文地址:https://www.cnblogs.com/binghe001/p/12961977.html
Copyright © 2011-2022 走看看