继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Java Stream用法总结(一)

霜花似雪
关注TA
已关注
手记 163
粉丝 1.5万
获赞 8507

Java Stream

Java API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。

Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。

Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。

这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。

元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。

什么是 Stream?

Stream(流)是一个来自数据源的元素队列并支持聚合操作,元素是特定类型的对象,形成一个队列。Java中的Stream并不会存储元素,而是按需计算。

Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。

数据源 流的来源。可以是集合,数组,I/O channel, 产生器generator 等。

聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。

和以前的Collection操作不同, Stream操作还有两个基础的特征:

Pipelining: 中间操作都会返回流对象本身。这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。

内部迭代:以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。

Stream将要处理的元素集合看作一种流,在流的过程中,借助Stream API对流中的元素进行操作,比如:筛选、排序、聚合等。
Stream可以由数组或集合创建,对流的操作分为两种:

  • 中间操作,每次返回一个新的流,可以有多个。
  • 终端操作,每个流只能进行一次终端操作,终端操作结束后流无法再次使用。终端操作会产生一个新的集合或值。
    图片描述
    使用 Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。

Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。

简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。

Stream的特点:

  • 不是数据结构,stream不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果。

  • 不会修改原来的数据源,它会将操作后的数据保存到另外一个对象中,通常情况下会产生一个新的集合或一个值。

  • 惰性求值,流在中间处理过程中,只是对操作进行了记录,并不会立即执行,需要等到执行终止操作的时候才会进行实际的计算。

  • 无状态:指元素的处理不受之前元素的影响

  • 有状态:指该操作只有拿到所有元素之后才能继续下去

  • 非短路操作:指必须处理所有元素才能得到最终结果

  • 短路操作:指遇到某些符合条件的元素就可以得到最终结果,如 A || B,只要 A 为 true,则无需判断 B 的结果

什么是流

流是从支持数据处理操作的源生成的元素序列,源可以是数组、文件、集合、函数。流不是集合元素,它不是数据结构并不保存数据,它的主要目的在于计算

生成流的方式

1.通过集合生成,应用中最常用的一种, 通过集合的stream方法生成流(通过 java.util.Collection.stream() 方法用集合创建流)

 List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
 Stream<Integer> stream = integerList.stream();
List<String> list = Arrays.asList("a", "b", "c");
// 创建一个顺序流
Stream<String> stream = list.stream();
// 创建一个并行流
Stream<String> parallelStream = list.parallelStream();

2.通过数组生成:使用java.util.Arrays.stream(T[] array)方法用数组创建流

int[] intArr = new int[]{1, 2, 3, 4, 5};  
IntStream stream = Arrays.stream(intArr);  

通过Arrays.stream方法生成流,并且该方法生成的流是数值流【即IntStream】而不是Stream。补充一点使用数值流可以避免计算过程中拆箱装箱,提高性能。

Stream API提供了mapToInt、mapToDouble、mapToLong三种方式将对象流【即Stream】转换成对应的数值流,同时提供了boxed方法将数值流转换为对象流

3.通过值生成, 通过Stream的of方法生成流,通过Stream的empty方法可以生成一个空流

Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5, 6);

4.通过文件生成,通过Files.line方法得到一个流,并且得到的每个流是给定文件中的一行

Stream<String> lines = Files.lines(Paths.get("data.txt"), Charset.defaultCharset());

5.通过函数生成 提供了iterate和generate两个静态方法从函数中生成流

  • iterate: iterate方法接受两个参数,第一个为初始化值,第二个为进行的函数操作,因为iterator生成的流为无限流,通过limit方法对流进行了截断,只生成5个偶数
  • generator:generate方法接受一个参数,方法参数类型为Supplier,由它为流提供值。generate生成的流也是无限流,因此通过limit对流进行了截断
 //iterate
Stream<Integer> stream1 = Stream.iterate(0, n -> n + 2).limit(5);
        
//generator
Stream<Double> stream2 = Stream.generate(Math::random).limit(5);
stream3.forEach(System.out::println);

示例代码

/**
 * @ClassName CreateStream
 * @Desc 流生成的五种方式
 * 1.通过集合生成,应用中最常用的一种
 *
 * @Author diandian
 * @Date 2022/11/11 21:15
 **/
public class CreateStream {

    /**
     * 1.通过集合生成,应用中最常用的一种, 通过集合的stream方法生成流
     */
    private void CreateStream1(){
        List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
        Stream<Integer> stream = integerList.stream();
        System.out.println(stream.collect(Collectors.toList()));
    }

    /**
     * 2.通过数组生成
     *
     * 通过Arrays.stream方法生成流,并且该方法生成的流是数值流【即IntStream】而不是Stream<Integer>。补充一点使用数值流可以避免计算过程中拆箱装箱,提高性能。
     *
     * Stream API提供了mapToInt、mapToDouble、mapToLong三种方式将对象流【即Stream】转换成对应的数值流,同时提供了boxed方法将数值流转换为对象流
     */
    private void CreateStream2(){
        int[] intArr = new int[]{1, 2, 3, 4, 5};
        IntStream stream = Arrays.stream(intArr);
        System.out.println("最大值:"+stream.max().getAsInt());
    }

    /**
     * 3.通过值生成, 通过Stream的of方法生成流,通过Stream的empty方法可以生成一个空流
     */
    private void CreateStream3(){
       Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5, 6);
        System.out.println(integerStream.collect(Collectors.toList()));
    }

    /**
     * 4.通过文件生成,通过Files.line方法得到一个流,并且得到的每个流是给定文件中的一行
     */
    private void CreateStream4() throws IOException {
        Stream<String> lines = Files.lines(Paths.get("spring-boot-java8/doc/data.txt"), Charset.defaultCharset());
        System.out.println(lines.collect(Collectors.toList()));
    }

    /**
     * 5.通过函数生成 提供了iterate和generate两个静态方法从函数中生成流
     * iterate: iterate方法接受两个参数,第一个为初始化值,第二个为进行的函数操作,因为iterator生成的流为无限流,通过limit方法对流进行了截断,只生成5个偶数
     * generator:generate方法接受一个参数,方法参数类型为Supplier,由它为流提供值。generate生成的流也是无限流,因此通过limit对流进行了截断
     *
     */
    private void CreateStream5(){
        //iterate
        Stream<Integer> stream1 = Stream.iterate(0, n -> n + 2).limit(5);
        System.out.println(stream1.collect(Collectors.toList()));

        //generator
        Stream<Double> stream2 = Stream.generate(Math::random).limit(5);
        System.out.println(stream2.collect(Collectors.toList()));
    }


    public static void main(String[] args) throws IOException {
        CreateStream stream = new CreateStream();
        stream.CreateStream1();
        stream.CreateStream2();
        stream.CreateStream3();
        stream.CreateStream4();
        stream.CreateStream5();

    }
}

流的常用创建方法

  1. 使用 Collection 下的 stream() 和 parallelStream() 方法
Stream<String> stringStream = list.stream(); //获取一个顺序流
stringStream.forEach(s -> System.out.println(s));


Stream<String> parallelStream = list.parallelStream(); //获取一个并行流
parallelStream.forEach(s -> System.out.println(s));
 // 并行流 使用  分数不为null的学生人数
Long count = userPoList.parallelStream().filter(p -> null != p.getScore()).count();
//使用 parallelStream 来输出空字符串的数量
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");// 获取空字符串的数量
long count = strings.parallelStream().filter(string -> string.isEmpty()).count();
  1. 使用 Arrays 中的 stream() 方法,将数组转成流
//使用 Arrays 中的 stream() 方法,将数组转成流
Integer[] nums = new Integer[]{20, 3, 5, 8, 9, 4, 1, 0, 23, 11, 20, 4, 5, 3, 5};
Stream<Integer> stream = Arrays.stream(nums);
//去重
Stream<Integer> disInt = stream.distinct();
//排序输出
disInt.sorted(Comparator.naturalOrder()).forEach(n -> System.out.print(n+" "));
  1. 使用Stream中的静态方法:of()、iterate()、generate()
//使用Stream中的静态方法:of()、iterate()、generate()
Stream<Integer> stream = Stream.of(10, 3, 6, 8, 0, 2, 4, 7);
//获取最大值
Integer max = stream.max(Comparator.naturalOrder()).get();
System.out.println("max = " + max);

//迭代,步长为3,7次
Stream<Integer> stream1 = Stream.iterate(0, (x) -> x + 3).limit(7);
stream1.forEach(n-> System.out.print(n + " , "));

//随机生成8个数
Stream<Double> stream2 = Stream.generate(Math::random).limit(8);
stream2.forEach(System.out::println);
  1. 使用 BufferedReader.lines() 方法,将每行内容转成流
 //使用 BufferedReader.lines() 方法,将每行内容转成流
BufferedReader reader = new BufferedReader(new FileReader("spring-boot-java8/doc/meiwen.txt"));
Stream<String> lineStream = reader.lines();
lineStream.forEach(System.out::println);
  1. 使用 Pattern.splitAsStream() 方法,将字符串分隔成流:
//使用 Pattern.splitAsStream() 方法,将字符串分隔成流:
Pattern pattern = Pattern.compile("\\|");
String str = "10687699|10687722|10687725|10687729|10687751|10687759|10687772|10687773|10687774";
Stream<String> stringStream = pattern.splitAsStream(str);
stringStream.forEach(System.out::println);

本次分享就到此,后续还会不断更新!如果对你有帮助,请点赞支持一下!

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP