【问题标题】:Infinite Loop Iterating Through Hashtable通过哈希表进行无限循环迭代
【发布时间】:2013-01-30 19:33:02
【问题描述】:

我正在尝试使用 Hashtables 在数组中查找最流行的单词。由于某种原因,while 循环无限循环。我已经调试过,元素从它得到的第一个元素永远不会改变。关于为什么会发生这种情况的任何想法?

这是我的代码:

import java.util.Hashtable;

public class MyClass {
  public String mostPopularString (String []words) {
    if (words == null)
            return null;
    if (words.length == 0)
            return null;
    Hashtable<String, Integer> wordsHash = new Hashtable<String, Integer>();
    for (String thisWord : words)
    {
        if (wordsHash.containsKey(thisWord))
        {
            wordsHash.put(thisWord, wordsHash.get(thisWord) + 1);
        }
        else
        {
            wordsHash.put(thisWord, 1);
        }
    }
    Integer mostPopularCount = 0;
    String mostPopularWord = null;
    boolean tie = false;
    while (wordsHash.keys().hasMoreElements())
    {
        String currentWord = (String) wordsHash.keys().nextElement();
        if (wordsHash.get(currentWord) > mostPopularCount)
        {
            mostPopularCount = wordsHash.get(currentWord);
            mostPopularWord = currentWord;
            tie = false;
        }
        else if (wordsHash.get(currentWord) == mostPopularCount)
        {
            tie = true;
        }
    }
    if (tie)
        return null;
    else
        return mostPopularWord;
  }
}

【问题讨论】:

    标签: java hashtable


    【解决方案1】:

    您在循环的每次迭代中调用wordsHash.keys(),这会在每次迭代中为您提供一个新的Enumeration&lt;String&gt; - 然后您在循环内部再次调用它。

    你想调用它一次,然后遍历单个Enumeration&lt;String&gt;

    Enumeration<String> iterator = wordsHash.keys();
    while (iterator.hasMoreElements())
    {
        String currentWord = iterator.nextElement();
        ...
    }
    

    请注意,由于您还要获取每个元素的值,因此最好迭代 entrySet() 而不是 keys()

    最好使用HashMap而不是Hashtable,因为那样你就可以使用增强的for循环......

    【讨论】:

    • 非常感谢!这真的很好。只是需要另一双眼睛。
    【解决方案2】:

    问题出在一行

    while (wordsHash.keys().hasMoreElements())
    

    每次通过循环,您都会获得一个新的枚举副本。您需要获取一次密钥集,然后对其进行迭代。

    在这里使用增强的 for 循环可能会更容易

       for (Map.Entry<String,Integer> entry : wordsHash.entrySet()) {
            String currentWord = entry.getKey();
            Integer currentCount = entry.getValue();
            //more code here
        }
    

    这应该提供您想要的行为,同时更简单、更易于阅读。

    【讨论】:

    • 技术上它是一个枚举,而不是一个列表。
    【解决方案3】:

    问题是每当你调用wordsHash.keys(),它都会返回一个新的枚举:

    while (wordsHash.keys().hasMoreElements())                        // <=== HERE
    {
        String currentWord = (String) wordsHash.keys().nextElement(); // <=== AND HERE
    

    您需要做的是创建一个枚举并在整个循环中使用它。

    附:你为什么用Hashtable而不是HashMap

    【讨论】:

      【解决方案4】:

      .keys() 的每次调用都会返回一个新的枚举,并带有一个用于迭代的新内部指针:

      Hashtable table = new Hashtable();
      table.put("a", "a");
      table.put("b", "b");
      boolean b = table.keys() == table.keys();
      System.out.println(b); // false
                             // the two calls to `.keys()` returned different instances of Enumeration
      

      因此,将您的 keys 枚举分配给一个变量:

      Enumeration keys = wordsHash.keys();
      while (keys.hasMoreElements())
      {
          String currentWord = (String) keys.nextElement();
      
      }
      

      【讨论】:

        【解决方案5】:

        将您的代码更改为:

        Enumeration<String> keys = wordsHash.keys();
        while (keys.hasMoreElements()) {
            String currentWord = keys.nextElement();
        

        因此,每次进入循环时都不会创建指向HashTable 的第一个键的新枚举。

        【讨论】:

          【解决方案6】:

          没有修改wordsHash。这意味着如果wordsHash.keys().hasMoreElements() 一次为真,那么对于程序的其余部分将继续为真。这会导致无限循环。您要么需要删除密钥,要么只使用 for

          【讨论】:

            【解决方案7】:

            每次循环迭代都会得到一个新的 Iterable 提供所有键:wordsHash.keys(),只要其中至少有一个键,while 循环就永远不会结束。

            替换:

            while (wordsHash.keys().hasMoreElements()){
               String currentWord = (String) wordsHash.keys().nextElement();
            

            通过

            for (String currentWord: wordsHash.keys()){
            

            【讨论】:

              【解决方案8】:

              另外,与您的枚举问题无关,这可能是一个缺陷:

              else if (wordsHash.get(currentWord) == mostPopularCount)
              

              这是一个 java.lang.Integer 与另一个 java.lang.Integer 的参考比较。这不是它们所代表的实际值的比较。它适用于“小”数字,因为自动装箱使用缓存的引用,但最终会中断。你可能想要:

              else if (wordsHash.get(currentWord) == mostPopularCount.intValue())
              

              【讨论】:

              • 甚至wordsHash.get(currentWord).compareTo(mostPopularCount) == 0应该在这里使用:)
              • 是的,但是 'compareTo' 的存在以及在这种情况下对它的需要让人讨厌 java 的想法并想成为项目经理;)
              猜你喜欢
              • 1970-01-01
              • 2021-09-22
              • 1970-01-01
              • 1970-01-01
              • 2014-10-31
              • 2023-03-20
              • 2017-09-08
              • 2018-11-05
              • 2017-07-29
              相关资源
              最近更新 更多