概要

Base64 エンコードは、メール添付・REST API のトークン受け渡し・画像のインライン埋め込みなど、バイナリデータをテキストとして安全にやり取りする場面で頻繁に使われます。Java 8 以降は java.util.Base64 が標準で用意されており、外部ライブラリなしで3種類のエンコード方式(標準・URL セーフ・MIME)を使い分けることができます。この記事では、文字列の往復変換、URL に含めても壊れない URL セーフ Base64、バイナリデータの変換といった実務で必要になるパターンを整理します。パディングの有無による挙動の違いや、文字コードの指定を忘れたときに起きる問題など、初見で引っかかりやすいポイントも取り上げます。

使いどころ

REST API の認証ヘッダーにユーザー名とパスワードを Base64 エンコードして Basic 認証トークンを組み立てる

アップロードされた画像ファイルを Base64 文字列に変換し、JSON レスポンスにインラインで埋め込む

URL のクエリパラメータに構造化データを渡すため、JSON 文字列を URL セーフ Base64 でエンコードする

コード例

Base64EncodingExample.java
import java.util.Base64;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

public class Base64EncodingExample {

    /** 文字列を Base64 エンコードして返す */
    public static String encode(String text) {
        var bytes = text.getBytes(StandardCharsets.UTF_8);
        return Base64.getEncoder().encodeToString(bytes);
    }

    /** Base64 文字列をデコードして返す */
    public static String decode(String encoded) {
        var bytes = Base64.getDecoder().decode(encoded);
        return new String(bytes, StandardCharsets.UTF_8);
    }

    /** URL セーフ Base64 エンコード(パディングなし) */
    public static String encodeUrlSafe(String text) {
        var bytes = text.getBytes(StandardCharsets.UTF_8);
        return Base64.getUrlEncoder().withoutPadding().encodeToString(bytes);
    }

    /** URL セーフ Base64 デコード */
    public static String decodeUrlSafe(String encoded) {
        var bytes = Base64.getUrlDecoder().decode(encoded);
        return new String(bytes, StandardCharsets.UTF_8);
    }

    /** バイナリデータの Base64 往復変換 */
    public static boolean verifyBinaryRoundTrip(byte[] data) {
        var encoded = Base64.getEncoder().encodeToString(data);
        var decoded = Base64.getDecoder().decode(encoded);
        return Arrays.equals(data, decoded);
    }

    public static void main(String[] args) {
        // 文字列の往復変換
        var original = "Hello, java-recipes! 日本語テスト";
        var encoded = encode(original);
        var decoded = decode(encoded);
        System.out.println("元の文字列: " + original);
        System.out.println("エンコード: " + encoded);
        System.out.println("デコード:   " + decoded);
        System.out.println("一致:       " + original.equals(decoded));

        // URL セーフ Base64
        var urlSafe = encodeUrlSafe("test/path?key=value&other=123");
        System.out.println("URL セーフ: " + urlSafe);
        System.out.println("デコード:   " + decodeUrlSafe(urlSafe));

        // バイナリデータの往復確認
        var binary = new byte[]{0x00, 0x01, 0x02, (byte) 0xFF, (byte) 0xFE};
        System.out.println("バイナリ往復: " + verifyBinaryRoundTrip(binary));
    }
}

Java 8 / 17 / 21 の完全なサンプルコードは GitHub リポジトリ で確認できます。

Version Coverage

API 自体は Java 8 と同じだが、var による型推論と record で結果をまとめて返すコードが書ける。テキストブロックとの組み合わせも自然。

Java 17
// Java 17: var + record で結果をまとめる
record EncodingResult(String original, String encoded, String decoded) {}
var bytes = text.getBytes(StandardCharsets.UTF_8);
var encoded = Base64.getEncoder().encodeToString(bytes);
var decoded = new String(Base64.getDecoder().decode(encoded), StandardCharsets.UTF_8);
var result = new EncodingResult(text, encoded, decoded);

Library Comparison

標準 API(java.util.Base64)文字列・バイナリ・URL セーフの3パターンで十分な場合。依存ゼロで Java 8 以降どの環境でも動く。ストリーミングエンコードは wrap メソッドで可能だが、大容量データの分割処理は自前で管理する必要がある。
Apache Commons Codec(Base64)Java 7 以前の環境や、isBase64 のようなバリデーションメソッドが必要なとき。Java 8 以降では標準 API で同等の機能が揃うため、新規プロジェクトでは依存追加の理由が薄い。

注意点

getBytes() を文字コード指定なしで呼ぶと OS のデフォルトエンコーディングが使われ、環境によって結果が変わる。必ず StandardCharsets.UTF_8 を指定すること

URL セーフ Base64 の withoutPadding() を使うと末尾の = が省略される。デコード側が標準デコーダーだとパディング不足でエラーになるため、エンコーダーとデコーダーの組み合わせを揃える必要がある

Base64 はエンコーディングであって暗号化ではない。秘密情報を Base64 でエンコードしただけでは保護にならない。機密データには AES 等の暗号化を併用すること

MIME エンコーダーは76文字ごとに改行を挿入する。HTTP ヘッダーや JSON の値に使うと改行が混入して不具合の原因になるため、用途に応じてエンコーダーを選ぶこと

FAQ

Base64 エンコード後のサイズはどのくらい増えますか。

元データの約1.33倍になります。3バイトを4文字に変換するため、おおむね33%増加します。MIME エンコーダーは改行文字が追加されるぶん、さらにわずかに大きくなります。

URL セーフ Base64 と標準 Base64 の違いは何ですか。

URL セーフ版は + を - に、/ を _ に置き換えます。URL やファイル名に含めても壊れない文字だけで構成されるため、クエリパラメータやパス要素に直接使えます。

Base64 のデコードで不正な入力を渡すとどうなりますか。

IllegalArgumentException がスローされます。外部から受け取った文字列をデコードする場合は try-catch で囲み、不正入力時の振る舞いを明示的に定義しておくと安全です。

関連書籍

この記事のテーマをさらに深く学びたい方へ。

※ Amazon アソシエイトリンクを含みます