简体   繁体   English

通过Hashtable迭代的无限循环

[英]Infinite Loop Iterating Through Hashtable

I'm trying find the most popular word in an array using Hashtables. 我正在尝试使用Hashtables在数组中找到最流行的单词。 For some reason the while loop is looping infinitely. 由于某种原因,while循环无限循环。 I've debugged and the element never changes from the first one it gets. 我已经调试了,元素永远不会从它得到的第一个变化。 Any ideas on why this is happening? 有关为什么会发生这种情况的任何想法?

Here is my code: 这是我的代码:

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;
  }
}

You're calling wordsHash.keys() on each iteration of the loop, which gives you a fresh Enumeration<String> on each iteration - you're then calling it again inside the loop. 你在循环的每次迭代中调用wordsHash.keys() ,这会在每次迭代时给你一个新的Enumeration<String> - 然后你在循环再次调用它。

You want to call it once , and then iterate over the single Enumeration<String> : 您想要调用一次 ,然后遍历单个Enumeration<String>

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

Note that as you're also getting the value for each element, you'd be better off iterating over the entrySet() rather than the keys() . 请注意,因为您还获得了每个元素的值,所以最好迭代entrySet()而不是keys()

You'd also be better off using HashMap instead of Hashtable , as then you could just use an enhanced for loop... 你最好还是使用HashMap而不是Hashtable ,因为你可以使用增强的for循环......

The problem is in line 问题是符合的

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

each time through the loop, you are getting a new copy of the enumeration. 每次循环时,您都会获得枚举的新副本。 You'll want to get the keyset once, and iterate over that. 您将需要获取一次密钥集,并对其进行迭代。

It would probably be easier to use an enhanced for Loop here as well 在这里使用增强的for循环可能更容易

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

This should provide the behavior you want, while being simpler and easier to read. 这应该提供您想要的行为,同时更简单,更容易阅读。

The problem is that whenever you call wordsHash.keys() , it returns a new enumeration: 问题是无论何时调用wordsHash.keys() ,它都会返回一个新的枚举:

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

What you need to do is create a single enumeration and use it throughout the loop. 您需要做的是创建一个枚举并在整个循环中使用它。

PS Why are you using Hashtable and not HashMap ? PS你为什么使用Hashtable而不是HashMap

Every call to .keys() returns a new enumeration, with a new internal pointer for iterating: 每次调用.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

So assign your keys enumeration to a variable: 因此,将keys枚举分配给变量:

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

}

Change your code to: 将您的代码更改为:

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

So that a new enumeration pointing to the first key of the HashTable is not created every time that you enter the loop. 因此,每次进入循环时都不会创建指向HashTable的第一个键的新枚举。

Nothing is modifying the wordsHash . 什么都没有修改wordsHash That means that if wordsHash.keys().hasMoreElements() is true once, it'll continue to be true for the rest of the program. 这意味着如果wordsHash.keys().hasMoreElements()为真一次,则对于程序的其余部分,它将继续为真。 This causes an infinite loop. 这会导致无限循环。 You either need to remove the keys as you go along or you should just use a for 您需要在进行时删除密钥,或者只需使用for

you get a new Iterable ofer all keys each loop iteration: wordsHash.keys() as long as there is at least one key in it the while loop never ends. 你得到一个新的Iterable ofer每个循环迭代的所有键: wordsHash.keys()只要其中至少有一个键,while循环永远不会结束。

Replace: 更换:

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

by 通过

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

Also, unrelated to your Enumeration issue, this is probably a defect: 此外,与您的枚举问题无关,这可能是一个缺陷:

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

That's a reference comparison of a java.lang.Integer to another java.lang.Integer. 这是java.lang.Integer与另一个java.lang.Integer的参考比较。 It is not a comparison of the actual values they represent. 它不是它们所代表的实际值的比较。 It is working for "small" numbers because auto-boxing uses cached references, but will eventually break. 它适用于“小”数字,因为自动装箱使用缓存的引用,但最终会破坏。 You probably want: 你可能想要:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM