如何映射 Java 流中的 RuntimeExceptions 以从无效流元素中“恢复”

2023-12-14

想象一下,我正在构建一个库,它将接收整数流,而库代码所需要做的就是返回一个字符串流,其中包含数字的字符串表示形式。

public Stream<String> convertToString(Stream<Integer> input) {
  return input.map(n -> String.valueOf(n));
}

但是,想象一下有人决定使用以下代码调用我的函数:

Stream<Integer> input = Stream.of(1,2,3)
  .map(n -> {
    if (n %3 ) { throw new RuntimeException("3s are not welcome here!"); }
    else { return n; }
  }

Stream<String> output = convertToString(input);

由于我希望我的 API 合约能够处理这种情况并仍然返回字符串流,因此我想知道如何更改我的代码,以便它检测到流中存在异常并从异常中“恢复”通过将其映射到一个特殊的"NaN" value.

最后,我希望我的输出流是"1","2","NaN"

Notes:

  • 我不希望我的 API 必须为输入定义一个特殊的包装器。
  • 由于依赖关系的影响,我不想依赖第三方库。
  • 我不知道流有多大或者生成的速率是多少,所以我不能对所有值使用任何类型的缓存/预加载。

Java 8 Streams 可以实现这一点吗?

有了迭代器,我想我可以做到:

public class SafeIntegerToStringIterator implements Iterator<String> {
  Iterator<Integer> innerIterator;
  ...
  public String next() throws NoSuchElementException {
    try { return String.valueOf(this.innerIterator.next()); }
    catch (RuntimeException e) { return "NaN"; }
  }

}
...
public Iterator<String> convertToString(Iterator<Integer> input) {
  return new SafeIntegerToStringIterator(input);
}

Thanks


Note:请参阅本文末尾的编辑,它修复了我原始答案中的错误。无论如何,我都会留下原来的答案,因为它对于很多情况仍然有用,而且我认为它有助于解决OP的问题,至少有一些限制。


你的方法与Iterator朝着正确的方向前进。该解决方案可能起草如下:将流转换为迭代器,像您已经完成的那样包装迭代器,然后从包装迭代器创建一个流,但您应该使用Spliterator反而。这是代码:

private static <T> Stream<T> asNonThrowingStream(
        Stream<T> stream,
        Supplier<? extends T> valueOnException) {

    // Get spliterator from original stream
    Spliterator<T> spliterator = stream.spliterator();

    // Return new stream from wrapper spliterator
    return StreamSupport.stream(

        // Extending AbstractSpliterator is enough for our purpose
        new Spliterators.AbstractSpliterator<T>(
                spliterator.estimateSize(),
                spliterator.characteristics()) {

            // We only need to implement tryAdvance
            @Override
            public boolean tryAdvance(Consumer<? super T> action) {
                try {
                    return spliterator.tryAdvance(action);
                } catch (RuntimeException e) {
                    action.accept(valueOnException.get());
                    return true;
                }
            }
        }, stream.isParallel());
}

我们正在延长AbstractSpliterator包装原始流返回的 spliterator。我们只需要实现tryAdvance方法,该方法要么委托给原始 spliterator 的tryAdvance方法或捕获RuntimeException并使用提供的调用该操作valueOnException value.

Spliterator的合约指定了返回值tryAdvance必须是true如果该动作被消耗,那么如果RuntimeException被捕获,这意味着原始分裂者已将其从自己的内部抛出tryAdvance方法。因此,我们返回true在这种情况下,意味着该元素无论如何都会被消耗。

通过将这些值作为参数传递给构造函数来保留原始 spliterator 的估计大小和特征AbstractSpliterator.

最后,我们通过新的 spliterator 创建一个新流StreamSupport.stream方法。如果原始流也是并行的,则新流也是并行的。

下面介绍一下上述方法的使用方法:

public Stream<String> convertToString(Stream<Integer> input) {
    return asNonThrowingStream(input.map(String::valueOf), () -> "NaN");
}

Edit

As per 霍尔格的评论 below, 用户 holi-java善意地提供了一个解决方案,避免了 Holger 指出的陷阱。

这是代码:

<T> Stream<T> exceptionally(Stream<T> source, BiConsumer<Exception, Consumer<? super T>> handler) {
    class ExceptionallySpliterator extends AbstractSpliterator<T>
            implements Consumer<T> {

        private Spliterator<T> source;
        private T value;
        private long fence;

        ExceptionallySpliterator(Spliterator<T> source) {
            super(source.estimateSize(), source.characteristics());
            this.fence = source.getExactSizeIfKnown();
            this.source = source;
        }

        @Override
        public Spliterator<T> trySplit() {
            Spliterator<T> it = source.trySplit();
            return it == null ? null : new ExceptionallySpliterator(it);
        }

        @Override
        public boolean tryAdvance(Consumer<? super T> action) {
            return fence != 0 && consuming(action);
        }

        private boolean consuming(Consumer<? super T> action) {
            Boolean state = tryConsuming(action);
            if (state == null) {
                return true;
            }
            if (state) {
                action.accept(value);
                value = null;
                return true;
            }
            return false;
        }


        private Boolean tryConsuming(Consumer<? super T> action) {
            fence--;
            try {
                return source.tryAdvance(this);
            } catch (Exception ex) {
                handler.accept(ex, action);
                return null;
            }
        }

        @Override
        public void accept(T value) {
            this.value = value;
        }
    }

    return stream(new ExceptionallySpliterator(source.spliterator()), source.isParallel()).onClose(source::close);
}

请参考进行测试如果您想进一步了解此解决方案。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何映射 Java 流中的 RuntimeExceptions 以从无效流元素中“恢复” 的相关文章

  • Java 弱哈希映射 - 需要根据值的弱点而不是键来删除条目

    所以JavaWeakHashMap让我们创建一个映射 如果其键变弱 则删除该映射的条目 但是我怎样才能创建一个Map 当它的条目被删除时values地图上变弱了 我想使用映射的原因是作为全局哈希表 它根据对象的 ID 跟踪对象 ID gt
  • 如何用Java创建图像

    比如说在我的程序中 我有这个paint 方法 我的愿望是创建所绘制的矩形的图像 使用 for 循环 我尝试了下面的方法 它确实给了我那些矩形 蓝色 但背景是全黑的 当我运行程序而不创建图像 仅在 JFrame 上绘制矩形时 背景为白色 我怎
  • 无法从 TemporalAccessor 获取 OffsetDateTime

    当我这样做时 String datum 20130419233512 DateTimeFormatter formatter DateTimeFormatter ofPattern yyyyMMddHHmmss withZone ZoneI
  • 包含小时、分钟和秒的周期[关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我需要一个代表年 月 周 日 小时 分钟 秒的间隔数据类型 前三年 年 月 日 可以用Period最后
  • Selenium - 保存网站,包括所有图像、css、dom

    我想使用 firefox 或 chrome 访问带有 selenium 的页面 当页面加载时 我想从页面下载所有图像 css dom 我想存储每张图像 就像我在其中找到它们一样 chrome gt Tools gt Development
  • 黄瓜与 Micronaut

    我正在尝试将 Cucumber 与 Micronaut 一起使用 但当我尝试将其与 Cucumber 一起使用时 MicronautTest 注释根本不起作用 未注入 theApple 请参阅下面的代码 如果我在没有黄瓜的情况下运行它就可以
  • 如何在 Java 中安装附加包?

    我对 Java 很陌生 我想使用名为的包中的一些功能daj 教程代码有以下几行 import daj import java util import java lang Math import Msg 但第一行和第四行会产生红色下划线 导致
  • 将二进制数据的 byte[] 转换为 String

    我有二进制格式的数据 hex 80 3b c8 87 0a 89 我需要将其转换为字符串 以便通过 Jackcess 将二进制数据保存在 MS Access 数据库中 我知道 我不打算在 Java 中使用 String 来存储二进制数据 但
  • 为什么 Java 中的 hashCode() 可以对不同对象返回相同的值?

    引用我正在读的书中的一段话首先Java http www amazon co uk Head First Java Kathy Sierra dp 0596009208 关键是 哈希码可以相同 但不一定保证对象相等 因为使用的 哈希算法 h
  • 如何将 currentTimeMillis 转换为可读的日期格式? [复制]

    这个问题在这里已经有答案了 我想用currentTimeMillis两次 这样我就可以计算持续时间 但我也想以用户可读的格式显示时间和日期 我遇到了麻烦currentTimeMillis有利于计算 但我看不到内置函数可以转换为合适的时间或时
  • 如何在 Ivy 中使用不同的分类器下载多个 Maven 依赖项?

    我试图依靠Neo4j 服务器 jar http repo neo4j org content repositories snapshots org neo4j app neo4j server 1 5 SNAPSHOT neo4j serv
  • 如何使用 UUID 生成唯一的正 Long

    我需要为我的数据库主键列生成唯一的长 ID 我以为我可以用UUID randomUUID getMostSignificantBits 但有时它也会产生一些负多头 这对我来说是个问题 是否可以从 UUID 中仅生成正长 将会有数十亿个条目
  • kafka Avro 多个主题的消息反序列化器

    我正在尝试以 avro 格式反序列化 kafka 消息 我使用以下代码 https github com ivangfr springboot kafka debezium ksql blob master kafka research c
  • 使用antlr4获取预处理器行并解析C代码

    我正在使用 Antlr4 来解析 C 代码 并使用以下语法来解析 链接到 C g4 https github com antlr grammars v4 blob master c C g4 上面的语法默认不提供任何解析规则来获取预处理器语
  • 获取证书链

    我正在 Java 中使用 X509 证书 给定一个证书 是否可以在签名层次结构中找到所有其他证书 直到找到根证书 我有一个证书文件 带有 cer扩展名 我想提取父签名证书 我想继续查找该证书的父证书 直到获得最终的自签名根证书 我已经检查了
  • 在 MVVM 中哪里可以捕获异常?

    我的视图模型类有一个连接到服务的方法 不确定这是否是一个好的实践 或者视图模型是否应该是严格的属性和属性更改机制 当然 我想在连接或断开连接时处理任何可能的 WCF 异常 让我们使用未找到端点作为示例 考虑到这是一个我想引起用户注意的异常
  • 为什么jdk中没有ConcurrentLinkedHashMap类?

    这个问题直接接着问从我之前的问题来看 https stackoverflow com q 12299731 1527084 我想我的第二个问题的答案是否定的 所以我想了解为什么 java util concurrent 包中没有 Concu
  • WebSocketStompClient 将无法连接到 SockJS 端点

    我正在尝试新的 从版本 4 2 开始 java STOMP 客户端支持 我的出发点是入门指南 使用 WebSocket 构建交互式 Web 应用程序 http spring io guides gs messaging stomp webs
  • 如何确保超类的子类方法的线程安全?

    我参加了一次面试 并被要求为以下要求设计一个课程 假设我有一个 A 类 它可以有任意数量的子类 即子类 类 A 有一个名为 doSomething 的方法 该方法是同步的 要求是 A 的所有子类都是强制性的重写 doSomething me
  • 在Java的System.out中以表格格式输出

    我正在从数据库获取结果 并希望将数据作为 Java 标准输出中的表输出 我尝试过使用 t 但我想要的第一列的长度变化很大 有没有办法将其显示在类似输出的漂亮表格中 Use System out format http java sun co

随机推荐

  • 获取 DOM 节点的字符串表示形式

    Javascript 我有一个节点 元素或文档 的 DOM 表示 我正在寻找它的字符串表示 例如 var el document createElement p el appendChild document createTextNode
  • 如何使用 socket.io 存储来自特定用户的套接字资源?

    我正在设计一个聊天脚本 我使用不同的浏览器在我的机器上测试它 我正在尝试使用 socket io 向特定用户发送消息 所以这里是 client socket on msgFromServer function data message da
  • 在使用 PHP 和 AJAX 执行期间终止 MySQL 查询

    我正在创建一个自定义查询生成器 当用户创建查询时 他可以通过单击按钮来验证查询语法 当用户单击按钮进行验证时 AJAX 调用将发送到服务器 并开始执行查询 在此期间 用户可以在屏幕上看到带有取消按钮的模式 如果用户有任何机会单击取消按钮 我
  • tableView.cellForRowAtIndexPath 返回 nil 单元格过多(快速)

    所以我有最奇怪的事情 我正在循环 tableView 以迭代所有单元格 对于少于 5 个单元 它可以正常工作 但是对于更多单元 它会崩溃并显示 意外发现 nil 这是代码 for section in 0
  • Qt:meta.enumeratorCount() 没有为 Q_OBJECT 中的枚举提供元数据,为什么?

    我有以下课程 我尝试获取一些元数据enum MyEnum 然而 当循环结束时meta enumeratorCount 它的计数始终为 0 基本上我在关注这个例子在这里 为了找到问题 我也尝试了同样的方法 同样的问题 方法计数 0 代码编译
  • 从一列中的唯一值创建 Pandas 数据框

    我有一个包含 1000 行的 Pandas 数据框 它有Names列包括客户名称及其记录 我想根据每个客户的唯一名称为他们创建单独的数据框 我将唯一的名称放入列表中 customerNames DataFrame customer name
  • Google Slides API,能够使用十六进制设置颜色吗?

    是否可以使用十六进制格式设置元素形状背景颜色 例如 B6D7A8 我在这里看到一个例子 Google Slides API 如何更改特定颜色的所有形状的文本颜色 然而 Google Slide API 参考并没有提及它 我想确定一下 特别是
  • MIME 类型“image/jpg”与“image/jpeg”相同吗?

    很简单的问题 但似乎无法在网上找到它 我正在尝试制作一个程序 根据文件类型会给我扩展名 No image jpg不等于image jpeg 你应该使用image jpeg Only image jpeg被识别为 JPEG 文件的实际 mim
  • 是否有主日期时间模式适用于每个类似的日期时间模式

    我的消费者收到的时间格式是String有价值20 5 14 9 22 25 or 20 5 14 9 22 5 or 20 5 14 12 22 25 or 20 10 14 9 2 25 etc 以上所有内容都有非常不同的日期时间模式yy
  • struts 2中的多个文件上传

    我在使用struts2上传文件时遇到问题 我有多个文件标签 例如
  • 如何在matlab中用scatter3图在同一图中绘制等值面?

    我有一个 3D 体积和一个 3D 点云 我怎样才能绘制点云以及isosurface体积 而不覆盖散点图 使用patch绘制等值面总是会擦掉scatter3 plot 有些事情要尝试 首先绘制使用补丁的表面 h patch 然后设置hold
  • 无法连接 Websphere MQ 队列管理器

    我是 WebSphere MQ 的初学者 我正在研究 MQ 6 并且它工作正常 但现在我已经安装了 MQ 7 1 当我尝试创建一个新的队列管理器时 我可以做到 但它无法连接并且它给了我以下错误 你对此有什么想法吗 谢谢 如果使用以下命令安装
  • Linq 获取高于姓氏的项目

    问候 我正在尝试找到一种使用 Linq to SQL 来获取姓氏高于 Jan 的前 15 条记录的方法 当我在 SQL 中使用它时 我得到了姓氏以字母顺序高于 Jan 的任何字母开头的每个成员 然而使用query Where m gt m
  • Python Numpy 累积/差异[重复]

    这个问题在这里已经有答案了 我希望扭转 numpy 的 cumsum 函数的效果 即累积 运行总计 查看下面的代码 我将数字 1 到 10 分配给 a 将这些数字的运行总和分配给 b 我需要反转这个过程 即从b计算a 我可以对此进行编码 参
  • 计算本地存储空间的使用情况

    我正在使用 Bespin 编辑器和 HTML5 的 localStorage 创建一个应用程序 它在本地存储所有文件并帮助语法 使用 JSLint 和其他一些 CSS 和 HTML 解析器来帮助用户 我想计算已使用了多少 localStor
  • 在 C# 中从外部应用程序获取 UI 文本

    是否可以从 C 中的外部应用程序获取 UI 文本 特别是 有没有办法从第三方编写的外部 Win32 应用程序的标签 我假设它是普通的 Windows 标签控件 读取 Unicode 文本 文本可见 但无法在 UI 中通过鼠标选择 我假设有一
  • JodaTime - 检查 LocalTime 是否在现在之后以及现在在另一个 LocalTime 之前

    我正在尝试检查当前时间是否是在开始之后LocalTime在另一个终点之前LocalTime即开始时间加上 11 小时 如果开始时间为 11 00 结束时间为 22 00 则效果很好 但是 当我尝试比较开始时间 16 00 和结束时间 03
  • T-SQL:将新的 INSERT 标识返回给 C#

    我使用存储过程将值放入 SQL Server 该过程将向所添加的行添加一个 ID 我需要将此 ID 返回到我的代码中 目前我可以在 Visual Studio 的 OUTPUT 窗口中看到输出 id 但似乎无法在我的代码中捕获它 这是该过程
  • 如何从另一个java程序中运行.jar文件?

    我有一个 jar 文件 可以在命令行上运行 java jar myFile jar argument1 我想将此 jar 的输出保存为另一个 java 程序中的字符串变量 我该怎么做 我尝试将 myFile jar 作为参考包含在我的程序中
  • 如何映射 Java 流中的 RuntimeExceptions 以从无效流元素中“恢复”

    想象一下 我正在构建一个库 它将接收整数流 而库代码所需要做的就是返回一个字符串流 其中包含数字的字符串表示形式 public Stream