怎么break java8 stream的foreach

简介

我们通常需要在java stream中遍历处理里面的数据,其中foreach是最最常用的方法。

但是有时候我们并不想处理完所有的数据,或者有时候Stream可能非常的长,或者根本就是无限的。

一种方法是先filter出我们需要处理的数据,然后再foreach遍历。

那么我们如何直接break这个stream呢?今天本文重点讲解一下这个问题。

使用Spliterator

上篇文章我们在讲Spliterator的时候提到了,在tryAdvance方法中,如果返回false,则Spliterator将会停止处理后续的元素。

通过这个思路,我们可以创建自定义Spliterator。

假如我们有这样一个stream:

Stream<Integer> ints = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

我们想定义一个操作,当x > 5的时候就停止。

我们定义一个通用的Spliterator:

public class CustomSpliterator<T> extends Spliterators.AbstractSpliterator<T>  {

    private Spliterator<T> splitr;
private Predicate<T> predicate;
private volatile boolean isMatched = true; public CustomSpliterator(Spliterator<T> splitr, Predicate<T> predicate) {
super(splitr.estimateSize(), 0);
this.splitr = splitr;
this.predicate = predicate;
} @Override
public synchronized boolean tryAdvance(Consumer<? super T> consumer) {
boolean hadNext = splitr.tryAdvance(elem -> {
if (predicate.test(elem) && isMatched) {
consumer.accept(elem);
} else {
isMatched = false;
}
});
return hadNext && isMatched;
}
}

在上面的类中,predicate是我们将要传入的判断条件,我们重写了tryAdvance,通过将predicate.test(elem)加入判断条件,从而当条件不满足的时候返回false.

看下怎么使用:

@Slf4j
public class CustomSpliteratorUsage { public static <T> Stream<T> takeWhile(Stream<T> stream, Predicate<T> predicate) {
CustomSpliterator<T> customSpliterator = new CustomSpliterator<>(stream.spliterator(), predicate);
return StreamSupport.stream(customSpliterator, false);
} public static void main(String[] args) {
Stream<Integer> ints = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<Integer> result =
takeWhile(ints, x -> x < 5 )
.collect(Collectors.toList());
log.info(result.toString());
}
}

我们定义了一个takeWhile方法,接收Stream和predicate条件。

只有当predicate条件满足的时候才会继续,我们看下输出的结果:

[main] INFO com.flydean.CustomSpliteratorUsage - [1, 2, 3, 4]

自定义forEach方法

除了使用Spliterator,我们还可以自定义forEach方法来使用自己的遍历逻辑:

public class CustomForEach {

    public static class Breaker {
private volatile boolean shouldBreak = false; public void stop() {
shouldBreak = true;
} boolean get() {
return shouldBreak;
}
} public static <T> void forEach(Stream<T> stream, BiConsumer<T, Breaker> consumer) {
Spliterator<T> spliterator = stream.spliterator();
boolean hadNext = true;
Breaker breaker = new Breaker(); while (hadNext && !breaker.get()) {
hadNext = spliterator.tryAdvance(elem -> {
consumer.accept(elem, breaker);
});
}
}
}

上面的例子中,我们在forEach中引入了一个外部变量,通过判断这个外部变量来决定是否进入spliterator.tryAdvance方法。

看下怎么使用:

@Slf4j
public class CustomForEachUsage { public static void main(String[] args) {
Stream<Integer> ints = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<Integer> result = new ArrayList<>();
CustomForEach.forEach(ints, (elem, breaker) -> {
if (elem >= 5 ) {
breaker.stop();
} else {
result.add(elem);
}
});
log.info(result.toString());
}
}

上面我们用新的forEach方法,并通过判断条件来重置判断flag,从而达到break stream的目的。

总结

本文通过两个具体的例子讲解了如何break一个stream,希望大家能够喜欢。

本文的例子https://github.com/ddean2009/learn-java-streams/tree/master/break-stream-foreach

欢迎关注我的公众号:程序那些事,更多精彩等着您!

更多内容请访问 www.flydean.com

怎么break java8 stream的foreach的更多相关文章

  1. java8 Stream的实现原理 (从零开始实现一个stream流)

    1.Stream 流的介绍 1.1 java8 stream介绍 java8新增了stream流的特性,能够让用户以函数式的方式.更为简单的操纵集合等数据结构,并实现了用户无感知的并行计算. 1.2  ...

  2. 如何用Java8 Stream API找到心仪的女朋友

    传统的的Java 集合操作是有些啰嗦的,当我们需要对结合元素进行过滤,排序等操作的时候,通常需要写好几行代码以及定义临时变量. 而Java8 Stream API 可以极大简化这一操作,代码行数少,且 ...

  3. java List递归排序,传统方式和java8 Stream优化递归,无序的列表按照父级关系进行排序(两种排序类型)

    当有一个List列表是无序的,List中的数据有parentid进行关联,通过java排序成两种排序类型: 所用的测试列表最顶级无parentid,若为特殊值,修改下判断方法即可. 第一种排序:按照树 ...

  4. 简洁又快速地处理集合——Java8 Stream(下)

    上一篇文章我讲解 Stream 流的基本原理,以及它与集合的区别关系,讲了那么多抽象的,本篇文章我们开始实战,讲解流的各个方法以及各种操作 没有看过上篇文章的可以先点击进去学习一下 简洁又快速地处理集 ...

  5. 简洁又快速地处理集合——Java8 Stream(上)

    Java 8 发布至今也已经好几年过去,如今 Java 也已经向 11 迈去,但是 Java 8 作出的改变可以说是革命性的,影响足够深远,学习 Java 8 应该是 Java 开发者的必修课. 今天 ...

  6. java8 Stream使用总结

    [前言] java8新特性 java8 函数接口 java8 Optional使用总结 Java 8 时间日期使用 java8 lambda表达式 1.流的介绍 Java8 中的 Stream 是对集 ...

  7. Java8 Stream新特性详解及实战

    Java8 Stream新特性详解及实战 背景介绍 在阅读Spring Boot源代码时,发现Java 8的新特性已经被广泛使用,如果再不学习Java8的新特性并灵活应用,你可能真的要out了.为此, ...

  8. 【转】Java8 Stream 流详解

      当我第一次阅读 Java8 中的 Stream API 时,说实话,我非常困惑,因为它的名字听起来与 Java I0 框架中的 InputStream 和 OutputStream 非常类似.但是 ...

  9. 何用Java8 Stream API进行数据抽取与收集

    上一篇中我们通过一个实例看到了Java8 Stream API 相较于传统的的Java 集合操作的简洁与优势,本篇我们依然借助于一个实际的例子来看看Java8 Stream API 如何抽取及收集数据 ...

随机推荐

  1. Docker学习之搭建nginx环境

    前言 很久没写随笔了,今天我们来学习一下如何在docker搭建nginx环境吧! 一:下载镜像,使用docker pull拉取最新的nginx镜像 命令:docker pull nginx 查看镜像: ...

  2. ASP.NET Core中的Controller

    ASP.NET CORE出现之前我们实现的Controller,MVC都继承自Controller基类,WebApi的话继承自ApiController.现在ASP.NET CORE把MVC跟WebA ...

  3. 打开scratch后蓝屏怎么办

    1.试试开机,百出完电脑品牌后,按F8,安全模式,光标选定:最后一次正确配置,回车,回车,按下去,[度关键一步]2.再不行,问进安全模式,回车,到桌面后,用杀毒软件腾讯电脑管家,全盘杀毒,“隔离区”的 ...

  4. php--理解PHP的依赖注入和laravel的服务容器

    写在前面 为了了解laravel的服务容器在网上搜了许多文章,其中大多数都有其侧重点,没有很系统的一套东西以供参考,看完之后仍觉似乎少了一根把他们串起来的绳子,近期有幸拜读了陈昊的<Larave ...

  5. django自定义实现登录验证-更新版

    django自定义实现登录验证 django内置的登录验证必须让开发者使用django内置的User模块,这会让开发者再某些方面被限制住 下面的模块是我自己自定义实现的django验证,使用方式和dj ...

  6. sparkRdd driver和excuter

    //1 从内存中创建makeRdd,底层实现就是parallelize val rdd=sc.makeRDD(Array(1,2,"df",55)) //2 从中创建paralle ...

  7. python3(三)enc

    # ASCII编码和Unicode编码的区别:ASCII编码是1个字节,而Unicode编码通常是2个字节. # Unicode把所有语言都统一到一套编码里,这样就不会再有乱码问题了. # 新的问题又 ...

  8. nginx内置高可用配置与第三方高可用模块nginx_ustream_check_mudule配置

    1. nginx 第三方高可用模块 IP 备注 10.0.0.63 proxy 10.0.0.64 web1 10.0.0.65 web2 这里会讲解一些nignx常用高可用方案,以及引入第三方高可用 ...

  9. 实时OLAP分析利器Druid介绍

    文章目录 前言 Druid介绍 主要特性 基础概念 数据格式 数据摄入 数据存储 数据查询 查询类型 架构 运维 OLAP方案对比 使用场景 使用建议 参考 近期主题 前言 项目早期.数据(报表分析) ...

  10. shell命令(一)

    什么是shell? Shell是一个应用程序,它连接了用户和Linux内核,让用户能够更加高效.安全.低成本地使用Linux内核,这就是Shell的本质. shell与Linux系统关系图 shell ...