エンジニアが発信する【2006年01月】の記事です

エンジニアが作る最新ITブログ トップ>【2006年01月】

2006年01月27日

javacのバージョンの確認方法

たまたまQ&Aサイトに見つけた方法です。

javaならば、java -versionでバージョンを確認できます。

javacは分からなかったのですが、どうやらjava -J-versionで配下のjreのバージョンが出るようです。




2006年01月24日

整数でビット演算

javaでコーディングしているとビット演算なんて死語に近いが、とりあえずjava以外の言語でビット演算がないときのために、(javaで)整数だけで作ってみた。

BitFunc.java

そしてこちらがテストケース。8ビットならばすべての組み合わせをテストしたはず。さすがにビット数を増やすとCPUのベンチマークテストになってしまう。

BitTest.java

一応、eclipseの開発環境(自分のため)

bit-func.lzh

・・・

ビットセットが「マスクビットとorを取る」、ビットリセットが「マスクビットを反転してandを取る」ということをコーディングしたのは何年ぶりだろうか・・・。



2006年01月24日

悪名高き「ぬるぽ」対策

今日一日で何度もNullPointerExceptionが出ました。原因の場所によっては、ブラウザにスタックトレースが出力されたり、ブラウザは白紙でログファイルに出ていたりする。

そもそも、なんでぬるぽ(NullPointerException)が出るのだろうか???

例えば、『null.execute();』みたいなコーディングをしてもコンパイルエラーとなる。つまり、コンパイル時には見つからないからランタイムエラーとなるわけだが、これがまた嫌らしい。特にデバッグトレース内でぬるぽなんていうのは最悪である。

簡単なクラスの例として、Point { int x; int y };があるとする。メソッドはgetter, setterとtoString()とtoDebugString()とする。

デバッグログ出力メソッドがlog(String msg)として用意されていたとき、Point pt = new Point();で生成されたインスタンスをlog(pt);のように渡すとコンパイルエラーとなる。

そこで、明示的にStringに変換するわけですが、「log("" + pt);」や「log(pt.toString());」みたいにする。前者では、空文字列との連結時に暗黙的にptがStringに変換されて、結果的にptをStringに変換してメソッドに渡している。後者では、明示的にtoStringを呼んでStringに変換している。

ここで、ptがnullだった場合、前者はセーフ(nullという文字列が出力される)だが、後者はアウト(ぬるぽ発生)となる。

それでは、前者のスタイルに統一すればいいだろうと思うわけだが、冒頭でtoDebugStringメソッドがあると書きました。つまり、デバッグ出力用はtoStringではなくtoDebugString()を使うつもりということです。これではnullチェックしないとぬるぽになります。

一言でnullチェックと言っても、これが大変なんです。例えば、「pt1.toDebugString() + ", " + pt2.toDebugString() + ", " + pt3.toDebugString()」とやりたいと思ったら、やはりStringBufferを用意して一つづつnullチェックしながらappendしていくしかありません。

・・・

ここからが空想上のお話です。

まずnullは特定のクラスを持っていません。つまり、nullにどんなメソッドを呼び出してもぬるぽになります。そこで、Point pt = null;の時のptに入っているnullは、「Pointクラスのnullインスタンス」として(VMが)判断できないでしょうか。まずこれが1つ。

次にnullインスタンスに対しての特殊なメソッドをオーバーロードもしくはオーバーライドできないかな?ということです。例えば今回のpt.toDebugString();の場合、ptがPointクラスのnullインスタンスの場合では、ぬるぽを投げるのではなく"null"を返すみたいな。

となると、もっとも基底のObject.toString()も同様になります。既存ではobj=nullのときに、objは"null"なのに、obj.toString();は例外が投げられるということが、同じように"null"を返すことができるようになります。

toStringだけでなく、equalsやhashCodeなんかも同じ仕組みができるといいと思うんですけど、こんなことを考えるのは私一人でしょうか???



2006年01月05日

あなたの仕様は守っているけど、私の仕様は決めていないということについて

「ソフトウェアIC」という言葉が気になって、眠れなくなってしまった。

・・・

インターフェイスとは何ぞやということを考えていたら、あまりにも当たり前の現実に気が付いた。

それが「あなたの仕様は守っているけど、私の仕様は決めていない」

私の仕様を決めていないから、なかなかソフトウェアICが実現できないんじゃないか・・・。

・・・

例えば、スレッドクラスを作るためのRunnableインターフェイスを例にしてみる。Runnableを実装するクラスは、必ずrun()メソッドを定義することになる。これは「あなた(Thread)の仕様を守っている」ということです。

ここで、非同期にファイル監視するクラスAと非同期にソケット通信するクラスBがあったとき、クラスAとクラスBを取り替えたら動くだろうか・・・!?

動くわけないですな。

つまり、「私の仕様は決めていない」から片手落ちの手抜きのインターフェイスなんだろう。

・・・

じゃあ、ファイル監視するRunnableインターフェイスAとソケット通信するRunnableインターフェイスBの2つを定義したのちに、インターフェイスAを実装するクラスA1とクラスA2、インターフェイスBを実装するクラスB1とクラスB2があった場合ならどうよ。おそらくクラスA1とクラスA2は取り替えられるし、クラスB1とクラスB2も同様。

つまり、インターフェイスっていうのは、他に継承させているsuperインターフェイスは別として、末端のインターフェイスならばその実装クラスをどれに置き換えてもほぼ同じように動かないといけないんじゃないかな!?

・・・

ほとんど同じ例だけど、Servletの仕様を守っている100個のServletがあったとしても、取替えができない。例えば、LoginServletとLogoutServletを取り替えたらどうなるか? これはやっぱり手抜きなんだろうな。「あなたの仕様(Servlet)は守っているけど、私の仕様は決めていない」。

ILoginServletとILogoutServletのインターフェイスが別々に定義されていて、ILoginServletを実装するのがCSVLoginServletとなる。もしRDBにユーザマスタを持たせたいならRDBLoginServletで、XMLファイルに持たせたいならXMLLoginServletになる。

・・・

やっぱり私は、くどいけど「new ILoginServlet();」ってコーディングしたいですわ。

・・・

マザーボードにCPUソケットが付いていて、マザーボードのコーディングをしていたとする。そのときに3つの選択肢があるとする。

  1. CPUSocket cpu = new IntelCPU();
  2. CPUSocket cpu = new CPUSocket();
  3. CPUSocket cpu = di.get("cpu");

1.はCPUソケットがあるのにインテルが直接半田付けされている感じ。
2.はCPUとCPUソケットを抽象的に扱っている感じ。
3.は外部にドライバがないとCPUソケットが使えない感じ(USBみたいな感じ)。



2006年01月04日

安定しているメソッドかどうか分かれば

そういえばメソッドに安定しているか、安定していないか、って指定できればいいのに。

安定とは、同じパラメータを渡せば、同じ結果になるという意味です(正確には何と言うのか知らないけど、何となく意味は合っているでしょ?)。例えば、sin(x)やcos(x)は安定しているし、rand()やDBアクセスして結果を返すメソッドは安定していない。

・・・

実は安定しているメソッドは最適化できる。そもそもメソッドや関数は汎用的に作られている。数学関数(sinやcos)なんかは中がどうなっているか見たこともないが、とにかく正確な答えを返す。しかし、sinやcosに度数で{0度、90度、180度、270度}しか使わないのなら、汎用的なロジックでなくても、この4パターンに特化したロジックでも良いわけです。
ここで、間違いなく汎用的なロジックより、特化したロジックの方が速い。

・・・

今までは人間がここを汎用ロジックで、ここを特化したロジックで、と判断していたわけなんだが、もうそろそろこの作業の半分くらいをコンピュータにやってもらおうか(笑)。つまり、あるクラスAから、クラスB内の安定しているメソッドを呼び出したときに、パラメータが偏っているのならば、汎用的なロジックから自動生成した特化したロジックに切り替えてやったらどうよ。
一種のキャッシュみたいなもんだね。でも、キャッシュを人間が作りこむのではなく、ランタイムがキャッシュロジックを作りだして、メソッドのエントリポイントを変えてやる。雰囲気はJITコンパイラみたいな感じだけど、ソースファイルそのものを動的に作ってやる。

//元の人間が作ったソース
class A {
void func() {
int rc = B.calc(1);
}
}
class B {
@結果が安定しているマーク
static int calc(int x) {
return x*x;
}
}

//最適化したソース
class A {
void func() {
//REPLACE by runtime
//int rc = B.calc(1);
int rc = B_2.calc(1);
}
}
class B {
@結果が安定しているマーク
static int calc(int x) {
return x*x;
}
}
//GENERATE by runtime
class B_2 {
static int calc(int x) {
if (x==1) return 1;
else return B.calc(x);
}
}

運用していると、どんどんモジュールサイズが肥大化していきます(笑)。

・・・

でも、なんか同じ結果ならより速いロジックを自動選択していくみたいなことがDIで実現できればいいんだけどね。つまり、上の単純な値のキャッシュだけでなく、パラメータが0〜100まではロジックA(クラスA)で、パラメータが101以上ならロジックBみたいな感じ。せっかくユニットテストを作るんだから、単純に○×だけでなく、速度の良し悪しもデータに残して、ランタイムがその成績みてロジックを選択してくれるみたいなことができてもいいな。



エンジニアが作る最新ITブログ トップ>【2006年01月】

メンバー紹介

タグパネル

ランキング

エンジニアが作る最新ITブログ DODA