This post originated from an RSS feed registered with Java Buzz
by Alan Williamson.
Original Post: Do not use java.net.URL as a key in HashMap
Feed Title: Technical @ alan.blog-city.com
Feed URL: http://www.ibm.com/us/en/
Feed Description: (Technical) the rants of a java developer trapped in the body of a java developer!
I ran into a subtle problem last week that had me wondering if it was the fault of SyndFeedInfo from the ROME project, or java.net.URL.
Basically what I was doing was getting a list of RSS URLs to poll, creating an instance of SyndFeedInfo and putting them into a HashMap for later use. I key the collection on the instance of the URL; since thats the one that is unique.
HashMap feedsToRead = new HashMap();
for ( my list of 30 elements ){
SyndFeedInfo feedInfo = new SyndFeedInfo();
feedInfo.setUrl( new URL( (String)row.get(0)) );
feedInfo.setLastModified(Long.valueOf((String)row.get(1)).longValue());
feedInfo.setETag( (String)row.get(2) );
feedInfo.setFeedID( (String)row.get(3) );
feedsToRead.put( feedInfo.getUrl(), feedInfo );
System.out.println( "[" + feedsToRead.size() + "]" );
}
Now when I did this with a list of 30 urls (all different, although some on the same host); the HashMap will result in a size of 9 elements!
I re jigged things a little and used the java.lang.String of the URL toString() as the key, then my HashMap reports 30 elements at the end of the exercise. As it should.
This has been a bug that has gone undetected for weeks in my code base and only after looking at another bug, did I find this strange behavior. After discussing this on the ROME list, it would appear that using java.net.URL as an object key on a HashMap is a bad idea due its implementation of equals(), which basically returns true if on the same host. Although in my examples, the hosts were technically different even though they all shared the same top-level domain.
I had never thought of looking at the equals() method of a common Java object. Ironically, I always take care when using custom-written objects when working with collections, but this one slipped by me.