Java Stream流以及常用方法操作实例

 更新时间:2025年08月11日 08:33:29   作者:重生之Java开发工程师  
Stream是对Java中集合的一种增强方式,使用它可以将集合的处理过程变得更加简洁、高效和易读,这篇文章主要介绍了Java Stream流以及常用方法的相关资料,需要的朋友可以参考下

一、Stream流是什么?

Stream流是Java 8中的一个新特性,它提供了一种处理集合和数组的方式。Stream流可以让我们以一种更加简洁、高效、可读性更强的方式来处理数据。,这个版本新增的Stream,配合同版本出现的 Lambda ,给我们操作集合(Collection)提供了极大的便利。Stream流可以用于过滤、映射、排序、聚合等操作,它可以让我们避免使用循环和条件语句来处理数据,从而让代码更加简洁易懂。

那么什么是Stream

Stream将要处理的元素集合看作一种流,在流的过程中,借助Stream API对流中的元素进行操作,比如:筛选、排序、聚合等。是一种基于支持一次性处理数据的数据源的元素序列,流只能使用一次。

关于对Stream流的理解,你可以把他当成工厂中的流水线,每个stream流的操作过程遵循着创建 -->操作 -->获取结果的过程,就像流水线上的节点一样组成一个个链条。除此之外你还可以把他理解成sql的视图,集合就相当于数据表中的数据,获取stream流的过程就是确定数据表的属性和元数据的过程,元数据的每一个元素就是表中的数据,对stream流进行操作的过程就是通过sql对这些数据进行查找、过滤、组合、计算、操作、分组等过程,获取结果就是sql执行完毕之后获取的结果视图一样,深入理解stream流可以让我们使用更加简洁的代码获取自己想要的数据。

流的设计初衷是为了支持函数式编程,它的目的是将数据处理和数据存储分离开来,使得数据处理更加灵活和高效。因此,流的元素只是在流中传递的临时数据,它们并不是永久存储在内存中的数据。当流的元素被消费后,它们就会被释放,不能再次使用.

如果需要对同一个数据集进行多次不同的操作,可以使用流的中间操作方法来构建多个流管道,每个流管道都可以对流进行不同的操作,并返回一个新的流。这样就可以对同一个数据集进行多次操作,而不需要重新获取数据集。

所以说Stream可以由数组或集合创建,对流的操作分为两种:

  1. 中间操作,每次返回一个新的流,可以有多个。
  2. 终端操作,每个流只能进行一次终端操作,终端操作结束后流无法再次使用。终端操作会产生一个新的集合或值。

另外,Stream有几个特性:

  1. stream不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果。
  2. stream不会改变数据源,通常情况下会产生一个新的集合或一个值。
  3. stream具有延迟执行特性,只有调用终端操作时,中间操作才会执行。也就是说只有等到用户真正需要结果的时候才会执行

二、stream的操作

2.1、stream流创建

获取stream流的方式有许多种,最常用的有以下几种:

  1. Collection接口的stream()或parallelStream()方法;
ArrayList<String> list=new ArrayList();
Collections.addAll(list,"a,b,c,d");
//ArrayList是Collection的实现类所以可以使用Collection的stream方法
list.stream().forEach(s -> System.out.println(s)); //Stream流方法获取数据
//map
HashMap<String,Integer> map=new HashMap<>();
map.put("aaa",111);
map.put("bbb",222);
map.put("ccc",333);
map.put("ddd",444);
 
//获取Stream流
map.keySet().stream().forEach(s -> System.out.println(s));
//第二种方式
map.entrySet().stream().forEach(stringIntegerEntry -> System.out.println(stringIntegerEntry));

streamparallelStream的简单区分: stream是顺序流,由主线程按顺序对流执行操作,而parallelStream是并行流,内部以多线程并行执行的方式对流进行操作,但前提是流中的数据处理没有顺序要求。例如筛选集合中的奇数,两者的处理不同之处:

  1. Arrays工具类的stream()方法:Arrays.stream(arr);
//数组
int [] arr ={1,2,3,4,5};
String [] stringArr={"哈哈","哈哈哈","哈哈哈"};
 
//获取stream流
Arrays.stream(arr).forEach(s-> System.out.println(s));
Arrays.stream(stringArr).forEach(s -> System.out.println(s));
  1. 静态的Stream.of()、Stream.empty()方法;
//零散数据stream流
Stream.of(1,2,3,4).forEach(s-> System.out.println(s));
 
Stream.of("6","7","8","9").forEach(s-> System.out.println(s));

注:

有关of方法的使用还有List.of()、Set.of()、Map.of()的方式创建各种集合,其表示的含义都是不可变集合,表示不允许修改集合内任何内容。

Stream.of(arr)中还可以传递数组但必须是引用类型的,而不是基本类型的,比如数组类中的stringArr,如果传递的是arr基本类型数组,那么会打印一个对象地址,不符合我们想要的效果.

2.2、stream的使用

Stream流接口中定义了许多对于集合的操作方法,总的来说可以分为两大类:中间操作和终端操作:

  1. 中间操作:会返回一个流,通过这种方式可以将多个中间操作连接起来,形成一个调用链,从而转换为另外 一个流。除非调用链后存在一个终端操作,否则中间操作对流不会进行任何结果处理。
  2. 终端操作:会返回一个具体的结果,如boolean、list、integer等。

2.2.1、中间操作-filter(筛选)

筛选,是按照一定的规则校验流中的元素,将符合条件的元素提取到新的流中的操作。

ArrayList<String> list=new ArrayList();
Collections.addAll(list,"张三丰","张二封","乔峰","傅红雪","张三丰","乔峰");
//filter 过滤/筛选
list.stream().filter(s -> s.startsWith("张")).forEach(s -> System.out.println(s));
 
//运行结果
张三丰
张二封
ArrayList<Integer> arrayList=new ArrayList<>();
Collections.addAll(arrayList,1,2,3,4,6,7,8);
arrayList.stream().filter(x-> x>6).forEach(x-> System.out.println(x)); //筛选出大于6的
 
//运行结果
7
8

2.2.2、中间操作-limit

获取前几个元素,不是索引,就是单纯个数。

 //limit 获取前几个元素 与索引无关  就是单纯前几个
arrayList.stream().limit(3).forEach(s-> System.out.print(s));
//运行结果
123

2.2.3、中间操作-skip

跳过前几个元素

//skip  跳过前几个元素
arrayList.stream().skip(3).forEach(s-> System.out.print(s));
//运行结果
4678

2.2.4、中间操作-distinct

元素去重,依赖于hashcode和equals方法(底层利用hashSet()方法去重)

//distinct 去重 依赖hashcode和equals方法
list.stream().distinct().forEach(s -> System.out.println(s));
//运行结果
张三丰
张二封
乔峰
傅红雪

2.2.5、中间操作-concat

合并两个流:Stream.concat(stream1,stream2)

//concat 合并两个流
Stream.concat(list.stream(),arrayList.stream()).forEach(s -> System.out.println(s));
//运行结果
张三丰
张二封
乔峰
傅红雪
张三丰
乔峰
1
2
3
4
6
7
8

2.2.6、中间操作-map

转换流中数据类型,返回一个新的流

//map  转换流中的数据结构
arrayList.stream().map(s->String.valueOf(s)).forEach(s -> System.out.println(s));
//运行结果
数组中整数全部转换为了string类型

2.2.7、终端操作-foreach

遍历方法,终端操作表示调用该方法后不能再使用该流。

   list.stream().distinct().forEach(s -> System.out.println(s));

2.2.7、终端操作-count

统计计数

//终端方法 foreach  count()
long count = list.stream().count();
System.out.println(count);
//运行结果
6

2.2.8、终端操作-toArray()

收集流中的数据,放到数组中。

String[] strings = list.stream().toArray(value -> new String[value]);
System.out.println(Arrays.toString(strings));
 
//运行结果
[张三丰, 张二封, 乔峰, 傅红雪, 张三丰, 乔峰]

2.2.9、终端操作-collect()

collect,收集,可以说是内容最繁多、功能最丰富的部分了。从字面上去理解,就是把一个流收集起来,最终可以是收集成一个值也可以收集成一个新的集合。

collect主要依赖java.util.stream.Collectors类内置的静态方法。

归集(toList/toSet/toMap)

因为流不存储数据,那么在流中的数据完成处理后,需要将流中的数据重新归集到新的集合里。toList、toSet和toMap比较常用,另外还有toCollection、toConcurrentMap等复杂一些的用法。

//  toList 将流中的数据转换为一个新的集合
List<String> newList = list.stream()
                            .filter(s -> s.startsWith("张"))
                            .collect(Collectors.toList());
//运行结果
[张三丰, 张二封, 张三丰]
//toSet集合
Set<String> newSet = list.stream()
                                .filter(s -> s.startsWith("张"))
                                .collect(Collectors.toSet());
System.out.println("newSet = " + newSet);
//运行结果
newSet = [张三丰, 张二封]

统计(count/averaging)

Collectors提供了一系列用于数据统计的静态方法:

  • 计数:count
  • 平均值:averagingInt、averagingLong、averagingDouble
  • 最值:maxBy、minBy
  • 求和:summingInt、summingLong、summingDouble
  • 统计以上所有:summarizingInt、summarizingLong、summarizingDouble
public class StreamTest {
	public static void main(String[] args) {
		List<Person> personList = new ArrayList<Person>();
		personList.add(new Person("Tom", 8900, 23, "male", "New York"));
		personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
		personList.add(new Person("Lily", 7800, 21, "female", "Washington"));
 
		// 求总数
		Long count = personList.stream().collect(Collectors.counting());
		// 求平均工资
		Double average = personList.stream().collect(Collectors.averagingDouble(Person::getSalary));
		// 求最高工资
		Optional<Integer> max = personList.stream().map(Person::getSalary).collect(Collectors.maxBy(Integer::compare));
		// 求工资之和
		Integer sum = personList.stream().collect(Collectors.summingInt(Person::getSalary));
		// 一次性统计所有信息
		DoubleSummaryStatistics collect = personList.stream().collect(Collectors.summarizingDouble(Person::getSalary));
 
		System.out.println("员工总数:" + count);
		System.out.println("员工平均工资:" + average);
		System.out.println("员工工资总和:" + sum);
		System.out.println("员工工资所有统计:" + collect);
	}
}
 
运行结果:
员工总数:3
员工平均工资:7900.0
员工工资总和:23700
员工工资所有统计:DoubleSummaryStatistics{count=3, sum=23700.000000,min=7000.000000, average=7900.000000, max=8900.000000}

总结:

到此这篇关于Java Stream流以及常用方法的文章就介绍到这了,更多相关Java Stream流常用方法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java 随机取字符串的工具类

    Java 随机取字符串的工具类

    随机数在实际中使用很广泛,比如要随即生成一个固定长度的字符串、数字。或者随即生成一个不定长度的数字、或者进行一个模拟的随机选择等等。Java提供了最基本的工具,可以帮助开发者来实现这一切
    2014-01-01
  • Spring Security中的Servlet过滤器体系代码分析

    Spring Security中的Servlet过滤器体系代码分析

    这篇文章主要介绍了Spring Security中的Servlet过滤器体系,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-07-07
  • Eclipse中如何显示explorer过程解析

    Eclipse中如何显示explorer过程解析

    这篇文章主要介绍了Eclipse中如何显示explorer过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-09-09
  • Java线程中的Timer和TimerTask原理详解

    Java线程中的Timer和TimerTask原理详解

    这篇文章主要介绍了Java线程中的Timer和TimerTask原理详解,Timer和TimerTask成对出现,Timer是定时器,TimerTask是定时任务,换句话说,定时任务TimerTask是给定时器Timer执行的具体任务,需要的朋友可以参考下
    2023-10-10
  • SpringBoot中配置文件pom.xml的使用详解

    SpringBoot中配置文件pom.xml的使用详解

    SpringBoot的pom.xml文件是Maven项目的核心配置文件,用于定义项目的依赖、插件、构建配置等信息,下面小编就来和大家详细介绍一下它的具体使用吧
    2025-03-03
  • java实现最短路径算法之Dijkstra算法

    java实现最短路径算法之Dijkstra算法

    这篇文章主要介绍了java实现最短路径算法之Dijkstra算法, Dijkstra算法是最短路径算法中为人熟知的一种,是单起点全路径算法,有兴趣的可以了解一下
    2017-10-10
  • 关于重写equals()方法和hashCode()方法及其简单的应用

    关于重写equals()方法和hashCode()方法及其简单的应用

    这篇文章主要介绍了关于重写equals()方法和hashCode()方法及其简单的应用,网上的知识有些可能是错误的,关于 equals() 方法的理解,大家讨论不一样,需要的朋友可以参考下
    2023-04-04
  • java动态口令登录实现过程详解

    java动态口令登录实现过程详解

    这篇文章主要介绍了java动态口令登录实现过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-07-07
  • Java实现饼图旋转角度的代码详解

    Java实现饼图旋转角度的代码详解

    在现代数据可视化领域,饼图因其直观展示各部分占整体比例而被广泛采用,为了增强互动性和吸引力,常会赋予饼图 旋转 动画:自动、平滑地旋转,让用户从不同角度重点查看扇区,本文将从零开始,手把手实现一个 Java2D Swing 版 的 可旋转饼图组件,需要的朋友可以参考下
    2025-05-05
  • Java生成二维码可添加logo和文字功能

    Java生成二维码可添加logo和文字功能

    这篇文章主要介绍了Java生成二维码可添加logo和文字功能,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2017-02-02

最新评论