Java Stream流详解(下)

简介: Java Stream流详解(下)

Peek(展示)


  • peek()方法可以用于在Stream流中获取元素同时执行一些操作,如打印、调试、观察等。通常会与其他的方法联合使用。


public class Main {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alex", "Brian", "Charles", "David");
        List<String> filteredNames = names.stream()
                .peek(System.out::println)
                .filter(name -> name.startsWith("C"))
                .peek(name -> System.out.println("Filtered value: " + name))
                .collect(Collectors.toList());
        System.out.println("-----------------------------------------------------------------");
        System.out.println(filteredNames);
    }
}


0ed74941e24f4b35838840d55c9fe84c.png

代码中创建了一个列表 names 包含四个字符串元素,然后使用流式操作处理这个列表。首先使用 peek() 方法将每个元素打印到控制台,然后使用 filter() 方法过滤掉不符合条件的元素,即不以字母 C 开头的字符串。接下来再次使用 peek() 方法将符合条件的字符串打印到控制台,以便验证过滤操作的效果。最后使用 collect() 方法将符合条件的字符串收集到一个新的列表 filteredNames 中,并输出该列表。

注意到,控制台上先输出了列表中的四个字符串,但只有以字母 C 开头的字符串 Charles 才符合筛选条件,因此仅仅 Charles 被保存在了 filteredNames 列表中。第二个 peek() 方法也被用来打印筛选出的元素 Charles。


终止操作


终止操作返回一个结果或副作用(例如:显示控制台输出),并将流关闭。


forEach(循环)


  • forEach()方法可将给定的方法应用于流中的每个元素。该方法是一种消费流的方式,不会返回值。


public class Main {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alex", "Brian", "Charles", "David");
        names.stream().forEach(System.out::println);
    }
}


a66fe94b5a7041debe27ae337b241968.png


这段代码创建了一个包含四个字符串元素的列表 names,使用流式操作将每个元素打印到控制台。具体来说,它使用 forEach() 方法遍历列表中的所有元素,并对每个元素执行打印操作。

其中,四个字符串元素按顺序打印到了控制台上。注意到,使用 forEach() 方法时并没有指定任何条件或谓词,因此它会对列表中的所有元素进行操作,以达到遍历、打印等目的。


Collect(收集)


  • collect()方法可以将流中的元素收集到一个集合中。一般与其他方法配合使用。


public class Main {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
        List<Integer> evenNumbers = numbers.stream().filter(n -> n % 2 == 0).collect(Collectors.toList());
        System.out.println(evenNumbers);
    }
}


825213184bb94a29bd24a3cd4012c233.png


这段代码创建了一个包含整数的列表 numbers,使用流式操作筛选出所有偶数,然后将它们收集到一个新的列表 evenNumbers 中,并打印输出。具体来说,它使用了 filter() 方法过滤掉所有奇数元素,只保留所有偶数元素,并使用 collect() 方法将它们收集到一个新的列表 evenNumbers 中。

注意到,只有偶数元素被保留在了新列表 evenNumbers 中,而奇数元素全部被过滤掉了。而且,在筛选偶数元素时,使用了 lambda 表达式 n -> n % 2 == 0,其中 % 表示取模操作,判断当前数是否为偶数。如果 n % 2 的结果是 0,就把 n 这个数保留下来,否则就过滤掉。


Count(计数)


  • count()方法可以返回流中的元素数。


public class Main {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alex", "Brian", "Charles", "David");
        long count = names.stream().count();
        System.out.println(count);
    }
}


dbbc57a8dfdf4d13985d53d907fc7aff.png

这段代码创建了一个包含四个字符串元素的列表 names,使用流式操作计算出它包含的元素数量(即列表大小),并将该数量打印到控制台。具体来说,它使用了 count() 方法统计列表中元素的个数。

注意到,count() 方法返回的是一个 long 类型的值,表示列表中元素的个数。因为列表 names 包含了四个元素,所以 count() 方法返回值为 4,最终被打印输出到了控制台。


Reduce(聚合)


  • reduce()方法可以将流元素聚合为单个结果。它接受一个BinaryOperator参数作为累加器。


public class Main {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
        Optional<Integer> sum = numbers.stream().reduce((a, b) -> a + b);
        System.out.println(sum);
    }
}

7b6e9b284d4a48f9949837a76c8f18de.png


这段代码创建了一个包含整数的列表 numbers,使用流式操作将它们累加起来得到总和,并将结果打印输出。具体来说,它使用了 reduce() 方法对列表中的所有元素进行累加操作。reduce() 方法接收一个 BinaryOperator 函数作为参数,用于指定如何处理相邻的两个元素并返回一个新的结果值。

注意到,reduce() 方法返回的是一个 Optional 类型的值,表示结果可能存在也可能不存在(例如当列表为空时)。由于列表 numbers 包含 1 到 5 共五个元素,因此 reduce() 方法的操作过程如下:

1 + 2 = 3

3 + 3 = 6

6 + 4 = 10

10 + 5 = 15

最终得到的结果 15 被包装成 Optional 类型的对象并打印输出到控制台。


AnyMatch(任意匹配)


  • anyMatch()方法如果至少有一个元素与给定的谓词匹配,则返回true。


public class Main {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alex", "Brian", "Charles", "David");
        boolean anyStartsWithB = names.stream().anyMatch(name -> name.startsWith("B"));
        System.out.println(anyStartsWithB);
    }
}

5a5fee3aef4646d889000d0de031d818.png


这段代码创建了一个包含四个字符串元素的列表 names,使用流式操作检查其中是否有任意一个元素以字母 “B” 开头,并将检查结果(布尔值)打印输出。具体来说,它使用了 anyMatch() 方法匹配列表中的所有元素,并依次对每个元素执行指定的谓词操作(这里是以 “B” 开头),只要有一个元素符合条件,就返回 true,否则返回 false。

注意到,列表 names 中包含了一个以字母 “B” 开头的元素 “Brian”,因此 anyMatch() 方法返回 true,最终被打印输出到了控制台。


AllMatch(全部匹配)


  • allMatch()方法如果所有元素都与给定谓词匹配,则返回true。
public class Main {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alex", "Brian", "Charles", "David");
        boolean allStartsWithB = names.stream().allMatch(name -> name.startsWith("B"));
        System.out.println(allStartsWithB);
    }
}

470a1da33766466899ae4e85963917fd.png


这段代码创建了一个包含四个字符串元素的列表 names,使用流式操作检查其中是否所有元素都以字母 “B” 开头,并将检查结果(布尔值)打印输出。具体来说,它使用了 allMatch() 方法匹配列表中的所有元素,并依次对每个元素执行指定的谓词操作(这里是以 “B” 开头),只有当所有元素都符合条件时,才返回 true,否则返回 false。

注意到,虽然列表 names 中包含了一个以字母 “B” 开头的元素 “Brian”,但是它不是所有元素都以 “B” 开头,因此 allMatch() 方法返回 false,最终被打印输出到了控制台。


NoneMatch(无匹配)


  • noneMatch()方法,如果没有任何元素与给定谓词匹配,则返回true。


public class Main {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alex", "Brian", "Charles", "David");
        boolean noneStartsWithB = names.stream().noneMatch(name -> name.startsWith("E"));
        System.out.println(noneStartsWithB);
    }
}

ed6ff0b40efa4551bb905f82161e8457.png


这段代码创建了一个包含四个字符串元素的列表 names,使用流式操作检查其中是否没有任意一个元素以字母 “E” 开头,并将检查结果(布尔值)打印输出。具体来说,它使用了 noneMatch() 方法匹配列表中的所有元素,并依次对每个元素执行指定的谓词操作(这里是以 “E” 开头),只有当所有元素都不符合条件时,才返回 true,否则返回 false。

注意到,列表 names 中不包含任何一个以字母 “E” 开头的元素,因此 noneMatch() 方法返回 true,最终被打印输出到了控制台。


以上就是Java Stream流的基础知识和操作方式。Stream API可以使Java程序员编写出高效,干净,紧凑的代码,使得代码易于阅读和维护。建议初学者多加练习,掌握基本操作。中级和高级程序员则需要深入研究Stream API的实现原理和运作机制,进一步提高代码的质量和效率。

使用Stream流的优缺点:


优点:

Stream流可以帮助简化代码,减少样板代码,从而提高代码质量和可读性。

Stream流充分利用了现代多核处理器的优势,在多线程场景下可以获得更好的性能表现。

Stream流提供了丰富的操作方法,可以轻松地处理各种集合和数组的数据,从而降低程序员的编码难度和心理负担。

Stream流可以帮助开发人员更容易地写出函数式风格的代码,使代码更加健壮可维护。


缺点:


Stream流有时候会让代码变得复杂,反而降低了可读性,因此在某些简单的情况下可能不需要使用Stream流。

Stream流可能会对程序的性能产生一定影响,尤其是在大型数据集或者复杂的业务逻辑的情况下,程序员需要根据具体的情况进行测试和分析,选择最优解。

Stream流可能会造成资源浪费,例如创建中间操作的临时对象,这些对象将占用存储空间,导致效率降低。

在实际开发中,应该根据具体情况来决定是否使用Stream流。一般建议在数据集较大或者需要进行复杂的数据处理操作时使用Stream流,而在一些简单的操作中则可以直接使用循环和传统的集合操作方法。此外,如果代码可读性受到影响,也可以考虑使用传统的集合操作方法来实现代码。


怎么用?


当处理的数据来源于数据库,并需要对其进行某些复杂的过滤或排序时,使用SQL可能更加适合。因为数据库查询语言的操作速度通常会比Java程序快得多,而且可以通过数据库索引进一步提高性能。

但是,如果你需要在本地内存中处理已经读入程序或已经存在于集合中的小型数据集,那么使用Stream流是一个很好的选择。如需使用Java语言过滤和处理数据,Stream流提供了很多方便且易于理解的操作方法,例如:filter()、map()、reduce()等,这些操作可以帮助开发人员轻松地对数据集进行过滤和转换,并支持代码的并行化执行,提高运行效率。


总之,具体要看数据规模和使用场景。对于大规模的数据处理,SQL通常更有优势。而对于小规模的内存数据,Stream流是更灵活和可操作的方式。



相关文章
|
3月前
|
安全 Java API
告别繁琐编码,拥抱Java 8新特性:Stream API与Optional类助你高效编程,成就卓越开发者!
【8月更文挑战第29天】Java 8为开发者引入了多项新特性,其中Stream API和Optional类尤其值得关注。Stream API对集合操作进行了高级抽象,支持声明式的数据处理,避免了显式循环代码的编写;而Optional类则作为非空值的容器,有效减少了空指针异常的风险。通过几个实战示例,我们展示了如何利用Stream API进行过滤与转换操作,以及如何借助Optional类安全地处理可能为null的数据,从而使代码更加简洁和健壮。
107 0
|
19天前
|
Java API 数据处理
探索Java中的Lambda表达式与Stream API
【10月更文挑战第22天】 在Java编程中,Lambda表达式和Stream API是两个强大的功能,它们极大地简化了代码的编写和提高了开发效率。本文将深入探讨这两个概念的基本用法、优势以及在实际项目中的应用案例,帮助读者更好地理解和运用这些现代Java特性。
|
1月前
|
Java 流计算
Flink-03 Flink Java 3分钟上手 Stream 给 Flink-02 DataStreamSource Socket写一个测试的工具!
Flink-03 Flink Java 3分钟上手 Stream 给 Flink-02 DataStreamSource Socket写一个测试的工具!
37 1
Flink-03 Flink Java 3分钟上手 Stream 给 Flink-02 DataStreamSource Socket写一个测试的工具!
|
1月前
|
Java Shell 流计算
Flink-02 Flink Java 3分钟上手 Stream SingleOutputStreamOpe ExecutionEnvironment DataSet FlatMapFunction
Flink-02 Flink Java 3分钟上手 Stream SingleOutputStreamOpe ExecutionEnvironment DataSet FlatMapFunction
23 1
Flink-02 Flink Java 3分钟上手 Stream SingleOutputStreamOpe ExecutionEnvironment DataSet FlatMapFunction
|
2月前
|
存储 Java API
Java——Stream流详解
Stream流是JDK 8引入的概念,用于高效处理集合或数组数据。其API支持声明式编程,操作分为中间操作和终端操作。中间操作包括过滤、映射、排序等,可链式调用;终端操作则完成数据处理,如遍历、收集等。Stream流简化了集合与数组的操作,提升了代码的简洁性
79 11
Java——Stream流详解
|
1月前
|
存储 Java 数据处理
Flink-01 介绍Flink Java 3分钟上手 HelloWorld 和 Stream ExecutionEnvironment DataSet FlatMapFunction
Flink-01 介绍Flink Java 3分钟上手 HelloWorld 和 Stream ExecutionEnvironment DataSet FlatMapFunction
35 1
|
2月前
|
Java API C++
Java 8 Stream Api 中的 peek 操作
本文介绍了Java中`Stream`的`peek`操作,该操作通过`Consumer&lt;T&gt;`函数消费流中的每个元素,但不改变元素类型。文章详细解释了`Consumer&lt;T&gt;`接口及其使用场景,并通过示例代码展示了`peek`操作的应用。此外,还对比了`peek`与`map`的区别,帮助读者更好地理解这两种操作的不同用途。作者为码农小胖哥,原文发布于稀土掘金。
114 9
Java 8 Stream Api 中的 peek 操作
|
2月前
|
Java C# Swift
Java Stream中peek和map不为人知的秘密
本文通过一个Java Stream中的示例,探讨了`peek`方法在流式处理中的应用及其潜在问题。首先介绍了`peek`的基本定义与使用,并通过代码展示了其如何在流中对每个元素进行操作而不返回结果。接着讨论了`peek`作为中间操作的懒执行特性,强调了如果没有终端操作则不会执行的问题。文章指出,在某些情况下使用`peek`可能比`map`更简洁,但也需注意其懒执行带来的影响。
138 2
Java Stream中peek和map不为人知的秘密
|
2月前
|
Java 大数据 API
Java 流(Stream)、文件(File)和IO的区别
Java中的流(Stream)、文件(File)和输入/输出(I/O)是处理数据的关键概念。`File`类用于基本文件操作,如创建、删除和检查文件;流则提供了数据读写的抽象机制,适用于文件、内存和网络等多种数据源;I/O涵盖更广泛的输入输出操作,包括文件I/O、网络通信等,并支持异常处理和缓冲等功能。实际开发中,这三者常结合使用,以实现高效的数据处理。例如,`File`用于管理文件路径,`Stream`用于读写数据,I/O则处理复杂的输入输出需求。
|
2月前
|
Java 程序员 API
Java 8新特性之Lambda表达式与Stream API的探索
【9月更文挑战第24天】本文将深入浅出地介绍Java 8中的重要新特性——Lambda表达式和Stream API,通过实例解析其语法、用法及背后的设计哲学。我们将一探究竟,看看这些新特性如何让Java代码变得更加简洁、易读且富有表现力,同时提升程序的性能和开发效率。