2009年3月11日水曜日

Javaでランダムで一意な文字列を生成したい

Javaでランダムで一意な文字列を生成したい...って時、どんなものを使ってますか??
そういう場面になったので見てみたものをちょっとマトメ。


桁数が長くてもいいから一意に 系

UUID

JDK1.5 で導入された java.util.UUID で UUID.randomUUID().toString(); をする。
取得される文字列(16進)は ffbac078-8cf0-483f-817d-184a5e812613 のような感じ。

これをMath.absで10進数にすると 2080304300 のような感じ

ナノ秒

これまたJDK1.5で導入された System.nanoTime() を使う。
取得される値は 1236777382401532000 て感じ。
複数Threadの場合には、ThreadIdをプラスしないと重複しちゃう事もあるだろうし...そうでなくても本当に重複しないって保証はあんまりないので、重複チェックの処理がいるかも。

MD5などでハッシュにする

idなど一意な文字列を元として、MD5やSHAなどでハッシュにする。
こうすると、ある文字列に対して常に同じ値が取得できるし、結果から元の値は想定しにくいものが作れる。(不可逆なので一方向関数というらしい)

Javaの場合、java.security.MessageDigest を使います。
  String value = "なんか";
  MessageDigest md5 = MessageDigest.getInstance("MD5");
  md5.update(value.getBytes());
  byte[] hash = md5.digest();

これを以下で文字列に
public static String hexString(byte[] bin) {
String s = "";
int size = bin.length;
for (int i = 0; i < size; i++) {
int n = bin[i];
if (n < 0) {
n += 256;
}
String hex = Integer.toHexString(n);
if (hex.length() == 1) {
hex = "0" + hex;
}
s += hex;
}
return s;
}

すると結果の文字列は 61c35ef8a6adc245e00a563a0627898b な感じ。
同じく "なんか" の文字列を
SHAでやってみると、9523f8f6accb5e1c7eda7ff087f771a7015efcc2。

今回私が欲しかったのは、あるシステムのログインIDを自動生成したいけど、想定できるようなものにはしたくない(連番はNG)
というものだったのでこれが目的に近いし、生成した文字列を保存する必要もなくて良い! だったんですが、んー長さが...長過ぎる...


ランダムで取得して重複チェックをする系

一意になるような文字列って長くなるのはしょうがないので...文字数を少なくしたいのであれば自前で重複チェックするしかないですよねー。多分。
という事で重複チェックをする前提で、ランダムで値を取得する方法です。

Math.random


おなじみ java.lang.Math で randomな数値を取得する
取得される値は 0.42089385157588244 な感じ。


RandomStringUtils


Commonsにこんな便利がものが!
org.apache.commons.lang.RandomStringUtils

用意されているメソッドは以下のようなものがあります。

public static String random(int count)
public static String randomAscii(int count)
public static String randomAlphabetic(int count)
public static String randomAlphanumeric(int count)
public static String randomNumeric(int count)

引数は文字の長さ。
Asciiだけで...英字だけで...英数字だけで...数字だけで...って指定ができる優れモノ!
英数字で6桁ものもが欲しければ RandomStringUtils.randomAlphanumeric(6) と記述し、結果は eW8awR な感じ。

結局今はコレに落ち着いたww
• • •