Stream
1.1.作用:
针对集合操作,使用函数式编程方式结合Lambda表达式简化代码
复制
1.2.思想:
Stream仅对数据进行加工,不存储数据,不是数据结构,是API
复制
1.3.定义:
Stream是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列
复制
Stream是Java8中处理集合的关键抽象概念,可以指定对集合的操作,
可以执行复杂的查找、过滤和映射数据等操作。
Stream API可以进行并行操作。
Stream API提供了一种高效且易于使用的数据处理方式。
复制
1.4.操作对象:
集合,数组,Stream
复制
1.5.Stream 和 Collection集合的区别:
Collection是一种静态的内存数据结构,面向内存,存储在内存中。
Stream是有关计算的,面向CPU,通过CPU实现计算。
复制
1.6.特点:
不存储数据
不改变源对象,返回一个持有结果的新Stream
Stream操作是延迟执行,需要调用终止操作方法才会执行
Stream只能操作一次(终止操作方法)
复制
1.7.操作步骤
1.7.1.创建Stream
一个数据源(集合、数组),获取一个Stream
复制
1.7.2.中间操作
一个中间操作链,对数据源的数据进行处理
复制
1.7.3.终止操作
一旦执行终止操作,就执行中间操作链,并产生结果,之后,不会再被使用
复制
1.8.Stream执行方式
串行:线程安全的,但是效率最低
并行:线程不安全,但是效率最高
复制
1.9.获取Stream方式
- 集合
- 数组
- 无限流
- Stream.of()
Stream.of()方法可以接收数组,并将其转换为Stream流。
- 将对象类型数组作为参数传递,会生成对象类型的Stream流
- 将基本类型数组作为参数传递,会生成基本类型数组的Stream流
例如:
Streams = Stream.of(String[] strs);
Streamns = Stream.of(int[] nums);
复制
1.9.5.代码
package com.bobo.study.jdk.stream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Stream;
import org.junit.Test;
public class StreamCreate {
@Test
public void testCreateStream() {
// 集合
// List
List<Integer> list = new ArrayList<Integer>();
list.parallelStream(); // 并行流
list.stream(); // 顺序流
// Set
Set<String> set = new HashSet<String>();
set.parallelStream(); // 并行流
set.stream(); // 顺序流
// Map没有Stream;
// 数组
String[] strs = new String[10];
Arrays.stream(strs);
// Stream.of() 通过参数生成,即将参数的类型统一后,生成Stream对象
Stream<Integer> intStream = Stream.of(1);
Stream<Object> objStream = Stream.of("1", "2", 3);
System.out.println(intStream);
System.out.println(objStream);
// Stream.iterate() 迭代生成, 参数一,迭代开始数值,参数二,如何迭代,输入输出类型一致
Stream<Integer> iterate = Stream.iterate(0, s -> s + 1);
// Stream.generate() 生成器,参数,生成器方法,可以使用随机生成方法生成数据
Stream<UUID> generate = Stream.generate(UUID::randomUUID);
iterate.limit(5).forEach(System.out::println);
generate.limit(5).forEach(System.out::println);
}
}
复制
结果:
java.util.stream.ReferencePipeline$Head@2d38eb89
java.util.stream.ReferencePipeline$Head@5fa7e7ff
0
1
2
3
4
59e3ee40-33b6-49a1-876f-99550ff2d8d5
8cb9b849-567e-42c2-9408-151acb99f22b
686da40c-16ee-4fa7-8f25-7fefc400129c
044387f5-ad74-454f-bd6e-b3caa647c3d5
4fdac61b-5158-4603-ac58-bcf4675cb7b2
复制
1.10.Stream中间操作
1.10.1.筛选与切片
filter(Predicate p) -- 过滤元素
limit(int n) -- 截断流,使其元素个数不超过给定值
skip(int n) -- 跳过给定值的元素,若元素数量不够,则返回空数据
distinct() -- 筛选(去重),通过元素的hashCode()和equals()方法去重复元素
复制
1.10.1.5.代码
package com.bobo.study.jdk.stream;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
public class StreamFilter {
@Test
public void testStreamFilter() {
List<Integer> list = new ArrayList<>();
for(int i = 0; i < 10; i ++) {
list.add(i);
}
list.stream().forEach(StreamFilter :: display);
System.out.println("\n---- filter(s -> s > 0) -----------------------");
// filter(Predicate p) 过滤
list.stream().filter(s -> s > 0).forEach(StreamFilter :: display);
System.out.println("\n---- limit(3) -----------------------");
// limit(int n) 现在,只取n个元素
list.stream().limit(3).forEach(StreamFilter :: display);
System.out.println("\n---- limit(30) -----------------------");
list.stream().limit(30).forEach(StreamFilter :: display);
System.out.println("\n---- skip(5) -----------------------");
// skip(int n) 跳过n个元素
list.stream().skip(5).forEach(StreamFilter :: display);
System.out.println("\n---- skip(50) -----------------------");
list.stream().skip(50).forEach(StreamFilter :: display);
System.out.println("\n---- distinct() -----------------------");
// distinct() 去重
list.add(1);
list.stream().distinct().forEach(StreamFilter :: display);
System.out.println("\n---------------------------");
}
public static void display(Object obj) {
System.out.print(obj + ", ");
}
}
复制
结果:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
---- filter(s -> s > 0) -----------------------
1, 2, 3, 4, 5, 6, 7, 8, 9,
---- limit(3) -----------------------
0, 1, 2,
---- limit(30) -----------------------
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
---- skip(5) -----------------------
5, 6, 7, 8, 9,
---- skip(50) -----------------------
---- distinct() -----------------------
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
---------------------------
复制
1.10.2.映射
map(Function) -- 将元素映射为另一个类型的元素
flatMap(Function<T, Stream>) -- 将元素映射为一个R 类型的元素
复制
对比
参数类型
- map参数为返回任意类型的Function对象
- flatMap参数为返回值为Stream类型的Function对象
返回类型
- map返回值可以是Stream<stream>对象
- flatMap返回值必须是Stream对象,会返回传入的Stream对象进行拆分合并后的Stream对象
复制
1.10.2.4.代码
package com.bobo.study.jdk.stream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.junit.Test;
public class StreamMap {
@Test
public void testStreamMap() {
// map
List<String> strList = Arrays.asList("aa", "bb", "cc", "dd");
Stream<String> map1 = strList.stream().map(s -> s.toUpperCase());
map1.forEach(StreamMap :: println);
System.out.println("\n---------------------------");
// map(Function<? super T, ? extends R> mapper)
// map 方法是将传入进来的数据直接放到原Stream中,即可以Stream<Stream<T>>形式
Stream<Stream<Character>> map2 = strList.stream().map(StreamMap :: strToStreamCharset);
map2.forEach(StreamMap :: println);
System.out.println("\n---------------------------");
// flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
// flatMap 方法是将传入进来的Stream流对象的数据拆分后,放到原Stream中,即Stream<T>形式
Stream<Character> flatMap = strList.stream().flatMap(StreamMap :: strToStreamCharset);
flatMap.forEach(StreamMap :: println);
// map 与 flatMap 方法区别
// map 方法参数无限制,可以是任意返回值的Function<T,R>对象
// flatMap 方法参数必须是返回值为流对象的Function<T, Stream<R>>对象,即参数的返回值必须是Stream对象
// map 返回的是任意数据类型,即返回Stream对象为Stream<R>对象,也可以是Stream<Stream<R>>对象
// flatMap 由于返回的是Stream对象,所以可以将Stream对象数据进行拆分之后,合并一个Stream对象,即返回Stream对象为Stream<R>对象
System.out.println("\n---------------------------");
Stream<char[]> map3 = strList.stream().map(String :: toCharArray);
map3.forEach(StreamMap :: println);
System.out.println("\n---------------------------");
strList = Arrays.asList("3", "1", "2","4");
Stream<Integer> map4 = strList.stream().map(Integer::parseInt);
map4.forEach(StreamMap :: println);
System.out.println("\n---------------------------");
IntStream mapToInt = strList.stream().mapToInt(Integer::parseInt);
mapToInt.forEachOrdered(StreamMap :: println);
System.out.println("\n---------------------------");
}
public static Stream<Character> strToStreamCharset(String str) {
char[] charArray = str.toCharArray();
List<Character> cs = new ArrayList<Character>();
for (char c : charArray) {
cs.add(c);
}
return cs.stream();
}
public static void println(Object obj) {
System.out.print(obj + ", ");
}
}
复制
结果:
AA, BB, CC, DD,
---------------------------
java.util.stream.ReferencePipeline$Head@379619aa,
java.util.stream.ReferencePipeline$Head@cac736f,
java.util.stream.ReferencePipeline$Head@5e265ba4,
java.util.stream.ReferencePipeline$Head@156643d4,
---------------------------
a, a, b, b, c, c, d, d,
---------------------------
[C@182decdb, [C@26f0a63f, [C@4361bd48, [C@53bd815b,
---------------------------
3, 1, 2, 4,
---------------------------
3, 1, 2, 4,
---------------------------
复制
1.10.3.排序
sorted() -- 自然排序
sorted(Comparatorcomparator) -- 自定义排序规则
复制
1.10.3.3.代码
package com.bobo.study.jdk.stream;
import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.junit.Test;
public class StreamSorted {
@Test
public void testStreamMap() {
List<String> strList = Arrays.asList("3", "1", "2","4");
Stream<Integer> map4 = strList.stream().map(Integer::parseInt);
map4.forEach(StreamSorted :: println);
System.out.println("\n---------------------------");
// sorted() 自然排序,需要实现Comparable或者Comparator的对象
IntStream mapToInt = strList.stream().mapToInt(Integer::parseInt).sorted();
mapToInt.forEachOrdered(StreamSorted :: println);
System.out.println("\n---------------------------");
// sorted(Comparator<T> comparator) 自定义排序规则
Stream<Integer> map = strList.stream().map(Integer :: parseInt);
map.sorted((n1,n2) -> -Integer.compare(n1, n2)).forEach(StreamSorted :: println);
}
public static void println(Object obj) {
System.out.print(obj + ", ");
}
}
复制
结果:
3, 1, 2, 4,
---------------------------
1, 2, 3, 4,
---------------------------
4, 3, 2, 1,
复制
1.11.Stream终止操作
1.11.1.匹配与查找
allMatch(Predicatepredicate) -- 所有元素是否都匹配
anyMatch(Predicatepredicate) -- 元素是否有匹配的
noneMatch(Predicatepredicate) -- 是否没有此元素
findFirst() -- 第一个元素
findAny() -- 任意元素
count() -- 元素个数
max(Comparatorcomparator) -- 最大值
min(Comparatorcomparator) -- 最小值
forEach(Consumeraction) -- 内部遍历
复制
1.11.1.10.代码
package com.bobo.study.jdk.stream;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.stream.Stream;
import org.junit.Test;
public class StreamMatchAndFind {
@Test
public void testStreamMap() {
List<String> strList = Arrays.asList("3", "1", "2","4");
// 遍历元素
strList.stream().forEach(StreamMatchAndFind :: println);
System.out.println();
System.out.println("---------------------------");
// 所有元素是否都匹配
boolean allMatch = strList.stream().allMatch(s -> s.equals("2"));
System.out.println(allMatch);
System.out.println("---------------------------");
// 是否有匹配的元素
boolean anyMatch = strList.stream().anyMatch(s -> s.equalsIgnoreCase("2"));
System.out.println(anyMatch);
System.out.println("---------------------------");
// 是否没有此元素
boolean noneMatch = strList.stream().noneMatch(s -> s.equals("2"));
System.out.println(noneMatch);
System.out.println("---------------------------");
// 查找第一个元素
Optional<String> findFirst = strList.stream().findFirst();
System.out.println(findFirst);
System.out.println("---------------------------");
// 查找任意元素
Optional<String> findAny = strList.stream().findAny();
System.out.println(findAny);
System.out.println("---------------------------");
// 返回元素个数
long count = strList.stream().count();
System.out.println(count);
System.out.println("---------------------------");
// 返回元素最大值
Stream<Integer> map = strList.stream().map(Integer :: parseInt);
Optional<Integer> max = map.max(Integer :: compare);
System.out.println(max);
System.out.println("---------------------------");
// 返回元素最小值
OptionalInt min = strList.stream().mapToInt(Integer :: parseInt).min();
System.out.println(min);
}
public static void println(Object obj) {
System.out.print(obj + ", ");
}
}
复制
结果:
3, 1, 2, 4,
---------------------------
false
---------------------------
true
---------------------------
false
---------------------------
Optional[3]
---------------------------
Optional[3]
---------------------------
4
---------------------------
Optional[4]
---------------------------
OptionalInt[1]
复制
1.11.2.归约
reduce() -- 将元素结合起来,例:求所有元素的和
复制
1.11.2.2.代码
package com.bobo.study.jdk.stream;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import org.junit.Test;
public class StreamReduce {
@Test
public void testStreamMap() {
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,0);
// 遍历元素
list.stream().forEach(StreamReduce :: println);
System.out.println();
System.out.println("---------------------------");
// 元素求和,初始值为20,再增加元素所有内容之后的求和
Integer reduce = list.stream().reduce(20, Integer :: sum);
System.out.println(reduce);
// 元素求和,返回Optional类型
Optional<Integer> reduce2 = list.stream().reduce(Integer :: sum);
System.out.println(reduce2);
}
public static void println(Object obj) {
System.out.print(obj + ", ");
}
}
复制
结果:
1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
---------------------------
65
Optional[45]
复制
1.11.3.收集
collect(Collector cr) -- 将流转换为其他形式,例:list或set集合或数组
复制
1.11.3.2.代码
package com.bobo.study.jdk.stream;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.junit.Test;
public class StreamCollect {
@Test
public void testStreamMap() {
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,0);
System.out.println("---------------------------");
// 转list
List<Integer> collectList = list.stream().collect(Collectors.toList());
System.out.println(collectList);
// 转set
Set<Integer> collectSet = list.stream().collect(Collectors.toSet());
System.out.println(collectSet);
// 转数组
Integer[] array = list.stream().toArray(Integer[] :: new);
System.out.println(Arrays.toString(array));
}
}
复制
结果:
---------------------------
[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
复制
1.12.ParallelStream并行流
-底层使用Fork/Join框架实现
-无法保证元素顺序
-使用线程同步,只能保证元素正确,不能保证元素顺序
复制
1.13.解决Stream并行线程不安全问题
并行操作是线程不安全的
方案一:使用同步代码快synchronized
方案二:使用线程安全的集合
方案三:使用collect、toArray方法
复制
1.13.5.代码
package com.bobo.study.jdk.stream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Vector;
import java.util.stream.Collectors;
import org.junit.Test;
public class StreamParallel {
@Test
public void testParallel() {
List<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < 10000; i ++) {
list.add(i);
}
List<Integer> newList = new ArrayList<>();
list.parallelStream().forEach(newList :: add);
System.out.println("list1.size = " + newList.size());
// 方案一: 使用synchronized同步代码快
List<Integer> list1 = new ArrayList<>();
list.parallelStream().forEach(n -> {
synchronized (list1) {
list1.add(n);
}
});
System.out.println("list1.size = " + list1.size());
// 方案二: 使用线程安全的集合
Vector<Integer> v = new Vector<Integer>();
list.parallelStream().forEach(v :: add);
System.out.println("v.size = " + v.size());
List<Integer> synchronizedList = Collections.synchronizedList(new ArrayList<Integer>());
list.parallelStream().forEach(synchronizedList :: add);
System.out.println("synchronizedList.size = " + synchronizedList.size());
// 方案三: 使用collect/toarray操作
List<Integer> collect = list.parallelStream().collect(Collectors.toList());
System.out.println("collect.size = " + collect.size());
Integer[] array = list.parallelStream().toArray(Integer[] :: new);
System.out.println("array.length = " + array.length);
}
@Test
public void testParallel1() {
List<Integer> list = new ArrayList<Integer>();
for(int i = 0; i < 10000; i ++) {
list.add(i);
}
Optional<Integer> reduce = list.stream().reduce(Integer :: sum);
System.out.println(reduce.get());
Optional<Integer> reduce2 = list.parallelStream().reduce(Integer :: sum);
System.out.println(reduce2.get());
}
}
复制
结果:
49995000
49995000
list1.size = 5483
list1.size = 10000
v.size = 10000
synchronizedList.size = 10000
collect.size = 10000
array.length = 10000
复制
2.Optional类
用途:解决空指针异常问题
复制
3.Fork/Join框架
JDK1.7推出的一套新的线程框架
使用分治法、工作窃取算法
复制
文章转载自博博JAVA学习之路,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。
评论
相关阅读
2025年4月中国数据库流行度排行榜:OB高分复登顶,崖山稳驭撼十强
墨天轮编辑部
2235次阅读
2025-04-09 15:33:27
数据库国产化替代深化:DBA的机遇与挑战
代晓磊
1040次阅读
2025-04-27 16:53:22
2025年3月国产数据库大事记
墨天轮编辑部
957次阅读
2025-04-03 15:21:16
2025年3月国产数据库中标情况一览:TDSQL大单622万、GaussDB大单581万……
通讯员
656次阅读
2025-04-10 15:35:48
数据库,没有关税却有壁垒
多明戈教你玩狼人杀
522次阅读
2025-04-11 09:38:42
国产数据库需要扩大场景覆盖面才能在竞争中更有优势
白鳝的洞穴
506次阅读
2025-04-14 09:40:20
最近我为什么不写评论国产数据库的文章了
白鳝的洞穴
461次阅读
2025-04-07 09:44:54
【活动】分享你的压箱底干货文档,三篇解锁进阶奖励!
墨天轮编辑部
415次阅读
2025-04-17 17:02:24
天津市政府数据库框采结果公布,7家数据库产品入选!
通讯员
392次阅读
2025-04-10 12:32:35
2025年4月国产数据库中标情况一览:4个千万元级项目,GaussDB与OceanBase大放异彩!
通讯员
371次阅读
2025-04-30 15:24:06