JAVA-流的创建

菜鸟为了巩固所写

目录

菜鸟为了巩固所写

一、概述

二、创建Stream

        综合示例1

1、基于集合创建Stream      

2、使用Stream.of创建流 

3、使用Stream.Builder

4、基于数组构建流

 5、构建一个不包容任何元素的流

        综合示例2

1、“基于工厂函数”构建无限流

2、“基于迭代函数”构建无限流

综合示例3(Fibonacci)

 解释1

综合示例4(生成随机数流)

解释1

解释2

数值流

示例5(使用装箱流) 

综合示例6(基于文件夹和文件创建流)


一、概述

  • 为了支持级联调用,所有流的“中间操作”都会返回一个流对象。
  • 但我们总需有一个“初始”的流对象,以便基于它开始构建一个流处理管线。
  • 下面介绍如何从原始数据源中创建这个“初始”的流对象。

二、创建Stream

        综合示例1

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.function.IntSupplier;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class CreateStream {
    public static void main(String[] args) {

        createForCollection();

        createUseStreamOf();

        createUseStreamBuilder();

        createNumberStream();

        createEmptyStream();

    }

    // 基于集合对象创建流
    private static void createForCollection() {
        //创建一个集合对象
        Set<String> names = new HashSet<>();
        names.add("Tom");
        names.add("Jacket");
        // 基于集合对象创建流
        Stream<String> sequentialStream = names.stream();
        //基于集合对象创建并行流( parallel stream)
        Stream<String> parallelStream = names.parallelStream();
        //基于数组创建流
        int[] numbers = {2, 3, 5, 7, 11, 13};
        var arrayStream = Arrays.stream(numbers);
    }

    //使用Stream.of方法创建流
    private static void createUseStreamOf() {
        //使用可变参数创建流
        var strStream = Stream.of("Java", "Kotlin", "C#");
        //基于数组创建流
        String[] names = {"Ken", "Jeff", "Chris", "Ellen"};
        Stream<String> nameStream = Stream.of(names);
    }

    //使用StreamBuilder创建流
    private static void createUseStreamBuilder() {
        Stream<String> stream = Stream.<String>builder()
                .add("Ken")
                .add("Jeff")
                .add("Chris")
                .add("Ellen")
                .build();
    }

    //创建原始数值类型构成的流
    private static void createNumberStream() {
        //使用可变参数构建数值流
        IntStream stream = IntStream.of(1, 1, 2, 3, 5);
        //使用int数组构建流
        int[] values = {1, 2, 3, 4};
        IntStream stream2 = Arrays.stream(values);

        //生成的流包容 [0,100) 区间的所有整数
        IntStream zeroToNinetyNine = IntStream.range(0, 100);
        //生成的流包容 [0,100]区间的所有整数
        IntStream zeroToHundred = IntStream.rangeClosed(0, 100);
    }

    //构建一个不包容任何元素的流
    private static void createEmptyStream() {
        //构建一个空的字符串流
        Stream<String> stream = Stream.empty();
        //构建一个空的整数流
        IntStream numbers = IntStream.empty();
    }

}

1、基于集合创建Stream      

        所有集合对象都实现的Collection 接口定义了一个 Stream() 或parallelStream 方法,可以通过它来创建流对象:        

    // 基于集合对象创建流
    private static void createForCollection() {
        //创建一个集合对象
        Set<String> names = new HashSet<>();
        names.add("Tom");
        names.add("Jacket");
        // 基于集合对象创建流
        Stream<String> sequentialStream = names.stream();
        //基于集合对象创建并行流( parallel stream)
        Stream<String> parallelStream = names.parallelStream();
        //基于数组创建流
        int[] numbers = {2, 3, 5, 7, 11, 13};
        var arrayStream = Arrays.stream(numbers);
    }

        JDK中的 Arrays 类提供了直接基于现有数组创建流的静态方法 stream()stream(),注意一下流的类型比较特殊,是 IntStream 。

2、使用Stream.of创建流 

        Stream接口定义了一个 of 方法,可以用于创建流

    //使用Stream.of方法创建流
    private static void createUseStreamOf() {
        //使用可变参数创建流
        var strStream = Stream.of("Java", "Kotlin", "C#");
        //基于数组创建流
        String[] names = {"Ken", "Jeff", "Chris", "Ellen"};
        Stream<String> nameStream = Stream.of(names);
    }

        在Java 标准库中, of 方法的实现实际上被委托给java.util.Arrays 类定义的 stream 方法,基于数组创建流。

3、使用Stream.Builder<T>

        使用Stream.Builder<T 也 能创建流

    //使用StreamBuilder创建流
    private static void createUseStreamBuilder() {
        Stream<String> stream = Stream.<String>builder()
                .add("Ken")
                .add("Jeff")
                .add("Chris")
                .add("Ellen")
                .build();
    }

4、基于数组构建流

 5、构建一个不包容任何元素的流

    //构建一个不包容任何元素的流
    private static void createEmptyStream() {
        //构建一个空的字符串流
        Stream<String> stream = Stream.empty();
        //构建一个空的整数流
        IntStream numbers = IntStream.empty();
    }


 

        综合示例2

import java.util.function.IntPredicate;
import java.util.function.IntUnaryOperator;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class StreamElementFactory {

    public static void main(String[] args) {
        // 示例1:使用 Stream.generate 方法
        generateExample();

        // 示例2:使用 Stream.iterate 方法
        iterateExample();

        // 示例3:使用带条件的 Stream.iterate 方法
        useIterateWithPredicate();
    }

    // 示例1:使用 Stream.generate 方法生成流
    private static void generateExample() {
        // 定义一个随机数生成器,生成 [0, 100) 范围内的随机整数
        Supplier<Integer> intFactory = () -> (int) (Math.random() * 100);

        // 使用 Stream.generate 创建一个无限流,并限制为前 10 个元素
        Stream<Integer> stream = Stream.generate(intFactory).limit(10);

        // 打印流中的元素
        stream.forEach(System.out::println);
    }

    // 示例2:使用 Stream.iterate 方法生成流
    private static void iterateExample() {
        // 初始值为 1
        int seed = 1;

        // 定义一个生成规则:a[n] = a[n-1] + 2
        UnaryOperator<Integer> intFactory = n -> n + 2;

        // 使用 Stream.iterate 创建一个无限流,并限制为前 10 个元素
        Stream<Integer> stream = Stream.iterate(seed, intFactory).limit(10);

        // 打印流中的元素
        stream.forEach(System.out::println);
    }

    // 示例3:使用带条件的 Stream.iterate 方法生成流
    // 生成从 0 开始,每次加 5 的数列,直到元素大于 100 为止
    private static void useIterateWithPredicate() {
        // 定义一个条件:元素必须小于等于 100
        IntPredicate predicate = n -> n <= 100;

        // 定义生成规则:每次加 5
        IntUnaryOperator next = n -> n + 5;

        // 使用带条件的 IntStream.iterate 方法生成流
        IntStream.iterate(0, predicate, next)
                .forEach(System.out::println);
    }
}

1、“基于工厂函数”构建无限流

        我们可以定义一个函数,这个函数可以帮助我们构建出流的元素,这个函数可以看成是生成流元素的“元素工厂”,然后使用这个工厂生产出来的“元素”构建出流。

    // 示例1:使用 Stream.generate 方法生成流
    private static void generateExample() {
        // 定义一个随机数生成器,生成 [0, 100) 范围内的随机整数
        Supplier<Integer> intFactory = () -> (int) (Math.random() * 100);

        // 使用 Stream.generate 创建一个无限流,并限制为前 10 个元素
        Stream<Integer> stream = Stream.generate(intFactory).limit(10);

        // 打印流中的元素
        stream.forEach(System.out::println);
    }

        注意:这种方式可以构建出元素数目无限的“无限流”,因此,通常都会使用 limit() 方法限定要生成 的元素个数。

2、“基于迭代函数”构建无限流

        有些流的元素需要依据它的前一个元素才能确定,对于这种情况,可以使用 Stream.iterate() 方法构建流对象:

// 示例2:使用 Stream.iterate 方法生成流
    private static void iterateExample() {
        // 初始值为 1
        int seed = 1;

        // 定义一个生成规则:a[n] = a[n-1] + 2
        UnaryOperator<Integer> intFactory = n -> n + 2;

        // 使用 Stream.iterate 创建一个无限流,并限制为前 10 个元素
        Stream<Integer> stream = Stream.iterate(seed, intFactory).limit(10);

        // 打印流中的元素
        stream.forEach(System.out::println);
    }
  • Stream.iterate(seed, UnaryOperator)

    • Stream.iterate 是一个静态方法,用于生成一个无限流。
    • seed:初始值,这里是1。
    • UnaryOperator:生成规则,这里是  n -> n+2

综合示例3(Fibonacci)

import java.util.function.IntSupplier;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class CreateFibonacci {
    public static void main(String[] args) {
        getFibonacciUseIterator(10);
        getFibonacciUseGenerate(10);
    }

    private static void getFibonacciUseIterator(int limit) {
        //斐波那契元组序列
        Stream.iterate(new int[]{0, 1}, t -> new int[]{t[1], t[0] + t[1]})
                .limit(limit)    //生成20个元素
                .map(t -> t[0])  //只提取出数组中的第1个数(它就是要求的斐波那契数)
                .forEach(System.out::println);
    }

    static void getFibonacciUseGenerate(int limit) {
        IntSupplier fib = new IntSupplier() {
            private int previous = 0;
            private int current = 1;
            public int getAsInt() {
                int oldPrevious = this.previous;
                int nextValue = this.previous + this.current;
                this.previous = this.current;
                this.current = nextValue;
                return oldPrevious;
            }
        };
        IntStream.generate(fib)
                .limit(limit)
                .forEach(System.out::println);
    }

}

 解释1

在 Stream.iterate 中,第一次迭代直接返回初始值(seed),并不会调用生成规则(UnaryOperator)。

  • Stream.iterate(seed, UnaryOperator)

    • Stream.iterate 是一个静态方法,用于生成一个无限流。
    • seed:初始值,这里是 new int[]{0, 1},表示斐波那契数列的前两个数。
    • UnaryOperator:生成规则,这里是 t -> new int[]{t[1], t[0] + t[1]}
      • t[1]:当前元组的第二个数。
      • t[0] + t[1]:当前元组中两个数的和。
      • 每次迭代都会生成新的元组 [t[1], t[0] + t[1]],表示下一个斐波那契数对。

综合示例4(生成随机数流)

import java.util.Random;
import java.util.stream.Stream;

public class CreateRandomNumberStream {
    public static void main(String[] args) {
        useGenerate(1, 100);
        useRandomClass();
    }

    //使用generate()方法生成[from,to]之间的随机整数
    private static void useGenerate(int from, int to) {
        Stream.generate(Math::random)
                .limit(5)
                .map(doubleNum -> (int) (doubleNum * (to - from + 1)) + 1)
                .forEach(System.out::println);
    }

    //基于JDK所提供的Random类方法生成随机数流
    private static void useRandomClass() {
        //生成[0,100)区间中的随机整数
        new Random()
                .ints(0, 100)
                .limit(5)
                .forEach(System.out::println);

        //生成[100,200)区间内的随机浮点数
        new Random()
                .doubles(100, 200)
                .limit(5)
                .forEach(System.out::println);
    }
}

解释1

    //使用generate()方法生成[from,to]之间的随机整数
    private static void useGenerate(int from, int to) {
        Stream.generate(Math::random)
                .limit(5)
                .map(doubleNum -> (int) (doubleNum * (to - from + 1)) + 1)
                .forEach(System.out::println);
    }

        使用Stream.generate 方法,配合 JDK 中所提供的 Math.random方法,可以很方便地生成特定区间内的随机整数。

        Stream.generate是一个静态方法,用于创建无限流,Stream.generate可以没有接收形参,只有返回值,也就是说Stream.generate(Math::random)里面的Math::random可以改成()->Math.random()。

解释2

        鉴于程序中经常需要生成随机的整数和浮点数,JDK8 中为 Random 类添加了ints()/longs()/doubles() 方法创建相应的数值流。

    //基于JDK所提供的Random类方法生成随机数流
    private static void useRandomClass() {
        //生成[0,100)区间中的随机整数
        new Random()
                .ints(0, 100)
                .limit(5)
                .forEach(System.out::println);

        //生成[100,200)区间内的随机浮点数
        new Random()
                .doubles(100, 200)
                .limit(5)
                .forEach(System.out::println);
    }

数值流

  • 引入数值流的主要考虑, 是避免装箱损失。
  • Java 8引入了三个原始 类型流 接口: IntStream 、DoubleStream 和 LongStream ,其流中的元素为 int 、 long和 double 这样的原始数据类型,在处理数据时,可以避免装箱带来的性能损失。

示例5(使用装箱流) 

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class UseBoxedStream {
    public static void main(String[] args) {
        //以下代码无法编译
        //IntStream.of(3, 1, 4, 1, 5, 9)
        //        .collect(Collectors.toList());

        //解决之道:将int用boxed方法转换为Integer,就可以编译了
        List<Integer> ints = IntStream.of(3, 1, 4, 1, 5, 9)
                .boxed()
                .collect(Collectors.toList());
        //输出:[3, 1, 4, 1, 5, 9]
        System.out.println(ints);

        //另一种方式:使用mapToObject,将其转换为对象
        List<Integer> ints2 = IntStream.of(3, 1, 4, 1, 5, 9)
                .mapToObj(Integer::valueOf)
                .collect(Collectors.toList());
        //输出:[3, 1, 4, 1, 5, 9]
        System.out.println(ints2);

    }
}

        这里首先要知道collect()是Stream API的一个终端操作,用于将产生的流收集到一个地方,这里collect(Collectors.toList())就是将产生的流收集到List类型。

综合示例6(基于文件夹和文件创建流)

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;

public class GetStreamFromJDK {

    public static void main(String[] args) {
        //useNIOFileStream();

        listFileTree();
    }

    private static void useNIOFileStream() {
        //lines()方法,返回的就是一个字符串流
        try (Stream<String> lines = Files.lines(
                Paths.get("data.txt"))) {
            lines.forEach(System.out::println);
        } catch (IOException ex) {
            System.out.println(ex.getMessage());
        }
    }

    // 列出当前文件夹下的所有文件
    public static void listFileTree() {
        Path dir = Paths.get("");
        System.out.printf(" %s contains:\n", dir.toAbsolutePath());
        //walk方法返回一个Stream
        try (Stream<Path> fileTree = Files.walk(dir)) {
            fileTree.forEach(System.out::println);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值