Java 如何优化嵌套循环?

Java 如何优化嵌套循环?,java,Java,我有两个foreach循环。其中一个包含唯一电子邮件列表(外部)。我希望将其作为外循环,并在外循环和内循环的元素之间存在匹配时将计数增加1 我现在的代码: outer: for (String email : emailsOfContactsWhoFitDynConFilter) { for (Contact contact : emailClicks.items) { String[] contactLink = (contact.link).spli

我有两个
foreach
循环。其中一个包含唯一电子邮件列表(外部)。我希望将其作为外循环,并在外循环和内循环的元素之间存在匹配时将计数增加1

我现在的代码:

outer: for (String email : emailsOfContactsWhoFitDynConFilter) {
        for (Contact contact : emailClicks.items) {
            String[] contactLink =  (contact.link).split("\\?", -1);
            String queryStringActivity = getQueryStringByName("elqTrackId", contactLink[1]);

            if (email.equals(contact.EmailAddress) && contactLink[0].equals(linkInDynamicContentSplit[0])) {
                if (queryStringActivity !=null && queryStringDynConLink!=null && queryStringActivity.equals(queryStringDynConLink)){
                    count++;
                    break outer; 
                    } else if (queryStringActivity == null || queryStringDynConLink == null) {
                    System.out.println("  -  Missing elqTrackId. But base the same, count++");
                    count++;
                    break outer;
                }
            }
        }
    }
这是可行的,但问题在于这两条线:

String[] contactLink =  (contact.link).split("\\?", -1);
String queryStringActivity = getQueryStringByName("elqTrackId", contactLink[1]);
执行次数太多,会消耗大量时间

我可以反转循环,所以它看起来像这样:

outer: for (Contact contact : emailClicks.items) {
            String[] contactLink =  (contact.link).split("\\?", -1);
            String queryStringActivity = getQueryStringByName("elqTrackId", contactLink[1]);
          for (String email : emailsOfContactsWhoFitDynConFilter) {
          if (email.equals(contact.EmailAddress) && contactLink[0].equals(linkInDynamicContentSplit[0])) {
                if (queryStringActivity !=null && queryStringDynConLink!=null && queryStringActivity.equals(queryStringDynConLink)){
                    count++;
                    break outer; 
                    } else if (queryStringActivity == null || queryStringDynConLink == null) {
                    System.out.println("  -  Missing elqTrackId. But base the same, count++");
                    count++;
                    break outer;
                }
            }
        }
    }

这会快得多,但是我的
count++
发生的次数比我想要的要多,不会是每个唯一的电子邮件
+1

这里有几个不错的选择,但第一个选择是简单地缓存字符串[]。这是一个很有价值的教训,说明了为什么应该使用方法而不是成员

我建议使用
contact.getLinkCache()
method的方法,实现如下所示。这使您不必一次又一次地进行拆分(其中有一个克隆用于保护数据,但克隆是一种非常快速的方法,除非您认为这太慢,否则您可能应该使用它

class Contact {

    String link;
    String[] linkSplitCache;

    public void setLink(String link) {
        this.link = link;
        this.linkSplitCache = null;
    }

    public String getLink() {
        return link;
    }

    public String[] getLinkCache() {
        if(linkSplitCache == null) {
            linkSplitCache = link.split("\\?",-1);
        }
        // return linkSplitCache; // could corrupt!
        return linkSplitCache.clone(); // pretty fast array copy
    }
}
如果它太慢,那么您可能需要某种映射来缓存它,这可能在Contact类之外

Map<Contact, String[]> linkSplitCache = new HashMap<>();

outer: for (Contact contact : emailClicks.items) {
    String[] contactLink =  linkSplitCache.get(contact);
    if(contactLink == null) {
        contactLink = (contact.link).split("\\?", -1);
        linkSplitCache.put(contact,contactLink);
    }
    // rest of loop here
Map linkSplitCache=newhashmap();
外部:用于(联系人:emailClicks.items){
字符串[]contactLink=linkSplitCache.get(联系人);
如果(contactLink==null){
contactLink=(contact.link).split(“\\?”,-1);
linkSplitCache.put(contact,contactLink);
}
//这里是循环的其余部分

在@corsiKlause Ho的大力帮助下,我可以找到解决方案:

Map<String, String[]> linkSplitCache = new HashMap<>();
    int count = 0;
    String[] linkInDynamicContentSplit = linkInDynamicContent.split("\\?", -1);
    String queryStringDynConLink = getQueryStringByName("elqTrackId", linkInDynamicContentSplit[1]);
    if (emailClicks != null && emailsOfContactsWhoFitDynConFilter != null) {
        for (String email : emailsOfContactsWhoFitDynConFilter) {
        inner: for (Contact contact : emailClicks.items) {
                String[] contactLink = linkSplitCache.get(contact.EmailAddress);
                if (contactLink == null){
                    contactLink =  (contact.link).split("\\?", -1);
                    contactLink[1] = getQueryStringByName("elqTrackId", contactLink[1]);
                    linkSplitCache.put(contact.EmailAddress, contactLink);
                }

                if (email.equals(contact.EmailAddress) && contactLink[0].equals(linkInDynamicContentSplit[0])) {
                     if (contactLink[1] !=null && queryStringDynConLink!=null && contactLink[1].equals(queryStringDynConLink)){
                        count++;
                        break inner; // this excludes link clicks which were done
                                // twice by the same person
                    } else if (contactLink[1] == null || queryStringDynConLink == null) {
                        System.out.println("  -  Missing elqTrackId. But base the same, count++");
                        count++;
                        break inner;
                    }
                }
            }
        }
    }
Map linkSplitCache=newhashmap();
整数计数=0;
字符串[]linkInDynamicContentSplit=linkInDynamicContent.split(“\\?”,-1);
字符串queryStringDynConLink=getQueryStringByName(“elqTrackId”,linkindynamicscontentsplit[1]);
if(emailClicks!=null&&emailsOfContactsWhoFitDynConFilter!=null){
用于(字符串电子邮件:emailsOfContactsWhoFitDynConFilter){
内部:用于(联系人:emailClicks.items){
字符串[]contactLink=linkSplitCache.get(contact.EmailAddress);
如果(contactLink==null){
contactLink=(contact.link).split(“\\?”,-1);
contactLink[1]=getQueryStringByName(“elqTrackId”,contactLink[1]);
linkSplitCache.put(contact.EmailAddress,contactLink);
}
if(email.equals(contact.EmailAddress)和&contactLink[0].equals(linkindynamicscontentsplit[0])){
如果(contactLink[1]!=null&&queryStringDynConLink!=null&&contactLink[1]。等于(queryStringDynConLink)){
计数++;
中断内部;//这不包括已完成的链接单击
//两次是同一个人干的
}else if(contactLink[1]==null | | queryStringDynConLink==null){
System.out.println(“-Missing-elqTrackId.But base same,count++”);
计数++;
打破内在;
}
}
}
}
}

基本上,我所做的是用唯一的键
电子邮件地址将链接添加到
HashMap
,这确保了我不会在不必要的地方多次执行相同的操作。

我投票将这个问题作为离题题来结束,因为这个问题更适合:为什么
count++
是e执行了不同的次数?在交叉连接中,每对代码只检查一次。顺便说一句,如果将标签放在循环上方的一行上,而不是放在同一行代码上,代码会更容易阅读。如果超出缩进,代码的
else if
行也会更清晰。基本上,缩进会使代码更清晰现在很难理解。计数会更高,因为内部循环包含的活动不是唯一的。这有意义吗?如果没有,我可以画出来。你可以不用嵌套:使用两个循环-首先是绘制一些地图,然后再做这项工作。你只需要一个好的键…你分析了你的代码吗?真的太复杂了吗慢?它在哪里花费时间?我想你有一个很好的观点,问题是,
电子邮件点击。项目作为一个对象在联系方面没有重复项。有重复项是两个不同的对象,但共享相同的电子邮件地址。但我想我可以通过一些调整使用你的解决方案。我很高兴你找到了一个解决方案但是我不能不认为你应该避免使用
object.member
-使用
object.getMember()
相反。有什么实际的原因应该通过getter来实现吗?我知道这是惯例,但仍然有什么真正的原因吗?因为这些对象只是一个
JSON
反序列化,我不使用任何构造函数,我真的不需要getter。你现在不需要getter,但你不知道如何实现以后可能需要更改实现。如果您使用值缓存或计算,如果您进行任何验证,您将很难获得所有验证,因为您使用的是成员访问而不是getter。请阅读有效Java,第二版第14项:“在公共类中,使用访问器方法,而不是公共字段”更多信息。非常感谢您提供的信息。