开发中的代码
在开发中的代码是不是很常见这样的代码:
这样的?
for 循环取元素取值
- List<User> szUserList = new ArrayList<>();
- for (User user : userList) {
- if (user.getAddress().equals("shenzhen")) {
- szUserList.add(user);
- }
- }
或者这样的?
for 循环去重
- for (int i = 0; i <list.size() - 1; i++) {
- for (int j = list.size() - 1; j> i; j--) {
- if (list.get(j).equals(list.get(i))) {
- list.remove(j);
- }
- }
- }
- Set set = new HashSet();
- List<String> newList = new ArrayList();
- for (Iterator iter = list.iterator(); iter.hasNext();) {
- Object element = iter.next();
- if (set.add(element))
- newList.add(element);
- }
- list.clear();
- list.addAll(newList);
- }
"普通"CV 族 VS "高级"CV 族
对于 "普通" 的 CV 族来说, 这样就差不多了, 功能实现了, 又可以收拾包袱准备下班了. 完美!!!
但对于我们 "高级"CV 族来, 这不够, 这远远的不够, 我们需要保持一颗折腾的心, 这样的代码彰显不出我们这段位的价值(青铜王者).
所以我们需要一种方式去提升我们代码的维度, 让我们的代码变得更 "高级", 使代码更加简洁并且更加语义化 .
由于 "高级"CV" 族保持这样的心态:
平凡的人, 平凡的生活, 平凡的工作
该有一颗不平凡的心
找出一种方式可以很好的升级这种代码问题:------Java 8 新提供给开发者的一组操作集合的 API----Stream 流
我们如何看待 Stream 流
那 Stream 流是如何来提升代码维度?
首先我们来看看 Stream 流处理 for 循环取元素取值:
- List<User> szUserList=userList.stream()
- .filter(user-> user.getAddress().equals("shenzhen"))
- .collect(Collectors.toList());
其实, stream 流会把需要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序, 聚合等. Stream 流可以极大的提高开发效率, 也可以使用它写出更加简洁明了的代码.
那么 Stream 流可以分几种:
顺序流 : 按照顺序对集合中的元素进行处理
并行流 : 使用多线程同时对集合中多个元素进行处理
在使用并行流的时候就要注意线程安全的问题
元素流在管道中经过中间操作 (intermediate operation) 的处理, 最后由终端操作 (terminal operation) 得到前面处理的结果.
中间操作(intermediate operation): 中间操作会产生另一个流 ,( 流是一种惰性操作, 所有对源数据的计算只在终止操作被初始化的时候才会执行), 而且中间操作还分无状态操作和有状态操作两种 .
无状态操作 : 在处理流中的元素时, 会对当前的元素进行单独处理. (例如: 过滤操作).
有状态操作 : 某个元素的处理可能依赖于其他元素.( 例如: 查找最小值, 最大值, 和排序 ).
终止操作 (terminal operation): 消费 Stream 流, 并且会产生一个结果 . 如果一个 Stream 流被消费过了, 那它就不能被重用的.
Stream 流一般的执行过程可概括为:
源(Stream)
零个或多个中间操作(intermediate operation)
终止操作 (到这一步才会执行整个 stream pipeline 计算) (terminal operation)
源的创建方式
使用 Collection 下的 stream() 和 parallelStream() 方法
使用 Stream 中的静态方法: of()
- List<String> createStream = new ArrayList<String>();
- // 顺序流
- Stream<String> stream = createStream.stream();
- // 并行流
- Stream<String> parallelStream = createStream.parallelStream();
- // of()方法创建
- Stream<String> stringStream = Stream.of(
- createStream.toArray(new String[createStream.size()]));
Intermediate 操作
中间操作包括 map (mapToInt, flatMap 等), filter, distinct, sorted, peek, limit, skip, parallel, sequential, unordered 等.
常用操作解析:
filter : 筛选符合条件的元素后重新生成一个新的流.
map : 接收一个函数作为参数, 该函数会被应用到每个元素上, 并将其映射成一个新的元素.
flatMap: 接收一个函数作为参数, 将流中的每个值都换成另一个流, 然后把所有流连接成一个流.
distinct: 去重操作, 将 Stream 流中的元素去重后, 返回一个新的流.
sorted: 产生一个自然顺序排序或者指定排序条件的新流.
skip: 跳过 n 元素, 配合 limit(n)可实现分页
peek: 生成一个包含原 Stream 的所有元素的新 Stream, 同时会提供一个消费函数(Consumer 实例), 新 Stream 每个元素被消费的时候都会执行给定的消费函数(一般用于重赋值那些);
limit: 对一个 Stream 进行截断操作, 获取其前 N 个元素, 如果原 Stream 中包含的元素个数小于 N, 那就获取其所有的元素;
Terminal 操作
终止操作包括: forEach, forEachOrdered, toArray, reduce, collect, min, max, count, anyMatch, allMatch, noneMatch, findFirst, findAny, iterator 等
常用操作解析:
forEach: 遍历了流中的元素.(终端操作)
collect: 接收一个 Collector 实例, 将流中元素收集成另外一个数据结构
max: 获得流中最大值, 比较器可以由自己定义.(终端操作)
min: 获得流中最小值, 比较器可以由自己定义.(终端操作)
anyMatch : 判断 Stream 流中是否有任何符合要求的元素, 如果有则返回 ture, 没有返回 false.(终端操作)
该如何操作呢?
Stream 操作都可以按照一般步骤进行.
比如上面的去重操作:
distinct 操作:
- list=list.stream()
- .distinct()
- .collect(Collectors.toList());
NOTE:distinct()使用 hashCode()和 eqauls()方法来获取不同的元素. 因此, 需要去重的类必须实现 hashCode()和 equals()方法
结合 filter,distinct,peek,skip,limit,collect 例子:
- List arrList = userList.stream().filter(user -> user.getName().equals("ccww"))// 过滤
- .distinct()// 去重
- .peek(user -> user.setAddress("shenzhen"))// 重新赋值
- .skip(2)// 跳读
- .limit(2)// 读取 2 个元素
- .collect(Collectors.toList());
map 的例子:
- List arrList1=userList.stream()
- .map(user->{
- //todo 处理函数
- user.setAddress(cityService.getCity());
- }).collect(Collectors.toList());
- }
来源: https://www.cnblogs.com/Ccwwlx/p/12021066.html