1

EDIT: FML! MY implementation of hashcode had a lowercase c. -.-

I've been trying to learn TDD and have been following the 'By Example' book by Kent Beck; it's very good!

However, I can't seem progress because a value is returning null when I access a hashtable. I've run a debug session and the object with the value is clearly there yet the result is null.

The code to build and access is:

public void addRate(String from, String to, int rate){
    this.rates.put(new Pair(from, to), new Integer(rate));
}

from and to are "GBP" and "USD". Also verified by debug.

Test case calling the above:

@Test
public void testreduceMoneyDifferentCurrency(){
    Bank bank = new Bank();
    bank.addRate("GBP", "USD", 2);
    Money result = bank.reduce(Money.gbpound(2), "USD");
    assertEquals(Money.dollar(1), result);
}

The reduce method in bank calls the method rate:

public Money reduce(Bank bank, String to){
    int rate = bank.rate(this.currency, to);
    return new Money(this.amount / rate, to);
}

Which is where the issue is:

    public int rate(String from, String to){
    if (from.equals(to)) return 1;
    Integer rate = (Integer) this.rates.get(new Pair(from, to));
    return rate.intValue();
}

The first line copes with USD -> USD conversions etc.

The Pair object is 2 strings built to be used as a key.

I've not used has tables a great deal but I can't see what the issue is, I know for certain that the values are in the hashtable but 'rate' is always returning a null value.

I can't see the wood for the trees. :) Could someone point me in the right direction please?

null
  • 3,469
  • 7
  • 41
  • 90

2 Answers2

9

I think the problem is in the Pair method. When you do this:

this.rates.get(new Pair(from, to));

you are creating a new instance of Pair, which is not the same as the one you've put into the map in the addRate method.

If you want the code to work correctly, you either have to use the same instance of Pair class or correctly implement equals and hashCode method on Pair class.

Here's a bit deeper insight into the inner working on HashMap and what you have to do to make it work: https://stackoverflow.com/a/6493946/2266098

Community
  • 1
  • 1
NeplatnyUdaj
  • 6,052
  • 6
  • 43
  • 76
  • He also needs to make `Pair` immutable. – Adam Arold Apr 28 '15 at 14:24
  • thank you, my equals method is: public boolean equals(Object object){ Pair pair = (Pair)object; return this.from.equals(pair.from) && this.to.equals(pair.to); } But, I'll now look at how I create and pass in the key, I have a direction so thank you for that! :D – null Apr 28 '15 at 14:31
  • With your equals method it should work, but you also need to provide the `hashCode` method, which will return same result for same values. To confirm that it is working, you could just make the hashCode() method which returns 0 all the time. Performance-wise this will reduce the HashMap to LinkedList, but you will fullfill the contract, which merely says that two objects must have the same hashCode if they are equals. – NeplatnyUdaj Apr 28 '15 at 14:33
  • @NeplatnyUdaj, ah, my hashcode does return 0. It's quite simply : public int hashcode(){ return 0; } – null Apr 28 '15 at 14:37
  • my hashcode method used a lowercase c. FML :) thank you for your help – null Apr 28 '15 at 14:51
0

Java keeps the reference of objects. So when you are trying to do this this.rates.get(new Pair(from, to)); you are basically creating a new instance of Pair which does not exists as a key in your HashMap.

articuno
  • 546
  • 5
  • 12