Home日記コラム書評HintsLinks自己紹介
 

フィンローダのあっぱれご意見番 第111回「i is for Integer」

← 前のをみる | 「フィンローダのあっぱれご意見番」一覧 | 次のをみる →

携帯電話の話を前回書いたが、 世の中にその話がまだ出ていないうちにDoCoMo が矢継ぎ早に妥協案を出したようだ。 まさか原稿のメールがインターネットで盗聴されて…なんてことはないだろうな、 と思う今日此の頃。

 

※ タイトルを超訳すれば「iという変数名は整数のためにある」とかいう。 これはレイ・ブラッドベリのショートショートの題名、 例えば 「S is for Space」 などを意識している。 邦訳「ウは宇宙船のウ」。 創元SF文庫。

要するに迷惑メールに受信者が金を払うのは納得できないという話なのだが、 その後 DoCoMo が猛烈なPR体制でアドレスの設定方法を宣伝したり、 一定数までは受信を無料にすると発表したり、 いろいろ工夫しようという努力を見せているようだ。 個人的には、メールアドレスを設定してからしばらくの間、 全くDMが来なくなったので、これで平和になったかと思ったわけだが、 おっとどっこい。 頻度は少ないが、またぞろ迷惑メールが来るようになったのである。 電話番号だけならともかく、今のアドレスにメールが来るというのは不思議というか、 誰かがアドレスを漏らしているとしか思えないのだが…。 誰?

§

  

完全にJavaにハマっているのだが、何とかFPROGのアンケートも servlet 上で動作するようになった。 アンケートというデザインパターンがあるのかもしれないが(そうか?)、 中途半端な汎用性を持たせようとすると、 面倒なことになってしまうようである。 実際書いてみれば、 なるほどJavaはperlより手間をかけずに、 ある意味複雑なことができると実感できる。 もちろん「できる」というのが実用的な話なのか単なる可能性の話なのか、 というのは別の大きな問題なのだが。

 

※ perl の素敵なところは、ワンライナー的な使い方もできるとか、 文字列の処理が強力だとか。 昔の Java は文字列系の処理が貧弱だったが、 今だと正規表現はもちろん、printf まで使えるのだ。

Javaに関しては素人レベルから少し毛が生えたレベルになってきたと思っている。 ステップ数(死語?)で表現すれば、1万ステップは書いたが、10万ステップには届かない、 というあたりで、一番ノリのいい時期かもしれない。 ただ、相変わらずだが、どうしようもない基本的な所でコケている。 ずっこけ(死語?)ネタを何度も紹介しているわけだが、 考えてみれば、このような基本的なコケは、 良いチュートリアルを読めば一発で解決するはずなのだ。 Java FAQ のようなページにも、あるいは解決策が書いてありそうな気がする。 というか、実際書いてあるらしい。 ただし、ちょっと見た感じでは、 ある程度当たり前の質問は書かれているが、 限度を超えたウルトラビギナー的な質問は入っていないような気がする。 流石にそこまで面倒みられないのだろう。

前回も紹介したが、 Javaに再挑戦してからどうも違和感が取れなかったのが、文字列の処理である。 文字列と数値の間にある距離感がマヒしてしまった原因は、 Perlにちょっと親しみすぎたからかもしれない。 C言語どっぷりの時代は、 もっと型にハマった考え方をしていた。 例えば、"123" というような文字列から、123という数値を得たいなら、 C言語だったら、atoiという関数を使って、 i = atoi("123"); という感じのコードを書く。 Perl の場合は? そういうことを考えなくても済むのだ。 というか、そもそも、 ある変数が数値型だとか文字列型だという区別自体がない。 コンテキストが必要としている状況次第で、 適切に解釈される仕組みになっている。 例えば、次のコード。

    $s = "123";
    $s -= 100;
    print "$s\n";

$s に "123" を代入したのだから、 一見 $s は文字列型(というものがあるなら)のように見えるのだが、 いきなりそこから100を引き算している。 C言語的には言語道断な発想だと思うが、 これが Perl ではエラーにならない。 123という数値から100を引いた23という結果が、最後にプリントされるだけである。

§

さて、C言語のatoiに対応するJavaのメソッドは何なのだ。 最初はこんな感じのコードを書いていた。

    Integer in = new Integer(s);
    int i = in.intValue();
  

間違いではない。 しかし何か回りくどすぎる。 それがオブジェクト指向ってものさ。 とか言われたら、そうなのか、 と思わず思ってしまいそうな雰囲気もあるのだが、 それにしてはどうも違和感がありすぎる。

 

※ オブジェクト抜きのメソッドなんてあり得ない、という話。

とはいえ、やり方を他に知らなければ仕方がない。 さらに、何とかできてしまう、という現実が、 結果的に一番始末におえないコードで思考停止させてしまいかねない。 もちろん、、 static なメソッドは、わざわざオブジェクトを作らなくても、 直接クラスを指定して実行することができるから、

    i = Integer.parseInt("123");
  

と書けばいいのだ。 これは Tips と言うにもエレガントと言うにも値しない、 「当たり前」の書き方なのだが、 その当たり前が分からないレベルなので全く困ったものである。

 

※ ちなみに parseInt って thread safe でしたっけ?

無駄といっても、1行で書けるものを2行にしてしまっただけのようだが。 甘い。 このたった2行の中にドジのオンパレードがあるのだ。 実に下らない話だが、 最初の頃は Integer in と書くべきところをよく Integer int と書いてしまって、 コンパイルエラーを出していた。 int は予約語なので、そんな所に書いてはいけない。

 

※ 最近は省略しない癖がついたので、 Integer integer と書く。

省略しないで integer と書けばよさそうなものだが、 なぜかつい省略したくなるのである。 なぜだといわれても分からない。 そんなに省略したいのなら、 いっそ、Integer i と書けばいいという発想もある。 道理ではあるが、 先程紹介した2行で書いた例だと、 すぐ後に出てくる int の i と衝突してエラーになってしまう。

  

ループ変数に int の i を使うことが体に染み付いていて、 もしかしたら、まず無意識に使ってしまうプログラマーが多いのではないか。 他の体験では、Iterator の i と衝突したこともあった。 ちなみに、最近は、Iterator は it と書くことにしている。 これで i とは衝突しなくなった。 そもそも、心理的には、 iと言ったら基本型のintに対応しているに決まっているのである。 iといえばintのiであって、 決してiモードのiではないのだ。

 

※ itr と書く人もいるようだ。

じゃあ Integer は in と書けばいいのだが、 in と書くと、何となく入力のファイルハンドル系の変数みたいな気がして、 どうも落ち着かない。 発想がC的すぎるのかもしれないが、 そもそも、たかが整数の処理をしたいだけなのに、 Integer のオブジェクトを作ること自体が、どうも落ち着かない。 できればそんなクラスを使いたくないのである。 例えば String に intValue というメソッドがあって、

    i = "123".intValue();

と書けたらイメージ的にはすごく分かりやすいと思う。 実際はそんなメソッドはないのだが。

じゃあIntegerクラスを使わなければいい、 ということになるが、 SetやMapにデータを突っ込む時にはオブジェクトを作るしかないので、 int の値を入れるために仕方なく Integer クラスを使っていた。 「いた」じゃなくて、今も使っているのだが、 最近ちょっと気になるのが String である。 int をInteger クラスに変換するするのなら、 String に変換しても似たようなものではないだろうか、とか。

§

ところで、逆はどうするのだろう? C的には、sprintf を使うような状況である。 Javaでsprintfに相当する処理をどうすれば実現できるのか。 前回紹介したのがDecimalFormatを使うという方法で、 それを使えばもちろん何とでもなりそうだが、 最初はこんな感じで書いていた。

    Integer in = new Integer(i);
    String s = in.toString();

これも整数値を一旦 Integer のオブジェクトにするのが気に入らない。 Static メソッドを使えば、次の1行で書ける。

    String s = String.valueOf(i);

このように書けばよいことを知らなかった頃は、 一時、このような書き方をしていたことがある。

    String s = "" + i;

こんなのは Tips とも言わないかもしれないが、 分かってみると結構便利である。 ただ、全く気にならないわけでもない。というのは、 次のように書いたらコンパイル時「互換性のない型」というエラーになる。

    String s = i;

これがなぜ、

    String s = "" + i;

だとエラーにならないか。 理屈では分かっているのだが、感覚的に納得できないというか、 "" と足し算すればエラーにならないのであれば、

    String s = i;

と書いた時にも自動的に何かやってくれてもよさそうな気がするのだが、 とか思っているのは私だけ?

というわけで、感覚的には String.valueOf(i); の方が違和感はないのだが、 何しろ「+」で書けてしまうという便利さに捨て難い魅力があるため、 実際は "" + i という書き方に頼りがちだ。 Javaの応用系の本を読むと、もっと気になることが書いてある。 String のパフォーマンスの問題である。 この種の本には、 String を StringBuffer に置き換えて劇的に効率を改善するという話が必ず出てくる。 文字列の連結を何でも「+」で行うのは初心者だというのだ。 そこで、List 1 のようなプログラムを書いて、 どの程度の差があるのか調べてみた。

---- List 1 (test.java) ----

import java.io.*;

public class test {
  public static void main( String args[] ) throws IOException {
    final int limit = 1000000;

    long l1 = System.currentTimeMillis();

    for (int i = 0; i < limit; i++) {
      String s = "" + i;
//    String s = String.valueOf(i);
    }

    long l2 = System.currentTimeMillis() - l1;

    System.out.println("count = " + l2);
  }
}

---- List 1 end ----

List 1 の1行だけコメントアウトした所を、直前の行と入れ替えて再コンパイル、 実行して画面に表示される数を比較すればいい。 単純に予想すれば、"" + i という書き方だと、 "" というオブジェクトを生成して、iに対応するオブジェクトを生成して、 さらにそれらを結合したオブジェクトを生成する、 という感じか。 これに対して、String.valueOf(i) の方は、 いきなりStringオブジェクトを作るだけだ。 従って、効率としては、String.valueOf(i) が勝ると予想できる。 処理系依存なのはもちろんだが、実際にやってみると倍程度の差が出た。 Javaって恐い。

  

(C MAGAZINE 2001年9月号掲載)
内容は雑誌に掲載されたものと異なることがあります。

修正情報:
2006-03-03 裏ページに転載。

(C) Phinloda 2001-2006, All rights reserved.