阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

创建Stream

33次阅读
没有评论

共计 2680 个字符,预计需要花费 7 分钟才能阅读完成。

要使用 Stream,就必须先创建它。创建Stream 有很多种方法,我们来一一介绍。

Stream.of()

创建 Stream 最简单的方式是直接用 Stream.of() 静态方法,传入可变参数即创建了一个能输出确定元素的Stream

import java.util.stream.Stream;

public class Main {public static void main(String[] args) {Stream<String> stream = Stream.of("A", "B", "C", "D");
        // forEach()方法相当于内部循环调用,
        // 可传入符合 Consumer 接口的 void accept(T t)的方法引用:
        stream.forEach(System.out::println);
    }
}

虽然这种方式基本上没啥实质性用途,但测试的时候很方便。

基于数组或 Collection

第二种创建 Stream 的方法是基于一个数组或者 Collection,这样该Stream 输出的元素就是数组或者 Collection 持有的元素:

import java.util.*;
import java.util.stream.*;

public class Main {public static void main(String[] args) {Stream<String> stream1 = Arrays.stream(new String[] { "A", "B", "C" });
        Stream<String> stream2 = List.of("X", "Y", "Z").stream();
        stream1.forEach(System.out::println);
        stream2.forEach(System.out::println);
    }
}

把数组变成 Stream 使用 Arrays.stream() 方法。对于 CollectionListSetQueue 等),直接调用 stream() 方法就可以获得Stream

上述创建 Stream 的方法都是把一个现有的序列变为Stream,它的元素是固定的。

基于 Supplier

创建 Stream 还可以通过 Stream.generate() 方法,它需要传入一个 Supplier 对象:

Stream<String> s = Stream.generate(Supplier<String> sp);

基于 Supplier 创建的 Stream 会不断调用 Supplier.get() 方法来不断产生下一个元素,这种 Stream 保存的不是元素,而是算法,它可以用来表示无限序列。

例如,我们编写一个能不断生成自然数的 Supplier,它的代码非常简单,每次调用get() 方法,就生成下一个自然数:

import java.util.function.*;
import java.util.stream.*;

public class Main {public static void main(String[] args) {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;
    }
}

上述代码我们用一个 Supplier<Integer> 模拟了一个无限序列(当然受 int 范围限制不是真的无限大)。如果用 List 表示,即便在 int 范围内,也会占用巨大的内存,而 Stream 几乎不占用空间,因为每个元素都是实时计算出来的,用的时候再算。

对于无限序列,如果直接调用 forEach() 或者 count() 这些最终求值操作,会进入死循环,因为永远无法计算完这个序列,所以正确的方法是先把无限序列变成有限序列,例如,用 limit() 方法可以截取前面若干个元素,这样就变成了一个有限序列,对这个有限序列调用 forEach() 或者 count() 操作就没有问题。

其他方法

创建 Stream 的第三种方法是通过一些 API 提供的接口,直接获得Stream

例如,Files类的 lines() 方法可以把一个文件变成一个Stream,每个元素代表文件的一行内容:

try (Stream<String> lines = Files.lines(Paths.get("/path/to/file.txt"))) {...}

此方法对于按行遍历文本文件十分有用。

另外,正则表达式的 Pattern 对象有一个 splitAsStream() 方法,可以直接把一个长字符串分割成 Stream 序列而不是数组:

Pattern p = Pattern.compile("\\s+");
Stream<String> s = p.splitAsStream("The quick brown fox jumps over the lazy dog");
s.forEach(System.out::println);

基本类型

因为 Java 的范型不支持基本类型,所以我们无法用 Stream<int> 这样的类型,会发生编译错误。为了保存 int,只能使用Stream<Integer>,但这样会产生频繁的装箱、拆箱操作。为了提高效率,Java 标准库提供了IntStreamLongStreamDoubleStream这三种使用基本类型的 Stream,它们的使用方法和范型Stream 没有大的区别,设计这三个 Stream 的目的是提高运行效率:

// 将 int[]数组变为 IntStream:
IntStream is = Arrays.stream(new int[] { 1, 2, 3 });
// 将 Stream<String> 转换为 LongStream:
LongStream ls = List.of("1", "2", "3").stream().mapToLong(Long::parseLong);

练习

编写一个能输出斐波拉契数列(Fibonacci)的LongStream

1, 1, 2, 3, 5, 8, 13, 21, 34, ...

下载练习

小结

创建 Stream 的方法有:

  • 通过指定元素、指定数组、指定 Collection 创建Stream
  • 通过 Supplier 创建Stream,可以是无限序列;
  • 通过其他类的相关方法创建。

基本类型的 StreamIntStreamLongStreamDoubleStream

正文完
星哥说事-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2024-08-05发表,共计2680字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中