1. Overview
In this short article, we’ll take a look at the main differences between URIs and URLs and implement examples to highlight those differences.
2. URI and URL
The difference between them is straightforward after knowing their definitions:
- Uniform Resource Identifier (URI) − a sequence of characters that allows the complete identification of any abstract or physical resource
- Uniform Resource Locator (URL) − a subset of URI that, in addition to identifying where a resource is available, describes the primary mechanism to access it
Now we can conclude that every URL is a URI, but the opposite is not true, as we’ll see later.
2.1. Syntax
Every URI, regardless if it’s a URL or not, follows a particular form:
scheme:[//authority][/path][?query][#fragment]
Where each part is described as follows:
- scheme − for URLs, is the name of the protocol used to access the resource, for other URIs, is a name that refers to a specification for assigning identifiers within that scheme
- authority − an optional part comprised of user authentication information, a host and an optional port
- path − it serves to identify a resource within the scope of its scheme and authority
- query − additional data that, along with the path, serves to identify a resource. For URLs, this is the query string
- fragment − an optional identifier to a specific part of the resource
To easily identify if a particular URI is also a URL, we can check its scheme. Every URL has to start with any of these schemes: ftp, http, https, gopher, mailto, news, nntp, telnet, wais, file, or prospero. If it doesn’t start with it, then it’s not a URL.
Now that we know the syntax, let’s look at some examples. Here is a list of URIs, where only the first three are URLs:
ftp://ftp.is.co.za/rfc/rfc1808.txt
https://tools.ietf.org/html/rfc3986
mailto:[email protected]
tel:+1-816-555-1212
urn:oasis:names:docbook:dtd:xml:4.1
urn:isbn:1234567890
3. URI and URL Java API Differences
In this section, we’ll demonstrate with examples the main differences between the URI and URL classes provided by Java.
3.1. Instantiation
Creating URI and URL instances is very similar, both classes provide several constructors that accept most of its parts, however, only the URI class has a constructor to specify all parts of the syntax:
@Test
public void whenCreatingURIs_thenSameInfo() throws Exception {
URI firstURI = new URI(
"somescheme://theuser:thepassword@someauthority:80"
+ "/some/path?thequery#somefragment");
URI secondURI = new URI(
"somescheme", "theuser:thepassword", "someuthority", 80,
"/some/path", "thequery", "somefragment");
assertEquals(firstURI.getScheme(), secondURI.getScheme());
assertEquals(firstURI.getPath(), secondURI.getPath());
}
@Test
public void whenCreatingURLs_thenSameInfo() throws Exception {
URL firstURL = new URL(
"http://theuser:thepassword@somehost:80"
+ "/path/to/file?thequery#somefragment");
URL secondURL = new URL("http", "somehost", 80, "/path/to/file");
assertEquals(firstURL.getHost(), secondURL.getHost());
assertEquals(firstURL.getPath(), secondURL.getPath());
}
The URI class also provides a utility method to create a new instance that does not throw a checked exception:
@Test
public void whenCreatingURI_thenCorrect() {
URI uri = URI.create("urn:isbn:1234567890");
assertNotNull(uri);
}
The URL class doesn’t provide such a method.
Since a URL has to start with one of the previously mentioned schemes, trying to create an object with a different one will result in an exception:
@Test(expected = MalformedURLException.class)
public void whenCreatingURLs_thenException() throws Exception {
URL theURL = new URL("otherprotocol://somehost/path/to/file");
assertNotNull(theURL);
}
There are other constructors in both classes, to discover them all, please refer to the URI and URL documentation.
3.2. Converting Between URI and URL Instances
Conversion between URI and URL is pretty straightforward:
@Test
public void givenObjects_whenConverting_thenCorrect()
throws MalformedURLException, URISyntaxException {
String aURIString = "http://somehost:80/path?thequery";
URI uri = new URI(aURIString);
URL url = new URL(aURIString);
URL toURL = uri.toURL();
URI toURI = url.toURI();
assertNotNull(url);
assertNotNull(uri);
assertEquals(toURL.toString(), toURI.toString());
}
However, trying to convert a non-URL URI results in an exception:
@Test(expected = MalformedURLException.class)
public void givenURI_whenConvertingToURL_thenException()
throws MalformedURLException, URISyntaxException {
URI uri = new URI("somescheme://someauthority/path?thequery");
URL url = uri.toURL();
assertNotNull(url);
}
3.3. Opening a Remote Connection
Since a URL is a valid reference to a remote resource, Java provides methods for opening a connection to that resource and obtain its contents:
@Test
public void givenURL_whenGettingContents_thenCorrect()
throws MalformedURLException, IOException {
URL url = new URL("http://courses.baeldung.com");
String contents = IOUtils.toString(url.openStream());
assertTrue(contents.contains("<!DOCTYPE html>"));
}
It should be noted that the implementation of the URL equals() and hashcode() functions may trigger the DNS naming service to resolve the IP address. This is inconsistent and can give different results depending on the network connection and also takes a long time to run. The implementation is known to be incompatible with virtual hosting and should not be used. We recommend using URI instead.
4. Conclusion
In this quick article, we presented a few examples to demonstrate the differences between URI and URL in Java.
We highlighted the differences when creating instances of both objects and while converting one object to the other. We also showed that a URL has methods to open a remote connection to the pointed resource.
As always, complete source code for this article can be found over on Github.