目录
一、Stream流是什么?
Stream流是Java 8中的一个新特性,它提供了一种处理集合和数组的方式。Stream流可以让我们以一种更加简洁、高效、可读性更强的方式来处理数据。,这个版本新增的Stream,配合同版本出现的 Lambda ,给我们操作集合(Collection)提供了极大的便利。Stream流可以用于过滤、映射、排序、聚合等操作,它可以让我们避免使用循环和条件语句来处理数据,从而让代码更加简洁易懂。
那么什么是Stream?
Stream将要处理的元素集合看作一种流,在流的过程中,借助Stream API对流中的元素进行操作,比如:筛选、排序、聚合等。是一种基于支持一次性处理数据的数据源的元素序列,流只能使用一次。
关于对Stream流的理解,你可以把他当成工厂中的流水线,每个stream流的操作过程遵循着创建 -->操作 -->获取结果的过程,就像流水线上的节点一样组成一个个链条。除此之外你还可以把他理解成sql的视图,集合就相当于数据表中的数据,获取stream流的过程就是确定数据表的属性和元数据的过程,元数据的每一个元素就是表中的数据,对stream流进行操作的过程就是通过sql对这些数据进行查找、过滤、组合、计算、操作、分组等过程,获取结果就是sql执行完毕之后获取的结果视图一样,深入理解stream流可以让我们使用更加简洁的代码获取自己想要的数据。
流的设计初衷是为了支持函数式编程,它的目的是将数据处理和数据存储分离开来,使得数据处理更加灵活和高效。因此,流的元素只是在流中传递的临时数据,它们并不是永久存储在内存中的数据。当流的元素被消费后,它们就会被释放,不能再次使用.
如果需要对同一个数据集进行多次不同的操作,可以使用流的中间操作方法来构建多个流管道,每个流管道都可以对流进行不同的操作,并返回一个新的流。这样就可以对同一个数据集进行多次操作,而不需要重新获取数据集。
所以说Stream可以由数组或集合创建,对流的操作分为两种:
- 中间操作,每次返回一个新的流,可以有多个。
- 终端操作,每个流只能进行一次终端操作,终端操作结束后流无法再次使用。终端操作会产生一个新的集合或值。
另外,Stream有几个特性:
- stream不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果。
- stream不会改变数据源,通常情况下会产生一个新的集合或一个值。
- stream具有延迟执行特性,只有调用终端操作时,中间操作才会执行。也就是说只有等到用户真正需要结果的时候才会执行
二、stream的操作
2.1、stream流创建
获取stream流的方式有许多种,最常用的有以下几种:
- 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));
stream和parallelStream的简单区分: stream是顺序流,由主线程按顺序对流执行操作,而parallelStream是并行流,内部以多线程并行执行的方式对流进行操作,但前提是流中的数据处理没有顺序要求。例如筛选集合中的奇数,两者的处理不同之处:
- 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));
- 静态的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流接口中定义了许多对于集合的操作方法,总的来说可以分为两大类:中间操作和终端操作:
- 中间操作:会返回一个流,通过这种方式可以将多个中间操作连接起来,形成一个调用链,从而转换为另外 一个流。除非调用链后存在一个终端操作,否则中间操作对流不会进行任何结果处理。
- 终端操作:会返回一个具体的结果,如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}
总结:
标签:Java,Stream,stream,System,详解,println,操作,out From: https://blog.csdn.net/Tomkruse11/article/details/143918733