DevTools Hub

Search tools

Search for a developer tool

URL Encoding in Java

Part of the Encoding Toolkit

Java's most reached-for encoding class, java.net.URLEncoder, is not actually a general-purpose URL encoder — its own Javadoc says it's for application/x-www-form-urlencoded data. Using it to encode a URI path or a full URL is a common, quiet source of bugs. The general encoding rules are unchanged from URL Encoding Explained; this is about which Java class actually implements them.

URLEncoder is a form encoder, not a URI encoder

The tell is the space character — URLEncoder encodes it as +, the application/x-www-form-urlencoded convention, not the %20 a general URI encoder would produce:

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

URLEncoder.encode("hello world", StandardCharsets.UTF_8);
// "hello+world"

That's the same +-for-space convention covered in URL Encoding Explained — correct for a form field or a query parameter value, wrong if you use it on a path segment or a whole URL.

What that means in practice: running it on a whole URL breaks it

URLEncoder has no concept of URI structure — it encodes everything that isn't alphanumeric or one of a small safe set, including /, ?, and :. Run it on something that's already a path or URL and the structural characters go too:

URLEncoder.encode("/search?q=cats", StandardCharsets.UTF_8);
// "%2Fsearch%3Fq%3Dcats"   — not a usable path anymore

This is the exact same class of mistake as running encodeURIComponent on a whole URL in JavaScript instead of encodeURI — except Java doesn't offer a built-in "whole-URL" equivalent at all. URLEncoder is only ever correct for a single value.

A specific quirk: it escapes ~, even though the spec says not to

RFC 3986 marks ~ as unreserved — never needing escaping, alongside letters, digits, -, _, and .. URLEncoder escapes it anyway:

URLEncoder.encode("a*b.c-d_e~f", StandardCharsets.UTF_8);
// "a*b.c-d_e%7Ef"   — everything left alone except ~, which becomes %7E

Harmless — a decoder gets the right character back either way — but it's a good reminder that URLEncoder's safe set is its own, not a direct implementation of RFC 3986's unreserved characters, and won't byte-for-byte match what another language's encoder produces for the same input.

Always pass a Charset explicitly

URLEncoder and URLDecoder have older overloads that take no charset argument — those are deprecated precisely because they silently fall back to the JVM's platform default charset instead of UTF-8, which can differ between machines and produce different encoded output for the same non-ASCII input depending on where the code runs. Always use the two-argument form with an explicit StandardCharsets.UTF_8.

Building an actual URI: use java.net.URI, not URLEncoder

For constructing a real URI from separate components, the multi-argument URI constructor is the right tool — it quotes each component correctly for its position (path segment, query, and so on) rather than treating the whole thing as one opaque form value:

import java.net.URI;

URI uri = new URI("https", "example.com", "/search/a b", "q=c d", null);
uri.toASCIIString();
// "https://example.com/search/a%20b?q=c%20d"   — %20, not +, and the / stayed structural

Note the space here comes out as %20, not + — the URI constructor is quoting per RFC 2396/3986 rules, not the form-encoding convention URLEncoder uses. The path argument is treated as an already-formed path (its / characters stay as separators); it isn't a single-value encoder either — pass it a complete path, not a fragment you want treated as one opaque value.

Decoding: match the encoder you used

URLDecoder.decode is URLEncoder's exact counterpart — it treats both + and %20 as a space, so it round-trips either one correctly. The mismatch risk here is smaller than in Python, where quote and quote_plus have two separate, non-interchangeable decoders — Java only gives you the one pairing.

Try it yourself

Check what a value encodes to with URL Encode and URL Decode, or break down / assemble a full URL with URL Parser and URL Builder. All run entirely in your browser.

Related tools