草庐IT

java - 我应该流多次还是在一个流中进行所有计算?

coder 2024-03-13 原文

我有以下代码:

mostRecentMessageSentDate = messageInfoList
    .stream()
    .findFirst().orElse(new MessageInfo())
    .getSentDate();

unprocessedMessagesCount = messageInfoList
    .stream()
    .filter(messageInfo -> messageInfo.getProcessedDate() == null)
    .count();

hasAttachment = messageInfoList
    .stream()
    .anyMatch(messageInfo -> messageInfo.getAttachmentCount() > 0);

如您所见,我将同一个列表流式传输 3 次,因为我想找到 3 个不同的值。如果我在 For-Each 循环中执行此操作,我可以只循环一次。

那么做这个 for 循环是否更好,性能更明智,这样我只循环一次?我发现流更具可读性。

编辑:我进行了一些测试:

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Main {

public static void main(String[] args) {

    List<Integer> integerList = populateList();

    System.out.println("Stream time: " + timeStream(integerList));
    System.out.println("Loop time: " + timeLoop(integerList));

}

private static List<Integer> populateList() {
    return IntStream.range(0, 10000000)
            .boxed()
            .collect(Collectors.toList());
}

private static long timeStream(List<Integer> integerList) {
    long start = System.currentTimeMillis();

    Integer first = integerList
            .stream()
            .findFirst().orElse(0);

    long containsNumbersGreaterThan10000 = integerList
            .stream()
            .filter(i -> i > 10000)
            .count();

    boolean has10000 = integerList
            .stream()
            .anyMatch(i -> i == 10000);

    long end = System.currentTimeMillis();

    System.out.println("first: " + first);
    System.out.println("containsNumbersGreaterThan10000: " + containsNumbersGreaterThan10000);
    System.out.println("has10000: " + has10000);

    return end - start;
}

private static long timeLoop(List<Integer> integerList) {
    long start = System.currentTimeMillis();

    Integer first = 0;
    boolean has10000 = false;
    int count = 0;
    long containsNumbersGreaterThan10000 = 0L;
    for (Integer i : integerList) {
        if (count == 0) {
            first = i;
        }

        if (i > 10000) {
            containsNumbersGreaterThan10000++;
        }

        if (!has10000 && i == 10000) {
            has10000 = true;
        }

        count++;
    }

    long end = System.currentTimeMillis();

    System.out.println("first: " + first);
    System.out.println("containsNumbersGreaterThan10000: " + containsNumbersGreaterThan10000);
    System.out.println("has10000: " + has10000);

    return end - start;
}
}

正如预期的那样,for 循环总是比流快

first: 0
containsNumbersGreaterThan10000: 9989999
has10000: true
Stream time: 57
first: 0
containsNumbersGreaterThan10000: 9989999
has10000: true
Loop time: 38

但从来没有显着。

findFirst 可能是一个不好的例子,因为如果流为空它就会退出,但我想知道它是否有所作为。

我希望得到一个允许从一个流进行多次计算的解决方案。 IntSummaryStatistics 并没有完全按照我的意愿行事。我想我会注意@florian-schaetz 并坚持支持可读性以获得边际性能提升

最佳答案

您不会遍历集合 3 次。

mostRecentMessageSentDate = messageInfoList
        .stream()
        .findFirst().orElse(new MessageInfo())
        .getSentDate();

以上检查集合中是否有任何元素,并根据此返回一个值。它不需要遍历整个集合。

unprocessedMessagesCount = messageInfoList
        .stream()
        .filter(messageInfo -> messageInfo.getProcessedDate() == null)
        .count();

这个需要过滤掉所有没有处理日期的元素并对它们进行计数,所以这个要遍历整个集合。

hasAttachment = messageInfoList
        .stream()
        .anyMatch(messageInfo -> messageInfo.getAttachmentCount() > 0);

上面只需要遍历元素,直到找到带有附件的消息。

因此,在三个流中,只有其中一个需要遍历整个集合,在最坏的情况下,您需要进行两次迭代(第二个,可能是第三个流) .

使用常规的 For-Each 循环可能会更有效,但您真的需要它吗?如果您的集合只包含几个对象,我不会费心去优化它。

但是,使用传统的 For-Each 循环,您可以组合最后两个流:

int unprocessedMessagesCount = 0;
boolean hasAttachment = false;

for (MessageInfo messageInfo: messageInfoList) {
  if (messageInfo.getProcessedDate() == null) {
    unprocessedMessagesCount++;
  }
  if (hasAttachment == false && messageInfo.getAttachmentCount() > 0) {
    hasAttachment = true;
  }
}

如果您认为这是一个更好的解决方案,这真的取决于您(我还发现流更具可读性)。我看不到将三个流合并为一个流的方法,至少不是以更具可读性的方式。

关于java - 我应该流多次还是在一个流中进行所有计算?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44237839/

有关java - 我应该流多次还是在一个流中进行所有计算?的更多相关文章

  1. ruby - 如何以所有可能的方式将字符串拆分为长度最多为 3 的连续子字符串? - 2

    我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123

  2. ruby - 多次弹出/移动 ruby​​ 数组 - 2

    我的代码目前看起来像这样numbers=[1,2,3,4,5]defpop_threepop=[]3.times{pop有没有办法在一行中完成pop_three方法中的内容?我基本上想做类似numbers.slice(0,3)的事情,但要删除切片中的数组项。嗯...嗯,我想我刚刚意识到我可以试试slice! 最佳答案 是numbers.pop(3)或者numbers.shift(3)如果你想要另一边。 关于ruby-多次弹出/移动ruby​​数组,我们在StackOverflow上找到一

  3. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  4. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  5. ruby-on-rails - 渲染另一个 Controller 的 View - 2

    我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>

  6. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  7. ruby-on-rails - 使用一系列等级计算字母等级 - 2

    这里是Ruby新手。完成一些练习后碰壁了。练习:计算一系列成绩的字母等级创建一个方法get_grade来接受测试分数数组。数组中的每个分数应介于0和100之间,其中100是最大分数。计算平均分并将字母等级作为字符串返回,即“A”、“B”、“C”、“D”、“E”或“F”。我一直返回错误:avg.rb:1:syntaxerror,unexpectedtLBRACK,expecting')'defget_grade([100,90,80])^avg.rb:1:syntaxerror,unexpected')',expecting$end这是我目前所拥有的。我想坚持使用下面的方法或.join,

  8. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  9. ruby - 为什么 SecureRandom.uuid 创建一个唯一的字符串? - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?

  10. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

随机推荐