文章目录
1、Strema概述
java 8 新增了Stream,配合同版本出现的 Lambda ,给我们操作集合(Collection)提供了极大的便利。
什么是Stream流?
Stream将要处理的元素集合看作一种流,在流的过程中,借助Stream API对流中的元素进行操作,比如:筛选、排序、聚合等。
Stream可以由数组或集合创建,对流的操作分为两种:
- 中间操作,每次返回一个新的流,可以有多个。(筛选filter、映射map、排序sorted、去重组合skip—limit)
- 终端操作,每个流只能进行一次终端操作,终端操作结束后流无法再次使用。终端操作会产生一个新的集合或值。(遍历foreach、匹配find–match、规约reduce、聚合max–min–count、收集collect)
如下图所示,每个流可以进行多次中间操作,但是只能进行一次终端操作
2、Stream流和传统for循环遍历的对比
假设要输出所有姓张的三字名称,分别使用for循环和stream流来实现
for循环:
import java.util.ArrayList;
import java.util.List;
public class Demo1List {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("小昭");
list.add("殷离");
list.add("张三");
list.add("张三丰");
List<String> listA = new ArrayList<>();
for ( String s : list) {
if (s.startsWith("张"))
listA.add(s);
}
List<String> listB = new ArrayList<>();
for (String s: listA) {
if (s.length() == 3)
listB.add(s);
}
for (String s: listB) {
System.out.println(s);
}
}
}
stream流:
import java.util.ArrayList;
import java.util.List;
public class Demo2Steam {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("小昭");
list.add("殷离");
list.add("张三");
list.add("张三丰");
list.stream()
.filter(name -> name.startsWith("张"))
.filter(name -> name.length() == 3)
.forEach(name -> System.out.println(name));
}
}
差别显而易见,可以看出用Stream流写出的代码结构更清晰,代码意图更易于理解。
3、Stream流的创建
1、Cllection集合可以直接使用内置的stream()方法进行创建
List<String> list = Arrays.asList("a", "b", "c");
// 创建一个顺序流
Stream<String> stream = list.stream();
stream.forEach(System.out::println);
// 创建一个并行流
Stream<String> parallelStream = list.parallelStream();
parallelStream.forEach(System.out::println);
2、数组可以使用Arrays.stream(T[] array)方法创建流
int[] array={1,3,5,6,8};
IntStream stream = Arrays.stream(array);
3、使用Stream的静态方法:of()、iterate()、generate()
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 3).limit(4);
stream2.forEach(System.out::println);
Stream<Double> stream3 = Stream.generate(Math::random).limit(3);
stream3.forEach(System.out::println);
4、stream和parallelStream的区别
stream是顺序流,由主线程按顺序对流执行操作,而parallelStream是并行流,内部以多线程并行执行的方式对流进行操作。使用并行流的前提是对流中的数据处理顺序没有要求。在流中数据量大的时候,并行流可以加快处理速度。
除了直接创建并行流,还可以通过parallel()方法把顺序流转换成并行流:
List<Integer> list = Arrays.asList(9, 11, 10, 8, 12, 4);
//将集合转换成顺序流
Stream<Integer> stream = list.stream();
//将顺序流转换成并行流
Stream<Integer> parallelstream = stream.parallel();
//打印
parallelstream.forEach(System.out::println);
打印结果为:8 4 12 9 11 10。
5、什么是Optional
在使用stream之前,先理解一个概念:Optional 。
Optional类(java.util.Optional) 是一个容器类,代表一个值存在或不存在,原来用 null 表示一个值不存在,现在 Optional 可以更好的表达这个概念。并且可以避免空指针异常。
6、Steam流的方法演示
(1)遍历流中元素:forEach
List<Integer> list = Arrays.asList(7, 6, 9, 3, 8, 2, 1);
// 遍历流中的元素
list.stream().forEach(System.out::println);
//或者
list.stream().forEach(x -> System.out.println(x));
结果依次输出7, 6, 9, 3, 8, 2, 1
(2)匹配:findFirst、findAny、anyMatch、allMatch:
List<Integer> list = Arrays.asList(7, 6, 9, 3, 8, 2, 1);
// 匹配第一个
Optional<Integer> findFirst = list.stream().filter(x -> x > 6).findFirst();
// 匹配任意(适用于并行流)
Optional<Integer> findAny = list.parallelStream().filter(x -> x > 6).findAny();
// 是否包含符合特定条件的元素
boolean anyMatch = list.stream().anyMatch(x -> x > 6);
//元素是否全部符合一定条件
boolean allMatch = list.stream().allMatch(x -> x > 6);
System.out.println("匹配第一个值:" + findFirst.get());
System.out.println("匹配任意一个值:" + findAny.get());
System.out.println("是否存在大于6的值:" + anyMatch);
System.out.println("是否存在大于6的值:" + allMatch);
输出结果为:
匹配第一个值:7
匹配任意一个值:8
是否存在大于6的值:true
是否存在大于6的值:false
(3)筛选:filter
筛选出大于6的值并打印输出:
List<Integer> list = Arrays.asList(7, 6, 9, 3, 8, 2, 1);
//筛选出大于6的值并打印输出
list.stream().filter(x -> x > 6).forEach(System.out::println);
输出结果:7, 6, 9,8
(4) max、min、count
max——获取Integer集合中的最大值:
public class StreamTest {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(7, 6, 9, 4, 11, 6);
// 自然排序
Optional<Integer> max = list.stream().max(Integer::compareTo);
// 自定义排序
Optional<Integer> max2 = list.stream().max(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
});
System.out.println("自然排序的最大值:" + max.get());
System.out.println("自定义排序的最大值:" + max2.get());
}
}
输出结果为:
自然排序的最大值:11
自定义排序的最大值:11
min与之相反。
count——计算Integer集合中大于6的元素的个数:
import java.util.Arrays;
import java.util.List;
public class StreamTest {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(7, 6, 4, 8, 2, 11, 9);
long count = list.stream().filter(x -> x > 6).count();
System.out.println("list中大于6的元素个数:" + count);
}
}
结果输出:list中大于6的元素个数:4
(5)映射: map、flatMap
map
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
flatMap
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
映射,可以将一个流的元素按照一定的映射规则映射到另一个流中。分为map和flatMap:
- map:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
- flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
map的应用(1)——将集合中的数全部+3:
List<Integer> list = Arrays.asList(7, 6, 9, 4, 11, 6);
//将每个数加3
List<Integer> newList = list.stream().map(x -> x+3).toList();`
System.out.println("每个元素+3:" + newList);
输出结果:每个元素+3:[10, 9, 12, 7, 14, 9]
map的应用(2)——将集合中的字母全部改为大写
String[] strArr = { "abcd", "bcdd", "defde", "fTr" };
List<String> strList = Arrays.stream(strArr).map(String::toUpperCase).toList();
System.out.println("每个元素大写:" + strList);
输出结果:每个元素大写:[ABCD, BCDD, DEFDE, FTR]
flatMap的应用——将两个字符数组合并成一个新的字符数组
List<String> list = Arrays.asList("m,k,l,a", "1,3,5,7");
List<String> listNew = list.stream().flatMap(s -> {
// 将每个元素转换成一个stream
String[] split = s.split(",");
Stream<String> s2 = Arrays.stream(split);
return s2;
}).toList();
System.out.println("处理前的集合:" + list);
System.out.println("处理后的集合:" + listNew);
输出结果:
处理前的集合:[m,k,l,a, 1,3,5,7]
处理后的集合:[m, k, l, a, 1, 3, 5, 7]
(6)归约:reduce
归约,也称缩减,顾名思义,是把一个流缩减成一个值,能实现对集合求和、求乘积和求最值操作。
利用reduce()方法求Integer集合的元素之和,乘积,和最大值:
public class StreamTest {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 3, 2, 8, 11, 4);
// 求和方式1
Optional<Integer> sum = list.stream().reduce((x, y) -> x + y);
// 求和方式2
Optional<Integer> sum2 = list.stream().reduce(Integer::sum);
// 求和方式3
Integer sum3 = list.stream().reduce(0, Integer::sum);
// 求乘积
Optional<Integer> product = list.stream().reduce((x, y) -> x * y);
// 求最大值方式1
Optional<Integer> max = list.stream().reduce((x, y) -> x > y ? x : y);
// 求最大值写法2
Integer max2 = list.stream().reduce(1, Integer::max);
System.out.println("list求和:" + sum.get() + "," + sum2.get() + "," + sum3);
System.out.println("list求积:" + product.get());
System.out.println("list求和:" + max.get() + "," + max2);
}
}
输出:
list求和:29,29,29
list求积:2112
list求和:11,11
结语
以上是小编总结的Stream流的学习笔记,供交流学习使用,欢迎大家一起学习讨论~