Posts Tagged ‘equals’
Comparing URLs with ‘URL.equals()’
Implementation of equals() in java.net.URL is based on a fancy rule saying that URLs of two hosts are equal as long as they are resolving to the same IP address. It is known to be incompatible with virtual hosting and should not be used.
For instance, URL.equals() would consider the URL of this blog (http://javaantipatterns.wordpress.com) to be equal to an URL of any random blog hosted on WordPress – that is obviously not true.
It is recommended to use java.net.URI objects instead.
P.S.
java.net.URL class is an absolute champion in a number of implemented antipatterns of equals() (and hashCode() as well):
- It lies
- It is incostistent
- It is slow and breakable
‘equals()’ and ‘hashCode()’ are context-sensitive
equals() and hashCode() implementations should rely only on an internal object state. Making them dependent on other objects, context of use and other external conditions conflicts with the general contracts of consistency:
“For any reference values
xandy, multiple invocations ofx.equals(y)consistently returntrueor consistently returnfalse” [*]
“Whenever it is invoked on the same object more than once during an execution of a Java application, the
hashCodemethod must consistently return the same integer” [*]
Violating those contracts may cause all kinds of weird and unpredictable behavior.
A known example of this antipattern is equals() and hashCode() in java.net.URL implementation where they are depending on information returned by a domain name server, rather than on actual stored URL data.
See also:
‘equals()’ does not check for null argument
If you override equals() method in your class, always check if an argument is null. If a null value is passed, equals() must unconditionally return false (no NullPointerException should be thrown!).
‘compareTo()’ is incompatible with ‘equals()’
If a class implements Comparable, compareTo() method must return zero if and only if equals() returns true for the same non-null argument (and vice versa). Violating this rule may cause unexpected behavior of the objects.
Using URLs in Collections
java.net.URL objects used as Map keys or Set items can result in a big performance issue. Internal implementation of equals() and hashCode() methods of java.net.URL class performs domain name resolution, so the time of their execution relies on an internet connection speed. If a computer is off-line, the time is nearly equal to a connection timeout (tens of seconds).
The same problem arises every time when URLs equality checking or hash code computation is performed.
Do not use java.net.URL to keep URL values. Use java.net.URI objects or the simple Strings instead.
‘equals()’ is overridden while ‘hashCode()’ is not
If you override equals() in your class, always provide a custom implementation of hashCode() that returns the same hash code value for two or more equal objects:
a.equals(b) → a.hashCode() == b.hashCode()
This is, in fact, a general contract defined by Java API Specification. Violation of this rule (which is likely the case if equals() method is overridden while hashCode() is inherited from Object) may cause numerous bugs and unexpected behaviours.
Note that the reverse rule: two or more unequal objects must have different hash codes, or
!a.equals(b) → a.hashCode() != b.hashCode()
though not required, is also highly recommended to be maintained wherever possible (except for the cases when a number of class instances is known to be greater than Integer.MAX_VALUE). Disregard of this rule (hash collisions) may reduce performance of HashMaps and Hashtables.