Java | Java 標準ライブラリ:UUID

Java Java
スポンサーリンク

UUID を一言でいうと

java.util.UUID は、

「ほぼ絶対に重ならない“ランダムな ID” を簡単に作るためのクラス」

です。

データベースの主キー、ファイル名、トークン、セッションID など、
「世界中で一意だと思ってよい ID」が欲しいときに使います。

UUID.randomUUID() と 1 行書くだけで、
550e8400-e29b-41d4-a716-446655440000 のような文字列をすぐに作れます。


UUID の見た目と正体をイメージでつかむ

典型的な UUID の文字列表現

Java で UUID を生成して toString() したとき、だいたいこんな形になります。

550e8400-e29b-41d4-a716-446655440000

ルールとしては、

32 桁の 16 進数
5 つのブロックに分かれていて 8-4-4-4-12
間は - で区切られている

という構造です。

ぱっと見て「意味のないランダムな ID」に見えますが、
内部的には 128 ビット(2 の 128 乗通り)の数値です。

2 の 128 乗というのは、感覚的には
「とてつもなく巨大すぎて、めったにかぶらない」レベルの数です。

Java の UUID クラスの中身

UUID クラス自体は、
この 128 ビットの数値を

mostSignificantBits(上位 64 ビット)
leastSignificantBits(下位 64 ビット)

の 2 つの long に分けて内部保持しているだけのシンプルなクラスです。

文字列表現はあくまで見やすくするための形式で、
本質は「128 ビットの番号」だとイメージしておくとよいです。


一番よく使う:UUID.randomUUID() でランダム ID を生成する

最小限の使い方

とりあえず何も考えずに「一意っぽい ID がほしい」なら、これだけ覚えてください。

import java.util.UUID;

public class UuidBasic {
    public static void main(String[] args) {
        UUID id = UUID.randomUUID();
        System.out.println(id.toString());
    }
}
Java

実行するたびに、違う値が出てきます。

UUID id = UUID.randomUUID();
これがすべての出発点です。

UUID 型のまま使ってもいいですし、
id.toString()String にして DB に入れたり、JSON に載せたりできます。

なぜ「ほぼ絶対に重ならない」と言えるのか

randomUUID() は、バージョン 4 と呼ばれる「ランダムベースの UUID」を生成します。

128 ビットのうち一部は「バージョン情報」などに使われますが、
残りは乱数です。

乱数がちゃんとしている前提で、
2^128 通りのうちのひとつが選ばれるわけですから、
同じものが偶然生成される確率は天文学的に低いです。

現実問題として、
「アプリの中で UUID がかぶって困る」事態は、
ほぼ無視してよいレベルだと考えて構いません。


例題:ユーザー ID やファイル名に UUID を使う

ユーザー登録で UUID を主キーにするイメージ

例えば、アプリのユーザーIDを自動採番ではなく UUID にしたいとします。

public class User {
    private final String id;
    private final String name;

    public User(String name) {
        this.id = UUID.randomUUID().toString();
        this.name = name;
    }

    public String getId() { return id; }
    public String getName() { return name; }
}
Java

こうしておけば、新しく User を作るたびに
"c8e2b95a-a1c3-4ed7-bd1e-5e4aa480abcd" のような ID が振られます。

利点として、

どのサーバーで生成しても、勝手にユニーク(ID 発番サーバーを用意しなくてよい)
外部から推測されにくい
別システムとマージするときも ID 衝突をあまり心配しなくてよい

といったものがあります。

一時ファイル名やディレクトリ名に使う

一時ファイルやアップロードファイルを保存するときにも、
UUID はよく使われます。

import java.nio.file.*;

public class TempFileExample {
    public static void main(String[] args) throws Exception {
        String fileName = UUID.randomUUID().toString() + ".tmp";
        Path path = Path.of("tmp", fileName);

        Files.createDirectories(path.getParent());
        Files.createFile(path);

        System.out.println("一時ファイル: " + path);
    }
}
Java

このようにしておけば、複数のリクエストが同時に来ても、
ファイル名がかち合う可能性は非常に低くなります。


文字列から UUID を復元する:UUID.fromString(...)

DB やファイルに保存した UUID を戻す

UUID を String として保存しておいて、
後でまた UUID に戻したいときは UUID.fromString を使います。

UUID id = UUID.randomUUID();
String text = id.toString();

UUID parsed = UUID.fromString(text);

System.out.println(id.equals(parsed)); // true
Java

fromString は、
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx の形式で書かれた文字列を
UUID オブジェクトに変換します。

形式が違っていると IllegalArgumentException が投げられるので、
入力を信頼できない場合は try-catch で囲むのが安全です。

equals / hashCode が定義されているので、キーとして使いやすい

UUIDequals / hashCode がちゃんと実装されているので、
Map<UUID, Something> のキーにしたり、Set<UUID> に入れたりするのも簡単です。

import java.util.*;

public class UuidAsKey {
    public static void main(String[] args) {
        Map<UUID, String> map = new HashMap<>();

        UUID id1 = UUID.randomUUID();
        UUID id2 = UUID.randomUUID();

        map.put(id1, "Alice");
        map.put(id2, "Bob");

        System.out.println(map.get(id1)); // Alice
        System.out.println(map.get(id2)); // Bob
    }
}
Java

「文字列として扱うか、UUID 型のまま扱うか」は好みやシステムの設計次第です。


UUID のバージョンやバリアントに少しだけ触れておく

getVersion() と getVariant()

UUID には、どのような生成方法で作られたかを表す「バージョン」や、
仕様の種類を表す「バリアント」という概念があります。

UUID id = UUID.randomUUID();
System.out.println("version = " + id.getVersion());  // たいてい 4
System.out.println("variant = " + id.getVariant());  // 通常は 2(IETF の標準形式)
Java

randomUUID() が返すのは「バージョン 4 の UUID」です。

バージョン 1(時刻+MACアドレスベース)など、
他のバージョンも仕様としては存在しますが、
Java 標準の UUID クラスでは主に「v4 ランダム」が意識されていれば十分です。

初心者のうちは、

UUID.randomUUID() → バージョン 4 のランダムな UUID
getVersion() が 4 なら「ランダム系」だな、くらい

と理解しておけば問題ありません。


UUID を使うときに意識しておきたいこと

「ユニーク ID をどう管理するか」の一つの答え

アプリケーションが大きくなると、
「ID をどこで採番するか」という問題が必ず出てきます。

DB の自動採番(AUTO_INCREMENT、シーケンス)
別の ID 採番サーバーを立てる
アプリ側でランダムに振る(UUID など)

UUID は、「アプリ側でランダムに振る」アプローチの代表選手です。

特に、マイクロサービスや分散システムのように、

複数サーバーが勝手に ID を発行しても衝突してほしくない
中央集権的な ID サーバーを置きたくない

といった場面で、UUID は非常に便利です。

デメリットも一応知っておく

UUID の弱点も少しだけ触れておきます。

文字列が長い(16 進で 32 桁+ハイフン)
整数 ID に比べてインデックスのサイズが大きくなる
連番でないので、DB のインデックス局所性が悪くなりパフォーマンスに影響する場合がある

ただ、最初からそれを細かく気にしすぎる必要はありません。

小さな〜中規模のシステムや、まずは動くものを作りたい段階では、

「ID 衝突をほとんど気にせず使える」「分散環境でも楽」というメリットの方が大きいです。

本当にパフォーマンスが問題になってから、
「連番+シャーディング」などを検討しても遅くはありません。


まとめ:UUID を自分の中でこう位置づける

UUID を初心者向けにまとめると、

「128 ビットの巨大な番号をランダムに振ることで、実質的に重ならない ID を簡単に作るためのクラス」

です。

特に意識してほしいのは、

  • UUID.randomUUID() で簡単に一意 ID が作れる
  • toString() / fromString() で文字列と相互変換できる
  • 主キーやファイル名、トークンなど「ユニークさが大事なもの」に向いている
  • ID 発番の仕組みを自分で構築しなくてよくなる(分散環境で特に嬉しい)

タイトルとURLをコピーしました