【问题标题】:How to modify the iterator when hashset values are added添加哈希集值时如何​​修改迭代器
【发布时间】:2014-10-07 10:28:56
【问题描述】:

我已经编写了代码,用于在 java 中使用 selenium webdriver 找出网站中存在的损坏链接。由于在启动不同的 url 时将链接添加到 HashSet 中。我试图从HashSet 读取添加的网址,它会在一段时间后停止执行。发生这种情况是因为迭代器仍然存在,因为它甚至添加了到 HashSet 的新链接。我希望对HashSet 中存在的所有链接继续执行。 [我尝试将Set 转换为数组,但重复的链接正在执行多次。]

public Set<String> unique_links;
HashMap<String, String> result;
Set<String> finalLinkSet = new HashSet<>();
Set<String> hs = new HashSet<>();
Set<String> uniqueLinkSet = new HashSet<>();
// String[] finalLinkArray;
String[] finalLinkArray;
boolean isValid = false;
FileWriter fstream;
BufferedWriter out;
int count = 1;
int FC = 0;
Set<String> secondaryset = new HashSet<>();

// String Responsecode = null;

@Test
public void LinkTesting() throws IOException, RowsExceededException,
        WriteException {

    w.manage().deleteAllCookies();
    unique_links = new HashSet<String>();
    w.get("http://www.skyscape.com");

    ArrayList<WebElement> urlList = new ArrayList<WebElement>();
    urlList = (ArrayList<WebElement>) w.findElements(By.tagName("a"));

    setFinalLinkSet(getUniqueList(urlList));


    for(Iterator<String> i = finalLinkSet.iterator(); i.hasNext(); ) {

    System.out.println(finalLinkSet.size());
    String currenturl = (String) i.next();


     if ((currenturl.length() > 0 && currenturl
     .startsWith("http://www.skyscape.com"))) {

     if (!currenturl.startsWith("http://www.skyscape.com/estore/")&&
     (!currenturl.startsWith("http://www.skyscape.com/demos/"))) {
     System.out.println(currenturl);

     getResponseCode(currenturl);
     }
     }
     }


    writetoexcel();
}

public void setFinalLinkSet(Set<String> finalLinkSet) {
    this.finalLinkSet = finalLinkSet;
}

// function to get link from page and return array list of links
public Set<String> getLinksOnPage(String url) {

    ArrayList<WebElement> secondaryUrl = new ArrayList<WebElement>();
    secondaryUrl = (ArrayList<WebElement>) w.findElements(By.tagName("a"));

    for (int i = 0; i < secondaryUrl.size(); i++) {

        secondaryset.add((secondaryUrl.get(i).getAttribute("href")
                .toString()));
    }

    return secondaryset;
}

// function to fetch link from array list and store unique links in hashset
public Set<String> getUniqueList(ArrayList<WebElement> url_list) {

    for (int i = 0; i < url_list.size(); i++) {
        uniqueLinkSet.add(url_list.get(i).getAttribute("href").toString());
    }

    return uniqueLinkSet;
}

public boolean getResponseCode(String url) {
    boolean isValid = false;

    if (result == null) {
        result = new HashMap<String, String>();
    }

    try {
        URL u = new URL(url);
        w.navigate().to(url);
        HttpURLConnection h = (HttpURLConnection) u.openConnection();
        h.setRequestMethod("GET");
        h.connect();
        System.out.println(h.getResponseCode());

        if ((h.getResponseCode() != 500) && (h.getResponseCode() != 404)
                && (h.getResponseCode() != 403)
                && (h.getResponseCode() != 402)
                && (h.getResponseCode() != 400)
                && (h.getResponseCode() != 401)) {
            // && (h.getResponseCode() != 302)) {

            //getLinksOnPage(url);

            Set<String> unique2 = getLinksOnPage(url);
            setFinalLinkSet(unique2);

            result.put(url.toString(), "" + h.getResponseCode());

        } else {

            result.put(url.toString(), "" + h.getResponseCode());

            FC++;
        }

        return isValid;
    } catch (Exception e) {

    }
    return isValid;
}

private void writetoexcel() throws IOException, RowsExceededException,
        WriteException {

    FileOutputStream fo = new FileOutputStream("OldLinks.xls");
    WritableWorkbook wwb = Workbook.createWorkbook(fo);
    WritableSheet ws = wwb.createSheet("Links", 0);
    int recordsToPrint = result.size();

    Label HeaderUrl = new Label(0, 0, "Urls");
    ws.addCell(HeaderUrl);
    Label HeaderCode = new Label(1, 0, "Response Code");
    ws.addCell(HeaderCode);
    Label HeaderStatus = new Label(2, 0, "Status");
    ws.addCell(HeaderStatus);
    Iterator<Entry<String, String>> it = result.entrySet().iterator();
    while (it.hasNext() && count < recordsToPrint) {
        String Responsecode = null;
        Map.Entry<String, String> pairs = it.next();
        System.out.println("Value is --" + pairs.getKey() + "  -  "
                + pairs.getValue() + "\n");

        Label Urllink = new Label(0, count, pairs.getKey());

        Label RespCode = new Label(1, count, pairs.getValue());

        Responsecode = pairs.getValue();
        System.out.println(Responsecode);
        if ((Responsecode.equals("500")) || (Responsecode.equals("404"))
                || (Responsecode.equals("403"))
                || (Responsecode.equals("400"))
                || (Responsecode.equals("402"))
                || (Responsecode.equals("401"))) {
            // || (Responsecode.equals("302"))) {
            Label Status1 = new Label(2, count, "Fail");
            ws.addCell(Status1);
        } else {
            Label Status2 = new Label(2, count, "Pass");
            ws.addCell(Status2);
        }

        try {
            ws.addCell(Urllink);
        } catch (RowsExceededException e) {
            e.printStackTrace();
        } catch (WriteException e) {

            e.printStackTrace();
        }
        ws.addCell(RespCode);
        count++;
    }

    Label FCS = new Label(4, 1, "Fail Urls Count is = " + FC);
    ws.addCell(FCS);
    wwb.write();
    wwb.close();

}

}

【问题讨论】:

  • 代码太多,而且(IMO)大部分与您的问题无关。请将其简化为一个小而完整的工作示例来说明问题。

标签: java iterator hashset


【解决方案1】:

简而言之,据我了解问题:您(至少)有两个线程(尽管我在太长的代码示例中找不到它们),一个是向 HashSet 添加条目,另一个应该在将元素添加到 HashSet 时连续列出元素。 第一:您应该为此使用并发数据结构,而不是简单的 HashSet。 第二:HashSet 的迭代器不支持并发修改,所以你现在可以让一个迭代器“等待”新条目的添加。

最好的方法是更改​​您的代码以使用某种事件消息模式(有时也称为广播器/侦听器),其中找到新 URL 会生成一个事件,您的代码的其他部分会侦听然后编写它们到文件中。

【讨论】:

  • 不,他没有 2 个线程。他只是在从循环内部调用的方法中替换(尽管打算更新)他正在迭代的列表。
【解决方案2】:

您的循环结束(比预期的要早),原因如下:

  • 你的for循环的启动部分Iterator&lt;String&gt; i = finalLinkSet.iterator()

    for(Iterator<String> i = finalLinkSet.iterator(); i.hasNext(); ) {
    

    在循环开始时被评估一次。因此它不会对 finalLinkSet 的更改做出反应,即使有一些变化。

  • 您没有对finalLinkSet 进行任何更改。相反,您在调用时用新的集合覆盖它

    setFinalLinkSet(unique2);
    

所以你应该:

  • 使用列表,这样您就可以对元素进行排序。 (将条目添加到无序集合将无法知道您已经迭代了哪些条目)。因此,我建议您使用ArrayList&lt;String&gt;,这样您就可以通过在添加新条目时调整大小的小缺点来获得恒定的访问时间。
  • 修改您的 for 循环以使用索引,因此评估 init-part 一次就足够了,您可以对不断变化的列表大小做出反应:

    for(int i = 0; i < finalLinkList.size(); i++) {
        System.out.println(finalLinkSet.size());
        String currenturl = (String) finalLinkList.get(i);
    
  • 那么,您应该:

    // for both occurrences
    addToFinalLinkList(...); // see new code below
    

    public void addToFinalLinkList(Set<String> tempSet) {
        for(String url: tempSet)
        {
            if(!finalLinkList.contains(url))
                finalListList.add(url);  
        }
    }
    

    我知道从性能的角度来看这不是最好的,但是由于您在测试中,所以从我所看到的来看这应该不是问题...

【讨论】:

    猜你喜欢
    • 2021-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-10
    • 2023-04-07
    • 2023-03-18
    • 1970-01-01
    • 2013-07-08
    相关资源
    最近更新 更多