用Java8流替换更复杂的嵌套for循环

用Java8流替换更复杂的嵌套for循环,java,for-loop,java-8,Java,For Loop,Java 8,我的循环比平常更复杂,在我更努力地实现它之前,我想听听它是否可行 if (emailClicks != null && emailsOfContactsWhoFitDynConFilter != null) { for (String email : emailsOfContactsWhoFitDynConFilter) { for (Contact contact : emailClicks.items) {

我的循环比平常更复杂,在我更努力地实现它之前,我想听听它是否可行

if (emailClicks != null  && emailsOfContactsWhoFitDynConFilter != null) {
            for (String email : emailsOfContactsWhoFitDynConFilter) {
                for (Contact contact : emailClicks.items) { 
                    String queryStringActivity = getQueryStringByName("elqTrackId", (contact.link).split("\\?",-1)[1]);
                    String queryStringDynConLink = getQueryStringByName("elqTrackId", linkInDynamicContent.split("\\?",-1)[1]);
                    if (email.equals(contact.EmailAddress) && (contact.link).split("\\?")[0].equals(linkInDynamicContent.split("\\?")[0])) {
                        if (queryStringActivity !=null && queryStringDynConLink!=null && queryStringActivity.equals(queryStringDynConLink)){
                            count++;
                            break; 
                        }else if (queryStringActivity==null || queryStringDynConLink ==null){
                            count++;
                            break;
                        }
                    }
                }
            }
        }
也许你可以帮我用其他方法优化它。当阵列太大(约20000个)时,我在这里经历了极大的时间消耗。

  • 正如注释中已经提到的:
    linkInDynamicContent.split(“\\?”,-1)
    可以在两个循环之外执行一次,因为
    linkInDynamicContent
    从不更改
  • 如果此条件
    if(email.equals(contact.EmailAddress)
    失败,您将拆分需要时间的
    contact.link
    ,然后不使用它。

    我看到的最大问题是,您基本上是在对email.id=contact.email上的
    电子邮件连接联系人进行“嵌套循环连接”,运行时为n*m,其中n为电子邮件数量,m为联系人数量。
    而且你根本不使用电子邮件。你对电子邮件和联系人的每一个组合都进行内部循环。但是只有一次,当contact.email匹配第一个循环中的电子邮件时,你实际上做了一些事情。
    尝试将您的结构更改为以下内容:

    String[] linkInDynamicContentSplit = linkInDynamicContent.split("\\?",-1);
    
    if (!emailsOfContactsWhoFitDynConFilter.isEmpty()) {
        for (Contact contact : emailClicks.items) {
            if(emailsOfContactsWhoFitDynConFilter.contains(contact.EmailAddress));
            // your code
            String queryStringActivity = getQueryStringByName("elqTrackId", (contact.link).split("\\?",-1)[1]);
            // ...
        }
    }
    
      • 不要在循环中包含可以在循环外完成的操作。(已经提到)

      • 查看重复代码的位置,或者多次检查相同的条件

      if(queryStringActivity!=null&&….)

      else if(queryStringActivity==null | |…)

      • 不要害怕创建新方法(JIT可以内联方法),这样就不会有效率损失

      • 尝试使用递归而不是迭代(递归来自上帝,迭代来自程序员)(遗憾的是,即使Java8也没有尾部递归,但这是一个很好的实践)


      我将从查看
      .split(“\\?”)
      开始。这可能会对性能产生重大影响,尤其是您经常这样做。在切换到流之前,请尝试评估花费的时间以及开销在哪里。在我看来,
      String queryStringDynConLink=getQueryStringByName(“elqTrackId”,linkindynamicscontent.split(“\\?”,-1)[1])重复太多次:将此行从循环中删除。另外
      (contact.link)。split(…)
      可以在每次迭代中调用一次,而不是两次。您不应该使用streams替换
      for
      循环,这是一种误解。使用流来简化您的工作或在真正需要时使用流。此外,您需要知道,您不能修改
      流中的变量,因此计数在那里不起作用,您可能需要对代码进行更多更改。我建议在尝试使用streams重写代码之前对该代码进行适当的单元测试。@LuiggiMendoza谢谢,但我认为流更快,因为它们可能是并行的,对吗?您可以使用
      ExecutorService
      for
      循环中添加并行性,这将是更详细的,但结果将是一样的。谢谢你的回答。然而,我需要两个循环,因为我需要循环通过所有符合自定义过滤器的联系人的每个电子邮件地址。我说的那个外环。不管怎么说,有些要点是非常好和有效的:)仅凭您发布的代码,您不需要外部循环,因为您只需将contact.EmailAddress与外部循环中的地址进行匹配。如果您在这方面做更多的工作,您可能需要一个带有电子邮件地址的HashMap,以避免在If语句中使用的内部循环中嵌套循环
      email.equals(contact.EmailAddress)
      ,你说我不需要外循环是什么意思?因为我需要为每个电子邮件地址累积
      计数
      。@OndrejTokar如果你需要遍历所有数据,在一次查询中检索所有数据,然后在内存中处理这些数据不是比多次查询数据源更容易、更快吗?在内部循环中,您可以从联系人处获得电子邮件地址。对于来自外部循环的电子邮件,您唯一要做的就是检查它是否与内部循环匹配。如果没有,则继续到下一个内部。所以基本上你会忽略每个内部邮件n-1次(对于n封外部邮件),然后做一次事情。因此,您可以只做内部循环,并检查是否有一个匹配的电子邮件地址为您的联系人。感谢您的良好和有效的输入。我还没有做过关于递归的任何事情,但是听说了很多。也许是时候使用它了!:)