Understanding URLs vs URIs, and What Makes Up a URL
Part 3 of 12 in Mastering Java Network Programming
The terms URI, URL, and URN are often used interchangeably in casual conversation — but they mean different things, and confusing them leads to subtle bugs when parsing or validating identifiers.
A URI (Uniform Resource Identifier) is the superset: any string that identifies a resource. A URL is a URI that also tells you where to find the resource — it encodes a network location and protocol. A URN (Uniform Resource Name) identifies a resource without saying how to locate it; think of it as a persistent name rather than a pointer.
In Java’s java.net package this hierarchy is reflected in two separate classes: URI parses, validates, and exposes the components of any URI string, while URL requires a registered network protocol handler and can only be constructed from strings whose scheme is known to the JVM.
Every URL is also a valid URI, but not every URI is a valid URL. The example below drives this home, then walks through all five URL components.
The code
import java.net.URI;
import java.net.URL;
import java.net.MalformedURLException;
public class UrlDemo {
private static final String URN_STR = "urn:isbn:978-0321349606";
private static final String[] URL_STRS = {
"https://www.example.com:8443/path/to/resource?key=value&foo=bar#section",
"ftp://[email protected]/pub/docs/readme.txt",
"http://192.168.1.1/api/v2/status",
"mailto:[email protected]"
};
public static void main(String[] args) throws Exception {
// Part 1 — URN is a URI but not a URL
URI uri = new URI(URN_STR); // succeeds
try { new URL(URN_STR); } // MalformedURLException: unknown protocol: urn
// Part 2 — break down every component for several URLs
for (String urlStr : URL_STRS) {
URI u = new URI(urlStr);
System.out.println(u.getScheme());
System.out.println(u.getAuthority());
System.out.println(u.getPath());
System.out.println(u.getQuery());
System.out.println(u.getFragment());
}
// Part 3 — authority subdivisions: userinfo, host, port
// Also covers IPv6 brackets and encoded passwords.
}
}
Running it
The output makes three points clear.
First, the URN urn:isbn:978-0321349606 parses into a valid URI but fails with MalformedURLException: unknown protocol: urn when fed to java.net.URL. This confirms that not every identifier is a locator — the JVM simply doesn’t know how to resolve the urn scheme.
Second, every URL-like string also parses as a valid URI. Java’s URI class handles HTTPS, FTP, HTTP (even with an IP address host), and even mailto: without complaint. All four produce proper five-component breakdowns:
- The full HTTPS example shows all five components populated: scheme (
https), authority (www.example.com:8443), path (/path/to/resource), query (key=value&foo=bar), and fragment (section). - The FTP URL reveals the authority splitting into userinfo (
anonymous) and host (files.example.com), with no explicit port. - The IPv4 host case (
http://192.168.1.1/api/v2/status) demonstrates that IP addresses work just fine as hosts — no hostname resolution needed at parse time. mailto:[email protected]is the outlier: despite containing an@, it has no authority becausemailto:doesn’t use the authority section; the email address lives in the scheme-specific part instead. This is a common gotcha for anyone assuming every@marks userinfo.
Third, the authority subdivision examples show that IPv6 addresses must be bracketed ([::1]) and Java’s URI.getHost() strips those brackets correctly. Encoded characters in userinfo (like %40 decoding to @) also parse through without issue — p%40ss becomes the raw string p@ss in the extracted value.
Takeaway
A URI identifies a resource; a URL adds how to reach it. When you need to validate or parse identifiers, use java.net.URI — it handles everything that Java’s URL class can plus URNs and custom schemes without requiring a network protocol handler. The five components of a URL (scheme, authority → userinfo/host/port, path, query, fragment) map directly onto the URI getter methods, but don’t assume every identifier with an @ has an authority — scheme-specific parsing rules apply before the authority section is even considered.