【问题标题】:Iterating through hashmap and creating unique objects - trying to prevent duplicates遍历 hashmap 并创建唯一对象 - 尝试防止重复
【发布时间】:2012-12-15 21:46:58
【问题描述】:

我在方法中的部分上方解释了我在 cmets 中尝试做的事情:

public int addPatron(String name) throws PatronException {
    int i = 0;
    //1. Iterate through a hashmap, and confirm the new name I am trying to add to the     record doesn't already exist in the hashmap
    for (Map.Entry<Integer, Patron> entry : patrons.entrySet()) {
        Patron nameTest = entry.getValue();
        //2. If the name I am trying to add already exists, we want to throw an exception saying as much.
        if (nameTest.getName() == name) {
            throw new PatronException ("This patron already exists");
            //3. If the name is unique, we want to get the largest key value (customer number) already in the hash, an increment by one.
        } else if (nameTest.getName() != name) {
            Map.Entry<Integer,Patron> maxEntry = null;
            for(Map.Entry<Integer, Patron> entryCheck : patrons.entrySet()) {
                if (maxEntry == null || entryCheck.getKey() > maxEntry.getKey()) {
                    maxEntry = entryCheck;
                    i = maxEntry.getKey();
                    i++;
                }
            }

        } else {
            throw new PatronException("Something's not working!");
        }
        //4. If everything is ok up to this point, we want to us the name and the new customer id number, and use those to create a new Patron object, which then gets added to a hashmap for this class which contains all the patrons.
        Patron newPatron = new Patron(name, i);
        patrons.put(i, newPatron);
    }
    return i;
}

当我尝试运行一个简单的单元测试时,如果我连续两次成功地为 addPatron 添加相同的名称,该单元测试将失败,测试失败。

try {
    testLibrary.addPatron("Dude");
    testLibrary.addPatron("Dude");
    fail("This shouldn't have worked");

测试失败,告诉我 addPatron 方法可以使用相同的名称两次。

@乔恩斯基特:

我的 Patron 类如下所示:

public class Patron {

//attributes
private String name = null;
private int cardNumber = 0;

//operations
public Patron (String name, int cardNumber){
    this.name = name;
    this.cardNumber = cardNumber;
}

public String getName(){
    return name;

}

public int getCardNumber(){
    return cardNumber;
}

}

【问题讨论】:

  • nameTest.getName() == name 应该是 nameTest.getName().equals(name)
  • 您似乎有一个 Map,但您应该有一个 Map
  • @DiegoBasch:应该,但这并不能解释失败的确切测试,因为使用了字符串文字(这将被实习)。
  • 如果 FIRST 条目的名称与给定名称不同,您还可以得出结论,该名称是唯一的。
  • @JonSkeet 这取决于 Patron 的构造函数在做什么。

标签: java hashmap


【解决方案1】:

正如其他人所说,使用== 比较字符串几乎肯定是不合适的。但是,它实际上不应该在您的测试用例中引起问题,因为您两次使用相同的常量字符串,所以 == 应该可以工作。当然,您仍然应该修复代码以使用equals

也不清楚Patron 构造函数或getName 方法的作用——其中任何一个都可能导致问题(例如,如果它们创建字符串的副本——这会导致你的测试失败,但通常也没有必要)。

让我稍微担心的是这条评论:

// 3. If the name is unique, we want to get the largest key value (customer number) 
// already in the hash, an increment by one.

这条评论主循环中。所以到那时我们不知道这个名字是唯一的 - 我们只知道它与此迭代中赞助人的名字不匹配

更令人担忧的是——我刚刚注意到这一点——你也在迭代块中执行了添加。在我看来,你应该有更多这样的东西:

public int addPatron(String name) throws PatronException {
    int maxKey = -1;

    for (Map.Entry<Integer, Patron> entry : patrons.entrySet()) {
        if (entry.getValue().getName().equals(name)) {
            // TODO: Consider using IllegalArgumentException
            throw new PatronException("This patron already exists");
        }
        maxKey = Math.max(maxKey, entry.getKey());
    }
    int newKey = maxKey + 1;
    Patron newPatron = new Patron(name, newKey);
    patrons.put(newKey, newPatron);
    return newKey;
}

此外,听起来真的您想要一张从姓名到赞助人的地图,可能还有从 id 到赞助人的地图。

【讨论】:

  • 这种改变正是我们所需要的 +1+1+1 :)
【解决方案2】:

你需要使用equals来比较java中的String对象,而不是==。所以替换:

if (nameTest.getName() == name) {

与:

if (nameTest.getName().equals(name)) {

【讨论】:

  • 但是 != 对于不等于还是可以的?
  • 不,你应该使用 if(!(nameTest.getName().equals(name))。更好的是,使用 else。它要么相等,要么不相等,没有其他选项。你可以信任那个 JVM。:)
【解决方案3】:

尝试使用

nameTest.getName().equals(name)

而不是

nameTest.getName() == name

因为现在您要比较的是引用而不是字符串的值。 it's explained here

重新审视您的代码

好吧,我再次查看了您的代码,问题是,您的 HashMap 在测试开始时为空。所以循环永远不会运行 ==> 永远不会添加赞助人或抛出异常。

【讨论】:

    【解决方案4】:

    问题的原因是您如何使用比较运算符==

    当你对两个对象使用这个操作符时,你测试的是那个变量指向同一个reference

    要测试两个对象的值是否相等,您应该使用equals() 方法或compareTo(如果有)。

    对于 String 类,调用 equals 足以检查存储相同的字符 more

    What is equals method ?

    比较对象的值 问题是你如何比较名字。

    【讨论】:

    • == 对于非基元是 valid - 它只是对引用具有非常特定的含义(检查引用身份)。此外,Map 不使用Patron 作为键,因此hashCodeequals 在那里无关紧要。
    • 在我的定义中是允许的,但不会返回预期的(对于这种情况)结果,对于这种类型的比较是无效的。有时使用简单的词,提供更好的理解。关于 hashCode 和 equals。它们可能与代码示例无关,但可能更容易解决 OP 的问题。但无论如何,在 SO 规则中,否决票更有效;-)。
    • Anything 只能根据要求视为有效或无效。在某些情况下,将引用与== 进行比较正是您想要的。我同意这里不合适,但我仍然不会声称使用 == 是“无效的”。
    • @JonSkeet,你说得对,但我认为你认为我不知道操作员是如何工作的。我承认,对于您所了解的人来说,在整个描述中缺乏上下文可能会导致这种解释。但我没有删除这篇文章的唯一原因是我想知道你会如何使用 operator == 进行字符串比较操作?
    • 我会准确地说出它的作用:它比较对象身份的引用。这通常不是你想要的,但它仍然是一个有效的运算符。它不像它有未定义的行为或类似的东西。我不评论你知道的 - 我只能评论你写的
    猜你喜欢
    • 2018-05-11
    • 2010-11-07
    • 2014-09-19
    • 2018-01-25
    • 2021-11-15
    • 1970-01-01
    • 1970-01-01
    • 2018-10-15
    • 1970-01-01
    相关资源
    最近更新 更多