为了账号安全,请及时绑定邮箱和手机立即绑定

Java Stream用法总结(一)

标签:
Java

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);

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

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
JAVA开发工程师
手记
粉丝
1.5万
获赞与收藏
8507

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消