トップ «前の日記(2007-01-08) 最新 次の日記(2007-01-10)» 編集

日々の破片

Subscribe with livedoor Reader
著作一覧

2007-01-09

_ Base64クラス

copy java\util\prefs\Base64.java Base64.java
してからパッケージ名変えるというんじゃだめなのかなぁ。 というか、Base64がオフィシャルに無いということはどういうことかと言うと、
  • java.util.prefs.Base64.java
  • com.sun.org.apache.xml.internal.security.utils.Base64.java
  • com.sun.org.apache.xerces.internal.impl.dv.util.Base64.java
と車輪がいっぱいあるということになる。そりゃ必要だもんな。

なんだかなー感が漂うね。

僕はルックアップテーブルを使ったprefsの実装が好きかな。

RFC2045準拠度だと多分、security.utilsが固そうな気がする(xercesの実装を元にしたOptimized codeだとコメントしてるし)。

ちなみにprefsのはジョシュアブロックの実装と@authorに書いてある。

ジョシュアブロックといえば
Java Puzzlers 罠、落とし穴、コーナーケース(ジョシュア・ブロック/ニール・ガフター/柴田 芳樹)
こういうのも書いているしJavaOneでもやってるみたいだけど、僕が読んだのは幾つかのソースコードと、
Effective Java(TM) Programming Language Guide (Java Series)(Joshua Bloch)
これ。

Effective Javaな人はルックアップテーブルを使うのであった。

_ ルックアップテーブル

16進化文字列"08Ab5"を10進数に変換することを考えてみる。 ひとつは、文字コードに着目する方法。たとえば
int result = 0;
for (char ch : "08Ab5") {
    result *= 16;
    if (Character.isDigit(ch)) {
        result += ch - '0';
    } else if (Character.isLowerCase(ch)) {
        result += ch - 'a' + 10;
    } else if (Character.isUpperCase(ch)) {
        result += ch - 'A' + 10;
    } else {
        throw new IllegalArgumentException("bad character: " + ch + " in given string");
    }
}
return result;
多分、最適化すると
int result = 0;
for (char ch : "08Ab5") {
    result *= 16;
    if (ch >= '0' && ch <= '9') {
        result += ch - '0';
    } else if (ch >= 'A' && ch <= 'F') {
        result += ch - 'A' + 10;
    } else if (ch >= 'a' && ch <= 'f') {
        result += ch - 'a' + 10;
    } else {
        throw new IllegalArgumentException("bad character: " + ch + " in given string");
    }
}
となる。
ルックアップテーブルを使う方法はまったく異なる。
static final int[] lookuptable = { 
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,
    -1, 10, 11, 12, 13, 14, 15, 16, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, 10, 11, 12, 13, 14, 15, 16, -1, -1, -1, -1, -1, -1, -1, -1, 
};
 
int result = 0;
for (char ch : "08Ab5") {
    result *= 16;
    if (lookuptable[ch] < 0) { // maybe thrown IndexOutOfBoundsException
        throw new IllegalArgumentException("bad character: " + ch + " in given string");
    }
    result += lookuptable[ch];
}
となる。

ルックアップテーブルを参照する方法はロジックがコードからテーブルに移動するため、一般的にはメンテナンスがしやすく、しかも高速になりえる(ルックアップテーブルってドメインモデルみたいだな)。

追記:文字列に拡張forは適用できないのか。残念。

上のforは、for (int i = 0; i < "08Ab5".length(); i++) { char ch = "08Ab5".charAt(i); と書いたものとしておこう。

さらに追記:leajistさんのツッコミが正しいですね、この場合。for (char ch : "08Ab5".toCharArray()) { ということで。

本日のツッコミ(全4件) [ツッコミを入れる]
_ るいも (2007-01-09 10:25)

java.util.prefsの中にBase64なんてあったんですね。でもパッケージプライベートだから、使えない... publicにして欲しいですね。私は普段はJavaMailの中のBase64を使用しています。

_ なひ (2007-01-09 12:26)

他のcommonsとセットで、common-codec。

_ leajist (2007-01-09 13:10)

for (char ch : "08Ab5".toCharArray()) {<br>でいけますよ〜

_ arton (2007-01-09 13:40)

そのてがあったか。


2003|06|07|08|09|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|

ジェズイットを見習え