If you ever were working on a Java application that had anything to do with the web you are probably familiar with java.net.URL class. I have a puzzle for you then: let’s say in your application you refer to JavaBlogging site with two URL using slightly different host name. Will those URL objects be equal to each other? See the following code snippet:

1:
2:
3:
4:
5:
6:
7:
public static void main(String[] args) throws Exception {

    URL url1 = new URL("http://www.javablogging.com");
    URL url2 = new URL("http://javablogging.com");

    System.out.println(url1.equals(url2));
}

So what will get printed out? One could argue that those links refer to the same site so we should get ‘true’… but on the other hand the address spelling is different so maybe the correct answer is ‘false’? You may not be decided which solution is the right one, but since its a deterministic code we know at least that one of them is correct… right?

Wrong! You may get either ‘true’ or ‘false’. The strange thing is that the result does not depend on JVM, on your machine specifics or Java version, but… on whether or not you are connected to the Internet!

This strange behavior is explained partially in URL JavaDoc (Doh!): one of the conditions for the two URLs to be considered equal is that the host names are resolved to the same IP. Therefore first step in checking for equality is resolving the IP address and this can be done only with Internet connection. Without it the host names are compared as Strings.

What are the consequences of this behavior, besides all of the confusion? One thing is that because of the IP resolution the equals() method for URL is very slow. What is even worse the equals() method is inconsistent and therefore breaking the Object.equals() contract! (see the requirements for equals() method for comparison)

Now check out the following ‘improvement’ to the code:

1:
2:
3:
4:
5:
6:
7:
8:
9:
public static void main(String[] args) throws Exception {

    URL url1 = new URL("http://www.javablogging.com");
    URL url2 = new URL("http://javablogging.com");

    while (true) {
        System.out.println(url1.equals(url2));
    }
}

disconnect yourself from Internet, run the code, connect again and enjoy URL changing its mind about the result of equality!

So what is the lesson from all of this? Remember that URL is cheating and its implementation of equals breaks the contract stated in Object class. Therefore URL should never be used in situations when it can be tested for equality as the results may be unpredictable. Beware of using it with collections: not use it as a Map key or as an element of Set or you may get yourself in trouble…