java - 使用 Java 8 流映射函数来执行长时间运行的任务

标签 java dictionary java-stream long-running-processes

我有一个方法,它将(远程文件的)URL 列表作为应该下载的参数。该方法返回一个其他类型的List(称为Attachment),它实际上包含java File类型的属性。 对于本例,我使用 Java Stream API 迭代 URL 并在“map”函数中启动下载,该函数实际上返回附件实例。

现在我的问题是:我是否滥用 Java Stream API 来做一些不该做的事情?喜欢将长时间运行任务放入其中吗?我应该只对输入数据进行小操作吗?

我现在看到的唯一缺点是测试有点困难。

private List<Attachment> download(List<URL> attachments) {
        return attachments.stream().map(attachmentUrl -> {
            try {
                Attachment attachment = new Attachment();
                File attachmentFile = new File(getFilename(attachment.getAttachmentId(), attachmentUrl));
                FileUtils.copyURLToFile(
                        attachmentUrl,
                        attachmentFile,
                        CONNECT_TIMEOUT,
                        READ_TIMEOUT);
                attachment.setAttachmentFile(attachmentFile);
                return attachment;
            } catch (IOException e) {
                e.printStackTrace();
                LOGGER.error(e.getLocalizedMessage());
            }
            return null;
        }).filter(Objects::nonNull).collect(Collectors.toList());
    }

最佳答案

我认为考虑 map 和其他功能结构(例如 filterreduce 等)可能会有所帮助。作为函数,而是作为语法stream().map() 是执行与 for 循环功能等效的语法。问“我是否因为使用该语法执行的内容而滥用了该语法?”那么就没那么有意义了:for 循环不关心它们在每次迭代中运行的任务需要多长时间,map 也不关心。它与它所应用的操作无关,因此唯一的问题是您是否正确使用了语法,即循环遍历集合,映射从某物到某物。

在这种情况下,其中 map 是语法,您想要的操作完全没问题。但是,您的实现可以稍微清理一下。

attachmentUrl -> {
    try {
        Attachment attachment = new Attachment();
        File attachmentFile = new File(getFilename(attachment.getAttachmentId(), attachmentUrl));
        FileUtils.copyURLToFile(
                attachmentUrl,
                attachmentFile,
                CONNECT_TIMEOUT,
                READ_TIMEOUT);
        attachment.setAttachmentFile(attachmentFile);
        return attachment;
    } catch (IOException e) {
        e.printStackTrace();
        LOGGER.error(e.getLocalizedMessage());
    }
    return null;
}

对于内联 map lambda 来说有点大。一般来说,我倾向于对任何需要大括号(即占用多行)的 map lambda 持怀疑态度,尽管并不总是反对。我建议将此 lambda 重构为命名函数,并且可能是一对,它们要么是嵌套的 (map(this::A),其中 A 然后调用 B) 或由流操作连续使用 map(this::A).map(this::B)

<小时/>

[编辑:]关于并行化您的:请记住,作为此方法的一部分,您所做的不仅仅是CPU处理 - 您似乎正在执行网络IO 文件 IO。如果并行执行,您不仅会并行化 CPU 利用率,还会并行化网络和磁盘使用率。如果网络磁盘是主导因素,而不是CPU,那么并行化可能不会给你带来什么好处,而且可能会让事情变得更糟。一般来说,更多的线程!=更快的网络或磁盘读/写。您可能会发现this question on parallel IO有用。

关于java - 使用 Java 8 流映射函数来执行长时间运行的任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58594814/

相关文章:

java - 使用 Java 8 Streams 减少字符串列表,仅向最后一个元素添加前缀

java - sendKeys 不适用于与 Appium 和 Java 一起使用的输入(三星的数字键盘)

Java正则表达式与句点部分匹配

类对象字典的vba深层复制/克隆问题

java - Files.lines 跳过 Java8 中的虚线

java - 在使用流时创建一个排序集

java - 在Windows的tomcat服务器上托管的Java程序中显示Unicode字符

java - 使用keytool安装安全证书

dictionary - 字典中键的 Pythonic 简写?

python - "in"的时间复杂度(包含运算符)