参照: http://stackoverflow.com/questions/2348399/why-does-java-net-urls-hashcode-resolve-the-host-to-an-ip
公式ドキュメントによると:
public boolean equals(Object obj)
…
2 つの URL オブジェクトが等しいのは、同じプロトコルを持ち、同じホストを参照し、ホスト上のポート番号が同じで、ファイルとファイルのフラグメントが同じ場合です。
2 つのホストが等価と見なされるのは、両方のホスト名が同じ IP アドレスに解決されるか、どちらかのホスト名を解決できない場合は、大文字小文字に関係なくホスト名が等しいか、両方のホスト名が null に等しい場合です。
ホスト比較には名前解決が必要なので、この操作はブロック操作です。
もちろん等価性に依存するhashCode()
などもこの影響を受けるので、うっかりコレクションにURL
を格納すると大量の名前解決が発生して死ぬほど遅くなる。
代替案:java.net.URI
を使う
ではどうするのがいいかというと、java.net.URI
のほうを使うと名前解決しないので良いです。
基本的には同じような操作が可能ですが、java.net.URL
より書式に厳密なので注意。不正な文字列を与えるとjava.net.URISyntaxException
になります。
よくある日本語文字列がそのまま入ったURLなどもアウトなので、事前にjava.net.URLEncoder
などを使ってダメな文字をエスケープする必要があります。
別の代替案:URLStreamHandler
を明示的に指定してURL
を構築する
ホスト比較時の動作はURLStreamHandler
を使ってるようなので、名前解決しない実装を作成してURL(String protocol, String host, int port, String file, URLStreamHandler handler)
等のコンストラクタに明示的に渡すようにすれば良いと思われます(未確認)。こっちのほうが影響範囲は少なそう。