Javaでの開発に携わって、過去にURLエンコードのトラブルで痛い目を見た経験は一度や二度ではありません。
API連携の実装中、特定の日本語キーワードだけ検索結果が0件になる不具合に遭遇しました。
原因は単純な「エンコード漏れ」でしたが、解決に丸一日を費やしてしまった苦い記憶があります。
この記事を読めば、JavaにおけるURLエンコードの正しい実装方法が身につきます。
文字化けや通信エラーの原因となる「やってはいけない実装」を回避し、安全なWeb通信プログラムを書けるようになるはずです。
JavaのURLエンコードとは?仕組みと必要性をわかりやすく解説

URLエンコードとは、URLとして使用できない文字を、インターネット上で安全に送信できる形式へ変換する処理です。
Webブラウザやサーバーは、URLに含まれる文字を特定のルールに従って解釈します。
日本語や特殊記号がそのまま混ざっていると、通信先が正しく理解できずエラーや誤作動を引き起こしかねません。
URLエンコードの基本(何を、なぜ変換するのか)
URLエンコードでは、日本語(マルチバイト文字)や一部の記号を「%」と「16進数の数値」の組み合わせに変換します。
インターネットの住所であるURLは、基本的に「半角英数字」と「一部の記号」だけで構成されなければなりません。
このルールを守るために変換が必要です。
たとえば、「東京」という文字をUTF-8でURLエンコードすると「%E6%9D%B1%E4%BA%AC」になります。
一見すると意味不明な文字列ですが、コンピュータにとってはこれが最も読み取りやすい形式です。
URLとして安全に表現できる形式に変換することが、URLエンコードの本質です。
変換対象となるのは主に以下の文字です。
- ひらがな、カタカナ、漢字などの全角文字
- スペース(空白)
- 「&」「?」「=」などの予約文字(URLの構造として特別な意味を持つ記号)
これらをそのまま送信してしまうと、サーバーはどこまでがパラメータで、どこからが別の命令なのか判断できません。
正しい通信を行うには、送信側できちんと変換処理を施す準備が不可欠です。
HTTP通信におけるURLエンコードの役割
HTTP通信において、URLエンコードはリクエストの意図を正確に伝えるための「封筒」のような役割を果たします。
Webシステムでは、クライアント(ブラウザやスマホアプリ)からサーバーへ情報を送る際、GETリクエストなどを利用してURLの後ろにデータを付与します。
たとえば検索機能を作る場合を想像してください。
「Java 入門」というキーワードで検索する際、URLは以下のようになります。
もしエンコードせずに q=Java 入門 とそのまま送ると、サーバーは「Java」の後ろにあるスペースで「URLはここで終わりだ」と誤解する恐れがあります。
あるいはスペース以降を不正なリクエストと見なして通信を遮断するかもしれません。
HTTP通信を成立させるには、ルールに則った形式でデータを渡すマナーが求められます。
URLエンコードしないと起きるトラブル例
適切にエンコードを行わない場合、システムは予期せぬ動作を引き起こします。
代表的なトラブルは以下の3つです。
- 文字化け:サーバーが受け取ったデータを正しく復元できず、「????」や「」のような無意味な記号の羅列になってしまいます。データベースへの保存時にデータが壊れる原因にもなり、復旧が困難になるケースも少なくありません。
- パラメータの消失:「&」などの記号を含んだ文字列を送る場合に発生します。たとえば「Q&A」という文字列を送りたいのに、システムが「&」を「次のパラメータの区切り」と勘違いしてしまいます。結果として「Q」しか届かず、「A」が消えてしまうバグにつながります。
- セキュリティリスク(インジェクション攻撃):特殊文字を適切に処理しないと、悪意のある第三者がURLに不正なコマンドを埋め込む隙を与えかねません。アプリケーションの安全性を保つためにも、入力値のエンコードは防御壁として機能します。
JavaでURLエンコードを行う方法【標準ライブラリ】

Javaには標準でURLエンコードを行うためのクラスが用意されています。
特別な外部ライブラリを導入しなくても、基本的な機能はJDKだけで実装可能です。
ここではJava11以降でも通用する、標準的な実装方法を解説します。
URLEncoder.encodeの使い方と基本構文
Javaで文字列をURLエンコードするには、java.net.URLEncoder クラスを使用します。
最も基本的な使い方は、encode メソッドに「変換したい文字列」と「文字コード」を渡すだけです。
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
public class Main {
public static void main(String[] args) {
try {
String original = "Java 開発";
// エンコード実行
String encoded = URLEncoder.encode(original, StandardCharsets.UTF_8);
System.out.println("変換前: " + original);
System.out.println("変換後: " + encoded);
} catch (Exception e) {
e.printStackTrace();
}
}
}このコードを実行すると、「Java+%E9%96%8B%E7%99%BA」のように変換された文字列が取得できます(スペースは「+」に変換されます)。
(スペースの扱いについては後述します)
try-catch ブロックで囲んでいるのは、指定した文字コードが存在しない場合に例外が発生する可能性があるからです。
UTF-8を指定すべき理由
URLEncoder.encode の第二引数には、必ず文字エンコーディングを指定します。
現代のWeb開発において、ここは迷わず StandardCharsets.UTF_8 を指定してください。
理由は単純で、Webの世界における標準文字コードがUTF-8だからです。
かつては「Shift_JIS」や「EUC-JP」が使われることもありました。
しかし現在は、ブラウザ、サーバー、データベースのほとんどがUTF-8を前提に設計されています。
ここで異なる文字コードを指定してしまうと、サーバー側でデコード(復元)する際に文字コードの不一致が起き、確実に文字化けします。
古いJavaのコードでは、文字コードを文字列で "UTF-8" と書いている例を見かけます。
しかしタイポ(入力ミス)を防ぐためにも、定数である StandardCharsets.UTF_8 を使うのがベストプラクティスです。
URLDecoder.decodeの仕組みと注意点
エンコードの対になる処理がデコードです。
java.net.URLDecoder クラスを使うことで、エンコードされた文字列を元の日本語に戻せます。
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
public class DecodeExample {
public static void main(String[] args) {
try {
String encoded = "Java+%E9%96%8B%E7%99%BA";
// デコード実行
String decoded = URLDecoder.decode(encoded, StandardCharsets.UTF_8);
System.out.println("復元後: " + decoded);
} catch (Exception e) {
e.printStackTrace();
}
}
}注意点はエンコード時と同じ文字コードを指定することです。
エンコードをUTF-8で行ったのに、デコードをShift_JISで行えば、元の文字には戻りません。
送信側と受信側でルールを統一させる意識を持ちましょう。
JavaのURLエンコードでよくあるエラーと対策

実装自体はシンプルですが、現場ではいくつかの典型的なエラーに遭遇します。
これらは知っていればすぐに解決できますが、知らないと原因特定に時間がかかる厄介な問題です。
UnsupportedEncodingException が出る原因
URLEncoder.encode を使う際、IDE(統合開発環境)から「例外処理を記述してください」と警告が出ます。
これは UnsupportedEncodingException というチェック例外が定義されているためです。
この例外は「指定された文字コードをシステムがサポートしていない場合」に投げられます。
しかし StandardCharsets.UTF_8 を使っている限り、Javaの実行環境でUTF-8がサポートされていない状況はまずあり得ません。
実質的には発生しない例外ですが、Javaの仕様上、try-catch が必要になります。なお、Java 10以降では URLEncoder.encode(String, Charset) のオーバーロードを使えばチェック例外が発生しないため、try-catch は不要です。Java 9以前では依然として例外処理が必要です。
コードを簡潔に保ちたい場合は、メソッド定義に throws Exception を追加して例外を呼び出し元に委譲するか、RuntimeException でラップして投げ直す方法が一般的です。
二重エンコード問題とは?チェック方法と防ぎ方
二重エンコードとは、すでにエンコード済みの文字列に対して、再度エンコード処理を行ってしまうミスです。
たとえば「%」という文字自体も「%25」にエンコードされます。
「あ」をエンコードして「%E3%81%82」になった文字列を、もう一度エンコードするとどうなるでしょうか。
「%」の部分がさらに変換され、「%25E3%2581%2582」という別の文字列に変わってしまいます。
これを受信側で一度だけデコードしても、「%E3%81%82」という文字列に戻るだけで、「あ」には戻りません。
画面に「%E3...」のような謎の文字列が表示されている場合、この二重エンコードを疑ってください。
防ぐ方法はシンプルです。
「エンコードは通信の直前に一度だけ行う」というルールを徹底します。
変数の受け渡しをしているうちに、どこでエンコードされたか分からなくなる設計は避けましょう。
変数の命名規則を工夫し、エンコード済みの変数には encodedUrl のような名前を付けるのも有効な対策です。
スペースの「+」と「%20」の違いを理解する
Javaの URLEncoder を使っていて最も混乱するのが、スペース(空白)の扱いです。
標準の URLEncoder は、半角スペースを「+」記号に変換します。
しかし、RFC3986に基づくパーセントエンコーディングでは、スペースは「%20」に変換されます(「+」は許容されません)。「+」はHTMLフォームの application/x-www-form-urlencoded 形式でのみ使われる表現です。
- application/x-www-form-urlencoded(HTMLフォームなど): スペースは「+」になる
- RFC3986(URLパスなど): スペースは「%20」になる
Javaの標準ライブラリは前者のフォーム送信仕様に基づいています。
接続先のAPIによっては、「+」を受け取ってもスペースとして認識してくれず、エラーになる場合があります。
もしAPIが「%20」を要求している場合は、変換後に置換処理を入れる必要があります。
String encoded = URLEncoder.encode("Java User", StandardCharsets.UTF_8);
// "Java+User" になるので、"+" を "%20" に置換
encoded = encoded.replace("+", "%20");この仕様の違いは非常にハマりやすいポイントなので、必ず頭の片隅に入れておいてください。
JavaのURLエンコードとライブラリ比較

標準ライブラリ以外にも、より便利で強力なライブラリが存在します。
プロジェクトの規模や用途に合わせて、最適なものを選択できるようになりましょう。
Java標準(URLEncoder)とApache Commonsの違い
Java標準の URLEncoder は手軽ですが、前述の通りスペースを「+」に変換する仕様や、例外処理の記述が面倒という欠点があります。
そこでよく使われるのが、Apache Commons Codecライブラリです。
Apache Commonsを使うと、より厳密な規格に沿ったエンコードが可能になります。
しかし、単にURLエンコードをするためだけに巨大なライブラリを追加するのは、依存関係を増やすリスクもあります。
すでにプロジェクトにApache Commonsが含まれているなら利用を検討し、そうでなければ標準ライブラリで十分なケースが多いです。
Spring WebのUriComponentsBuilderを使うメリット
Spring Frameworkを使用しているなら、UriComponentsBuilder が最強の選択肢です。
これはURLを組み立てるための専用ユーティリティで、パスやクエリパラメータのエンコードを自動的かつ適切に行ってくれます。
import org.springframework.web.util.UriComponentsBuilder;
String url = UriComponentsBuilder.fromHttpUrl("https://example.com/search")
.queryParam("q", "Java 入門")
.toUriString();
System.out.println(url);
// https://example.com/search?q=Java%20%E5%85%A5%E9%96%80最大のメリットは、スペースを適切に「%20」として扱ってくれる点と、個別にエンコード関数を呼ぶ手間が省ける点です。
可読性も圧倒的に高くなるため、Spring環境下ではこの方法を一択で推奨します。
用途別のおすすめエンコード方法
状況に応じて使い分ける指針をまとめます。
- Spring Frameworkを使っている場合:UriComponentsBuilder を利用する。最も安全でコードも綺麗に保てます。
- Java標準のみで実装する場合:URLEncoder を利用し、必要に応じて「+」を「%20」に置換する。外部ライブラリに依存したくない小規模なツールや、学習目的の場合に適しています。
- 厳密なRFC準拠が必要な場合:Apache Commonsなどの専用ライブラリ、または自作のエンコードメソッドを用意する。特殊な認証APIなど、1バイトの差異も許されないシビアな環境で必要になります。
JavaでURLエンコードを使う具体例

ここからは、実際の開発現場でよく使われるコードパターンを紹介します。
コピペして使えるレベルの実践的な内容にしました。
クエリパラメーターを安全に組み立てる方法
複数の検索条件をURLパラメータとして結合する場合、文字列連結(+演算子)を使うのは避けましょう。
可読性が下がるうえに、エンコード漏れのリスクが高まります。
Map を使ってパラメータを管理し、ループ処理で結合する方法がスマートです。
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
public class QueryParamBuilder {
public static void main(String[] args) {
Map<String, String> params = new HashMap<>();
params.put("keyword", "Java エンコード");
params.put("category", "プログラミング");
params.put("page", "1");
String queryString = params.entrySet().stream()
.map(entry -> {
try {
return URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8) + "=" +
URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8);
} catch (Exception e) {
throw new RuntimeException(e);
}
})
.collect(Collectors.joining("&"));
System.out.println("https://example.com/api?" + queryString);
}
}この方法ならパラメータが増えてもコードを変更する必要がなく、すべての値に対して確実にエンコードが適用されます。
APIリクエストURLを組み立てる実践コード
外部APIを呼び出す際、パスの一部(URLの途中)に変数を埋め込むケースがあります。
たとえば https://api.example.com/users/{userId}/details のような形式です。
この {userId} に記号が含まれる可能性がある場合、ここもエンコードが必要です。
String userId = "user/123"; // スラッシュが含まれるID
String baseUrl = "https://api.example.com/users/";
// パスパラメータとして埋め込む場合もエンコードする
String encodedId = URLEncoder.encode(userId, StandardCharsets.UTF_8);
String requestUrl = baseUrl + encodedId + "/details";
System.out.println(requestUrl);
// https://api.example.com/users/user%2F123/detailsもしエンコードせずに結合すると、users/user/123/details となり、サーバーは「user」と「123」という2つの階層があると勘違いしてしまいます。
パスの一部として値を埋め込む際も、エンコードは必須です。
フォーム送信値をURLエンコードするケース
HTMLフォームからPOST送信されるデータは、ブラウザが自動的に application/x-www-form-urlencoded 形式に変換してくれます。
しかし、JavaプログラムからPOSTリクエストを送信する場合(HttpClient などを使用する場合)、この変換を自前で行う必要があります。
Java11から導入された HttpClient を使う場合、以下のようにBodyを生成します。
import java.net.http.HttpRequest;
import java.net.URI;
// 前述のQueryParamBuilderのロジックで作成した文字列を使用
String formData = "name=" + URLEncoder.encode("山田 太郎", StandardCharsets.UTF_8) +
"&email=" + URLEncoder.encode("taro@example.com", StandardCharsets.UTF_8);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://example.com/register"))
.header("Content-Type", "application/x-www-form-urlencoded")
.POST(HttpRequest.BodyPublishers.ofString(formData))
.build();ここでエンコードを忘れると、受信側のサーバーで正しくデータを取り出せず、登録処理が失敗する原因になります。
まとめ|JavaのURLエンコードのポイント整理
JavaにおけるURLエンコードは、Web開発における「交通ルール」のようなものです。
正しく守れば安全に目的地(サーバー)までデータを届けられますが、無視すると事故(エラー)につながります。
最後に、これだけは覚えておいてほしい重要ポイントを3つに絞って復習します。
必ずUTF-8を使う理由
文字コードの指定には、迷わず StandardCharsets.UTF_8 を使用してください。
理由は、現代のWeb標準がUTF-8であり、それ以外を使うと文字化けのリスクが極めて高くなるから。
古いシステム改修などでShift_JISの指定を求められない限り、UTF-8一択で間違いありません。
二重エンコードを避ける基本ルール
エンコード処理は「送信する直前に、一度だけ」行うのが鉄則です。
理由は、多重にエンコードするとデコードしても元の文字列に戻せなくなるから。
コード内のあちこちでエンコードするのではなく、通信用のURLを生成する箇所でまとめて処理する設計を心がけましょう。
用途別に最適なエンコード方式を選ぼう
Java標準の URLEncoder は便利ですが、スペースが「+」になるという特徴があります。
Spring Frameworkを使っているなら UriComponentsBuilder を使い、そうでない場合は標準ライブラリの特性を理解した上で使い分けることが重要です。
接続先のAPIが何を求めているか(%20なのか+なのか)を仕様書で確認する癖をつけると、トラブルを未然に防げます。
URLエンコードは地味な処理に見えますが、ここを疎かにするとシステム全体の信頼性が揺らぎます。
今回紹介した知識を活用して、文字化けや通信エラーのない堅牢なJavaアプリケーションを開発してください。