套别人代码做网站,品牌设计作品,org 结尾的网站注册要什么手续,名聚优品一家只做正品的网站目录
前言
Stream流 是什么#xff1f;
为什么要用Steam流
常见stream流使用案例
映射 map() 集合 collect()
单字段映射
多字段映射
映射为其他的对象
映射为 Map
去重 distinct()
过滤 filter()
Stream流的其他方法
使用Stream流的弊端 前言 当你某天看…目录
前言
Stream流 是什么
为什么要用Steam流
常见stream流使用案例
映射 map() 集合 collect()
单字段映射
多字段映射
映射为其他的对象
映射为 Map
去重 distinct()
过滤 filter()
Stream流的其他方法
使用Stream流的弊端 前言 当你某天看到舍友的代码不再写for循环时你的反应 你还在 new Collection() 写着for循环的时候舍友已经开始偷偷卷你更改代码风格了
本文将带着大家简单理解 Stream 流并通过部分案例描述 Stream 流 的实用方法 Stream流 是什么 Stream 流是 Java 8 引入的一个强大工具它提供了一种全新的方式来处理集合和数组等数据源使得数据处理变得更加简单、高效和易于理解。 通俗的理解起来就是提供了一种更加便利的遍历处理方式。 如果你要问我 Stream流用起来什么感觉
那我只能说这种感觉就像飞翔在~~
噢不对感觉就是 为什么要用Steam流 Stream 流的主要用途是提供一种高效且表达力高的方式来处理集合和数组等数据源。通过使用 Stream 流可以避免显式的迭代器和循环使得代码更加简洁、易读。Stream 流支持复杂的查询/过滤、映射/转换、归约/汇总等操作能够极大地简化数据处理的复杂度。
总结起来还是简洁、易读
当然这也让你的代码看起来更高级那么一点点~~ 如下案例拿到所有的评论的id 集合的两种方法。
第一种-for循环便利获取 ListComment list commentMapper.selectList(wrapper);ListInteger commentId new ArrayList();for(Comment c : list){commentId.add(c.getId());}
第二种-Stream流获取 ListComment list commentMapper.selectList(wrapper);ListInteger commentId list.stream().map(Comment::getId).collect(Collectors.toList());
两种方法的区别显而易见 下面介绍stream流比较实用的方法 常见stream流使用案例 在这里我们准备一个简单的对象来进行案例测试只约定两个字段。
Data
AllArgsConstructor
public class StreamTestObject {Integer id1;Integer id2;}映射 map() 集合 collect() map() 方法是最常用的方法之一它可以将流中的每个元素转换成另一种形式返回转换后的 Stream。
如前文的例子所示 单字段映射 ListStreamTestObject streamTestObjects Arrays.asList(new StreamTestObject(1, 2),new StreamTestObject(3, 4),new StreamTestObject(5, 6));// 便于观察变化StreamStreamTestObject stream streamTestObjects.stream();StreamInteger id1Stream streamTestObjects.stream().map(StreamTestObject::getId1);
看代码我们可以看到map方法将对象的stream流映射为了其中 id1 这个字段的stream流 拿到这个字段的流后可以做些什么呢
最常用的方法之一就是与 集合 collect() 搭配起来使用。
那么 collect() 方法能做写什么呢
用途将流中的元素累积成一个汇总结果我们可以按照自己的需求将结果汇总为一个 List、Set、Map 等
如下代码所示 ListStreamTestObject streamTestObjects Arrays.asList(new StreamTestObject(1, 2),new StreamTestObject(3, 4),new StreamTestObject(5, 6));StreamStreamTestObject stream streamTestObjects.stream();StreamInteger id1Stream streamTestObjects.stream().map(StreamTestObject::getId1);ListInteger collectList id1Stream.collect(Collectors.toList());
// SetInteger collectSet id1Stream.collect(Collectors.toSet());// 连起来使用一行代码可以写成这样collectList streamTestObjects.stream().map(StreamTestObject::getId1).collect(Collectors.toList());
// collectSet streamTestObjects.stream().map(StreamTestObject::getId1).collect(Collectors.toSet());System.out.println(collectList: collectList);
// 输出结果 collectList:[1, 3, 5]
结果能够把 id1 成功收集起来代码的易读性也体现在其中。我们一眼就能看出这行代码映射了id1 这个字段为一个 List 或 Set。 多字段映射 那如果我们想要对象集合中的 id1 和 id2 都汇总到一个 ListInteger 集合里应该如何操作呢。
这里我们可以使用一个 flatMap() 方法
用途将流中的每个元素都转换成另一个流然后将所有流连接成一个流。
直接上代码 ListStreamTestObject streamTestObjects Arrays.asList(new StreamTestObject(1, 2),new StreamTestObject(3, 4),new StreamTestObject(5, 6));ListInteger collectList streamTestObjects.stream().flatMap(object -Stream.of(object.getId1(), object.getId2())).collect(Collectors.toList());System.out.println(collectList: collectList);//输出结果 collectList:[1, 2, 3, 4, 5, 6]
在这个例子中Stream.of(obj.getId1(), obj.getId2())为每个对象生成了一个包含两个ID的流它在map中 形成了一个临时的流
然后flatMap将这些流“展平”成了一个包含所有ID的流最后我们通过collect(Collectors.toList())将这个流收集到了一个列表中。 映射为其他的对象 有的时候的业务需求需要我们把一个对象集合转化为另外一个集合对象如果是单纯的 字段copy我们可以使用 BeanUtils 或者 MapStruct 等方法实现。
如果转化的过程中设计业务逻辑那么就需要 Stream流出手了。
这里需要设计到一个显示 return 的写法上代码先准备一个另外的对象只包含一个id字段
Data
NoArgsConstructor
AllArgsConstructor
public class StreamOtherObject {Integer id;}然后 我们将上述测试对象的id1转化为这里的id字段。 ListStreamTestObject streamTestObjects Arrays.asList(new StreamTestObject(1, 2),new StreamTestObject(3, 4),new StreamTestObject(4, 5));ListStreamOtherObject collectList streamTestObjects.stream().map(streamTestObject - {StreamOtherObject object new StreamOtherObject();object.setId(streamTestObject.getId1());return object;}).collect(Collectors.toList());System.out.println(collectList: collectList);//输出结果 collectList:[StreamOtherObject(id1), StreamOtherObject(id3), StreamOtherObject(id4)]
注意看返回的集合对象已经是我在表达式里return 的 StreamOtherObject了。
也就是 return 的内容就是集合的具体对象 映射为 Map Stream流还能把集合映射为一个Map这里我们测试用例为将映射结果设置为 key 为 id1 value 为对象本身 ListStreamTestObject streamTestObjects Arrays.asList(new StreamTestObject(1, 2),new StreamTestObject(3, 4));MapInteger, StreamTestObject map streamTestObjects.stream().collect(Collectors.toMap(StreamTestObject::getId1,Function.identity(),(existsOne, replaceOne) - replaceOne));System.out.println(collectMap: map);//输出结果 collectMap:{1StreamTestObject(id11, id22), 3StreamTestObject(id13, id24)}
可以看到toMap() 方法中传递了3个参数前两个分别为 key value
第三个参数传了一个表达式这里的逻辑表示如果发生冲突就保留 Map中新的那个对象而不是保留它。同时第三个参数也处理了冲突如果你没有对于 key 相同的情况做处理也就是 key 冲突了方法将抛出一个IllegalStateException。
所以你需要做对应的处理如try catch 下来或者进行冲突处理即传递第三个参数。 去重 distinct() 对于拿到的流结果我们有的时候有去重的需求当然我们可以转为 toSet() 进行去重
stream流同样提供了一个方法进行去重就是 distinct() 方法
用途去除流中的重复元素返回包含不同元素的 Stream。
这里比较好理解我们直接看案例 ListStreamTestObject streamTestObjects Arrays.asList(new StreamTestObject(1, 2),new StreamTestObject(3, 4),new StreamTestObject(4, 5));ListInteger collectList streamTestObjects.stream().flatMap(object -Stream.of(object.getId1(), object.getId2())).distinct().collect(Collectors.toList());System.out.println(collectList: collectList);//输出结果 collectList:[1, 2, 3, 4, 5] 过滤 filter() 用途根据提供的条件过滤元素返回满足条件的 Stream。
过滤的方法也是比较常用的方法也是比较多业务中有这个需求的。这里介绍两种方法
在拿到一个流后也许不是所有的元素我们都需要。我们需要保存满足特定条件的元素这时候就可以使用 filter方法来实现。
这里的案例表示筛选除 id1 为 1id2 为 4 的数据代码如下 ListStreamTestObject streamTestObjects Arrays.asList(new StreamTestObject(1, 2),new StreamTestObject(3, 4),new StreamTestObject(4, 5));ListStreamTestObject collectList streamTestObjects.stream().filter(object - object.getId1().equals(1) || object.getId2().equals(4)).collect(Collectors.toList());System.out.println(collectList: collectList);//输出结果 collectList:[StreamTestObject(id11, id22), StreamTestObject(id13, id24)]
如果你的过滤逻辑比较复杂可以使用显示 return 写法来过滤 ListStreamTestObject streamTestObjects Arrays.asList(new StreamTestObject(1, 2),new StreamTestObject(3, 4),new StreamTestObject(4, 5));ListStreamTestObject collectList streamTestObjects.stream().filter(object - {int id1 1;int id2 4;return object.getId1().equals(id1) || object.getId2().equals(id2);}).collect(Collectors.toList());System.out.println(collectList: collectList);//输出结果 collectList:[StreamTestObject(id11, id22), StreamTestObject(id13, id24)]
在代码块里可以编辑自己自定义的过滤逻辑
这里要注意返回值是一个布尔值如果为 true则保留这项数据不满足则进行一项数据处理。 Stream流的其他方法 前文是 Stream 流比较常见的方法案例它还提供了很多其他的接口来实现对应的场景如
sorted() 用途对流中的元素进行自然排序需实现 Comparable 接口返回排序后的 Stream。示例对用户列表按年龄进行排序。limit(long maxSize) 用途截断流使其包含不超过给定数量的元素返回截断后的 Stream。示例只取用户列表中的前三个用户。skip(long n) 用途跳过流中的前 n 个元素返回剩下的元素的 Stream。示例跳过用户列表中的前两个用户取后面的用户。forEach(Consumer? super T action) 用途这是大家比较熟悉的操作在代码编写中可以省去 .Stream() 的写法。意为对流中的每个元素执行提供的操作这是一个终结操作。示例遍历用户列表并打印每个用户的名字。 使用Stream流的弊端 学习了Stream流 的优点之后也需要知道随之产生的弊端有短些这里我列举几个主要的内容
性能问题
多次遍历有时为了完成一个操作可能需要多次遍历数据源。例如先过滤filter再映射map最后收集collect这会导致数据被多次遍历。并行流开销虽然并行流可以加速处理过程但它们引入了额外的线程管理开销并且不总是能带来性能提升尤其是在数据源较小或操作相对简单时。懒加载导致的意外行为Stream操作是懒加载的这意味着它们直到需要结果时才会执行。这可能导致在调试时难以追踪问题的源头或者在某些情况下当流操作依赖于外部状态时可能导致不可预测的行为。 可读性和维护性
前面不是可读性强吗怎么有问题了如果嵌套太多层的操作方法也会使得表达式的可读性降低
复杂逻辑难以追踪对于包含多个复杂操作如多重过滤、映射、归约等的Stream链其逻辑可能变得难以理解和追踪。调试困难由于Stream操作的延迟执行和中间操作的无状态性调试Stream代码可能会比传统循环更加困难。 错误处理
异常处理复杂在Stream操作中处理异常如尝试映射一个可能抛出异常的函数比在传统循环中更复杂。Stream API没有直接支持异常处理机制通常需要通过try-catch块或自定义函数来处理。 内存消耗
中间结果存储Stream API在执行过程中可能会创建中间结果的临时集合尤其是在进行复杂操作时这可能会增加内存消耗。 到这里同学们可以多实操一下这些方法来巩固知识。文章如有遗漏或建议更改的部分欢迎佬们指出。