返回顶部
首页 > 资讯 > 前端开发 > node.js >Java Stream流式编程常见的坑有哪些
  • 822
分享到

Java Stream流式编程常见的坑有哪些

2024-04-02 19:04:59 822人浏览 安东尼
摘要

本篇内容介绍了“Java Stream流式编程常见的坑有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

本篇内容介绍了“Java Stream流式编程常见的坑有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

1. Stream是什么?

Stream是Java8新增的一个接口,允许以声明性方式处理数据集合。Stream不是一个集合类型不保存数据,可以把它看作是遍历数据集合的高级迭代器(Iterator)。

Stream操作可以像Builder一样逐步叠加,形成一条流水线。流水线一般由数据源+零或者多个中间操作+一个终端操作所构成。中间操作可以将流转换成另外一个流,比如使用filter过滤元素,使用map映射提取值。

Stream与lambda表达式密不可分,本文默认你已经掌握了lambda基础知识。

2. Stream的特点

  • 只能遍历(消费)一次。Stream实例只能遍历一次,终端操作后一次遍历就结束,再次遍历需要重新生成实例,这一点类似于Iterator迭代器。

  • 保护数据源。对Stream中任何元素的修改都不会导致数据源被修改,比如过滤删除流中的一个元素,再次遍历该数据源依然可以获取该元素。

  • 懒。filter, map 操作串联起来形成一系列中间运算,如果没有一个终端操作(如collect)这些中间运算永远也不会被执行。

3. 创建Stream实例的方法

(1)使用指定值创建Stream实例

// of为Stream的静态方法 Stream<String> strStream = Stream.of("hello", "java8", "stream"); // 或者使用基本类型流 IntStream intStream = IntStream.of(1, 2, 3); 复制代码

(2)使用集合创建Stream实例(常用方式)

// 使用guava库,初始化一个不可变的list对象 ImmutableList<Integer> integers = ImmutableList.of(1, 2, 3); // List接口继承Collection接口,java8在Collection接口中添加了stream方法 Stream<Integer> stream = integers.stream(); 复制代码

(3)使用数组创建Stream实例

// 初始化一个数组 Integer[] array = {1, 2, 3}; // 使用Arrays的静态方法stream Stream<Integer> stream = Arrays.stream(array); 复制代码

(4)使用生成器创建Stream实例

// 随机生成100个整数 Random random = new Random(); // 加上limit否则就是无限流了 Stream<Integer> stream = Stream.generate(random::nextInt).limit(100); 复制代码

(5)使用迭代器创建Stream实例

// 生成100个奇数,加上limit否则就是无限流了 Stream<Integer> stream = Stream.iterate(1, n -> n + 2).limit(100); stream.forEach(System.out::println); 复制代码

(6)使用IO接口创建Stream实例

// 获取指定路径下文件信息,list方法返回Stream类型 Stream<Path> pathStream = Files.list(Paths.get("/")); 复制代码

4. Stream常用操作

Stream接口中定义了很多操作,大致可以分为两大类,一类是中间操作,另一类是终端操作;

Java Stream流式编程常见的坑有哪些

(1)中间操作

中间操作会返回另外一个流,多个中间操作可以连接起来形成一个查询。

中间操作有惰性,如果流上没有一个终端操作,那么中间操作是不会做任何处理的。

下面介绍常用的中间操作:

map操作

map是将输入流中每一个元素映射为另一个元素形成输出流。

// 初始化一个不可变字符串 List<String> Words = ImmutableList.of("hello", "java8", "stream"); // 计算列表中每个单词的长度 List<Integer> list = words.stream()         .map(String::length)         .collect(Collectors.toList()); // output: 5 5 6 list.forEach(System.out::println); 复制代码

flatMap操作

List<String[]> list1 = words.stream()         .map(word -> word.split("-"))         .collect(Collectors.toList());          // output: [Ljava.lang.String;@59f95c5d,  //             [Ljava.lang.String;@5ccd43c2 list1.forEach(System.out::println); 复制代码

哪里?你预期是List, 返回却是List<String[]>, 这是因为split方法返回的是String[]

这个时候你可以想到要将数组转成stream, 于是有了第二个版本

Stream<Stream<String>> arrStream = words.stream()         .map(word -> word.split("-"))         .map(Arrays::stream);          // output: java.util.stream.ReferencePipeline$Head@2c13Da15,  // java.util.stream.ReferencePipeline$Head@77556fd arrStream.forEach(System.out::println); 复制代码

还是不对,这个问题使用flatMap扁平流可以解决,flatMap将流中每个元素取出来转成另外一个输出流

Stream<String> strStream = words.stream()         .map(word -> word.split("-"))         .flatMap(Arrays::stream)         .distinct(); // output: hello java8 stream strStream.forEach(System.out::println); 复制代码

filter操作

filter接收Predicate对象,按条件过滤,符合条件的元素生成另外一个流。

// 过滤出单词长度大于5的单词,并打印出来 List<String> words = ImmutableList.of("hello", "java8", "hello", "stream"); words.stream()         .filter(word -> word.length() > 5)         .collect(Collectors.toList())         .forEach(System.out::println); // output: stream 复制代码

(2)终端操作

终端操作将stream流转成具体的返回值,比如List,Integer等。常见的终端操作有:foreach, min, max, count等。

foreach很常见了,下面举一个max的例子。

// 找出最大的值 List<Integer> integers = Arrays.asList(6, 20, 19); integers.stream()         .max(Integer::compareTo)         .ifPresent(System.out::println); // output: 20 复制代码

5. 实战:使用Stream重构老代码

假如有一个需求:过滤出年龄大于20岁并且分数大于95的学生。

使用for循环写法:

private List<Student> getStudents() {     Student s1 = new Student("xiaoli", 18, 95);     Student s2 = new Student("xiaoming", 21, 100);     Student s3 = new Student("xiaohua", 19, 98);     List<Student> studentList = Lists.newArrayList();     studentList.add(s1);     studentList.add(s2);     studentList.add(s3);     return studentList; } public void refactorBefore() {     List<Student> studentList = getStudents();     // 使用临时list     List<Student> resultList = Lists.newArrayList();     for (Student s : studentList) {         if (s.getAge() > 20 && s.getScore() > 95) {             resultList.add(s);         }     }     // output: Student{name=xiaoming, age=21, score=100}     resultList.forEach(System.out::println); } 复制代码

使用for循环会初始化一个临时list用来存放最终的结果,整体看起来不够优雅和简洁。

使用lambda和stream重构后:

public void refactorAfter() {     List<Student> studentLists = getStudents();     // output: Student{name=xiaoming, age=21, score=100}    studentLists.stream().filter(this::filterStudents).forEach(System.out::println); } private boolean filterStudents(Student student) {     // 过滤出年龄大于20岁并且分数大于95的学生     return student.getAge() > 20 && student.getScore() > 95; } 复制代码

使用filter和方法引用使代码清晰明了,也不用声明一个临时list,非常方便。

6. 使用Stream常见的误区

(1)误区一:重复消费stream对象

stream对象一旦被消费,不能再次重复消费。

List<String> strings = Arrays.asList("hello", "java8", "stream"); Stream<String> stream = strings.stream(); stream.forEach(System.out::println); // ok stream.forEach(System.out::println); // IllegalStateException 复制代码

上述代码执行后报错:

java.lang.IllegalStateException: stream has already been operated upon or closed

(2)误区二:修改数据源

在流操作的过程中尝试添加新的string对象,结果报错:

List<String> strings = Arrays.asList("hello", "java8", "stream"); // expect: HELLO JAVA8 STREAM WORLD, but throw UnsupportedOperationException strings.stream()         .map(s -> {             strings.add("world");             return s.toUpperCase();         }).forEach(System.out::println); 复制代码

注意:一定不要在操作流的过程中修改数据源。

“Java Stream流式编程常见的坑有哪些”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

--结束END--

本文标题: Java Stream流式编程常见的坑有哪些

本文链接: https://lsjlt.com/news/84432.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Java Stream流式编程常见的坑有哪些
    本篇内容介绍了“Java Stream流式编程常见的坑有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!...
    99+
    2024-04-02
  • Java中常见的坑有哪些
    今天小编给大家分享一下Java中常见的坑有哪些的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。1.前言同一个代码“坑”,踩第一...
    99+
    2023-06-27
  • Java中ReentrantLock常见的坑有哪些
    这篇文章主要介绍“Java中ReentrantLock常见的坑有哪些”,在日常操作中,相信很多人在Java中ReentrantLock常见的坑有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java中Re...
    99+
    2023-06-30
  • Java编程中常见的问题有哪些
    本篇内容介绍了“Java编程中常见的问题有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!字符串连接误用错误的写法:String ...
    99+
    2023-06-17
  • JAVA编程中的常见问题有哪些
    本篇内容主要讲解“JAVA编程中的常见问题有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“JAVA编程中的常见问题有哪些”吧!问题一:编译器找不到类。解决方法:确保你已经导入了类或者它的包。...
    99+
    2023-06-17
  • Java开发编程的坑有哪些
    这篇文章主要讲解了“Java开发编程的坑有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java开发编程的坑有哪些”吧!随处可见的 Null 值我见过很...
    99+
    2024-04-02
  • Java8 Stream流的常用方法有哪些
    这篇文章主要介绍“Java8 Stream流的常用方法有哪些”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Java8 Stream流的常用方法有哪些”文章能帮助大家解决问题。1、...
    99+
    2023-07-02
  • Java流式编程有哪些优缺点
    Java流式编程的优点包括:1. 简化代码:流式编程能够将复杂的代码逻辑简化成一系列简洁的操作,提高代码的可读性和可维护性。2. 减...
    99+
    2023-10-10
    Java
  • golang函数式编程的常见用法有哪些?
    go 语言支持函数式编程,提供内置函数式工具,如 map、filter、reduce等,允许使用无状态函数和不可变数据。高阶函数允许函数接受或返回其他函数,例如 sort.slice 函...
    99+
    2024-05-01
    golang 函数式编程 作用域
  • 编写Java的坑有哪些
    本篇内容主要讲解“编写Java的坑有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“编写Java的坑有哪些”吧!1、对象比较方法JDK 1.7 提供的 Objects.equals 方法,非常...
    99+
    2023-06-16
  • Java中常见的限流算法有哪些
    这篇“Java中常见的限流算法有哪些”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Java中常见的限流算法有哪些”文章吧。0...
    99+
    2023-07-05
  • Java编程中的常见算法错误有哪些?
    在Java编程中,算法是一项非常重要的技能。无论是在工作中还是面试中,编写高质量的算法都是必要的。然而,即使是经验丰富的Java程序员,在编写算法时也会犯一些常见的错误。在本文中,我们将讨论一些常见的Java编程中的算法错误,并提供演示代...
    99+
    2023-09-25
    编程算法 laravel 对象
  • Java IO流常见面试题有哪些
    本篇内容主要讲解“Java IO流常见面试题有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java IO流常见面试题有哪些”吧!IO概述在这一小节,我会试着给出Java IO(java.i...
    99+
    2023-06-02
  • Java和JSP编程中常见问题有哪些
    这篇文章主要为大家展示了“Java和JSP编程中常见问题有哪些”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Java和JSP编程中常见问题有哪些”这篇文章吧。Java是由Sun Microsys...
    99+
    2023-06-17
  • Java常见设计模式有哪些
    这篇文章主要介绍Java常见设计模式有哪些,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、设计模式总述:1、什么是设计模式:设计模式是一套经过反复使用的代码设计经验,目的是为了重用代码、让代码更容易被他人理解、保证...
    99+
    2023-06-29
  • java的常见异常有哪些
    1、NullPointerException:空指针异常,当操作一个 null 对象的方法或属性时会抛出这个异常。是一个很头疼的异常,因为它是运行时异常,不需要手动捕获,但运行时碰到这个异常会中断程序。 (推荐学习:j...
    99+
    2018-01-05
    java入门 java
  • 常见的Java异常有哪些
    本篇文章为大家展示了常见的Java异常有哪些,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。异常是 Java 程序中经常遇到的问题,我想每一个 Java 程序员都讨厌异常,一 个异常就是一个 BUG,...
    99+
    2023-06-16
  • C++构造函数常见的坑有哪些
    今天就跟大家聊聊有关C++构造函数常见的坑有哪些,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。某一天我们接到了一个需求,需要开发一个类似于STL中string的类。我们很快写好了代码...
    99+
    2023-06-22
  • Lambda 的陷阱与挑战:Java 函数式编程中的常见坑
    使用 Lambda 表达式时,如果在 Lambda 中捕获了外部变量,而该变量的生命周期比 Lambda 本身长,则可能会导致内存泄漏。这是因为 Lambda 会一直持有对该变量的引用,即使它不再需要该变量。 不可变性问题 Lambda ...
    99+
    2024-04-02
  • Java常见异常有哪些
    这篇文章主要介绍Java常见异常有哪些,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、概述异常指不期而至的各种状况,它在程序运行的过程中发生。作为开发者,我们都希望自己写的代码 永远都不会出现 bug,然而现实告诉...
    99+
    2023-06-15
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作