首页 > 基础资料 博客日记

Java Stream流以及常用方法详解

2025-01-03 08:00:08基础资料围观392

本篇文章分享Java Stream流以及常用方法详解,对你有帮助的话记得收藏一下,看Java资料网收获更多编程知识

目录

一、Stream流是什么?

二、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 = [张三丰, 张二封]
     Map<String, String> collect = list.stream()
                .distinct()
                .filter(s -> s.startsWith("傅"))
                .collect(Collectors.toMap(k -> k.split("红")[0], v -> v.split("红")[1]));
        System.out.println(collect);

统计(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}

总结:


文章来源:https://blog.csdn.net/Tomkruse11/article/details/143918733
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!

标签:

相关文章

本站推荐

标签云