Quantcast
Channel: Emerge Technology

websocket-client 0.9.0

$
0
0
会社も虎ノ門に引っ越したことだし、立て続けにパッチが二つ来たので、websocket-clientの0.9.0をリリースしました。普通にpip install websocket-client でインストールできるはずです。

変更点は

  • originを変更できるようになった
  • WebsocketApp.sendでopcodeを設定できるようになった
このうち、sendメソッドで何故opcodeを指定出来るようにしておかなかったかはよく分かりません。なんか、忘れていたんだと思います。

それはそれとして、パーフェクトPythonがもうすぐ出るので、そろそろwebsocket-clientもPython3に対応する頃です。著者の一人が自分の作ったものをPython3にまだ対応していないなんて、詐欺みたいなものじゃないですか。

一つだけいいわけすると、Python3に対応させようと思ったら、HTML5モバイルアプリケーションフレームワーク Sencha Touchパーフェクトガイド がちょっと大変なことになりそうだったので、そっちの方に時間をとられちゃったんです。全部、Senchaが悪いんです。なので、パーフェクトPythonを買う人はSenchaのパーフェクトガイドも買ってください。同じようにパーフェクトってついているのは、きっと偶然です。


websocket-cleintがPython3.3で動く

$
0
0
パーフェクトPython」の執筆者の一人がPython3を日常的に触っていないのはいかがなものか、と言うおしかりを受けて、webscoket-clientがPython3.3で動くようになりました。現状はまだ、ブランチを直接チェックアウトして動かす必要があります。

作業時間は、大体、数時間程度です。2to3で変換をかけた後にちまちま直していきました。

Cで育った世代としては、文字列はバイト列で十分じゃね?と思ってしまいますが、時代はウニコードなので、仕方ないですね。と言うことで、ネットワークでやりとりするのがすべてバイト列になって必要に応じて文字列に変換するのは、以外とめんどいですね。

それ以外は特に困ったこともなかったはずです。

さて、動くようにしたのはいいけど、この後どうすればいいんでしょう? PyPIにあげるときにwebsocket-client-py3みたいにもう一個、別個に作るのがいいのか、同じ名前のままsetup.pyでpythonのバージョンをみて、コードにパッチを当ててインストールさせるのがいいのか? うーん、どうしよう。

Sencha Touchパーフェクトガイドの「はじめに」の正誤表

$
0
0
HTML5モバイルアプリケーションフレームワーク Sencha Touchパーフェクトガイド」(タイトル長!)が今日から発売ですね。今の時点ではまだ、Amazonのページに表紙の画像がありません。悲しいですね。(<= 表紙表示されるようになりました。いいですね)本の中身の紹介は他の人がやってくれているので、「はじめに」のところの正誤をこっそりと…。

「はじめに」は川野さんが書いていますが、記憶は美化されるものです。そして、彼の書いた「Sencha Touchとの出会い」はウソです。これが「本当のSencha Touchとの出会い」です。

まず、自社製品でSencha Touchの採用を決めた背景ですが、当時はモバイルWebアプリを開発するときのフレームワークは、実質、jQuery MobileとjQTouchの後継のSencha Touchしかありませんでした。自分たちでフレームワークを作るつもりはなかったので、実質この二択です。jQuery Mobileはちょっと方向性が違う、って考えていて、すでにあるものをモバイルに対応させようと思ったらjQuery Mobileを採用していたと思います。でも、今回はスクラッチから開発するのでSencha Touchという理由です。それ以外の理由は後付けです。Sencha Touchを採用すると決めたときから、本を書くことは視野に入っていました。

ブログを彼が書くきっかけですが、本の中では自発的に書いていることになっています。これ、ウソです。当時は、かれは別の部署だったのですが、ブログを定期的に書くことを条件にSencha Touchでの開発に加わります。で、定期的に書くという条件をかれは、2回か3回書けばいい、と自分の中で勝手に解釈してしまいます。2回か3回書いたあたりから更新がありません。「とてもよく書けているから」とか、「毎週書くって約束だったでしょ」とか、いろいろ言うのは疲れました。それから、「とてもよく書けているから」って言うのは、実は僕はあまりちゃんと読んでいませんでした。ごめんなさい。
それから、「本を出せるから」って冗談で言ったことはありません。すべて計画のうちです。

執筆状況の話とか、もっと面白いのですが、それは秘密です。

最後に、Amazonで買うときは、「この商品を買った人はこんな商品も買っています」にある腹筋コロコロも一緒に買うといいですよ。みんな一緒に買っています。

炎のKindleがやってきた

$
0
0
先日、と言うか、月曜日に注文した炎のKindleがやって来ました。やって来たのは火曜ですが…。本当は8.9インチのほうが欲しかったのですが、おもちゃに2万5千円は高すぎます。そもそも、Androidとか嫌いだし…。

と言うことで、パッケージはシンプルで小さいです。真っ黒の箱でAppleとは違って暗黒世界をイメージします。
箱から出てきたKindle Fire HD。真っ黒です。サイズは大体想像通りだったのですが、思ったより重いです。

炎のKindleは画面がきれいらしいし、左右にスピーカーがあってそこそこの音がでるらしいです。なので、安価なマルチメディア端末としていいかも。

多分、僕はKindleで本は買わない…
とりあえず、火を入れます。電源ボタンの位置が分からずちょっと右往左往しました。
iPad miniたんと並べてみると、一回り小さいです。まあ、僕はiPad miniたんのほうが好きですが…。

使ってみると、Androidっぽくないです。慣れれば使いやすいのかも知れませんが、iPadでもAndroidでもないUIはちょっと戸惑います。うーん、Kindleの延長線上みたいな感じ。


前評判通りPlayストアは使えません。Amazonのストアは…。Huluがない…。この端末、Huluを見るのが理由の一つです。でも、悲しいことにAmazonのストアにはHuluはいません。Twonky Beamはいるので将来の利用用途には大丈夫ですが、当面Huluがいないのは残念ですね。

と言うことで、Huluをインストールしました。ESファイルエクスプローラとHuluを別のAndroid端末に入れて、ESファイルエクスプローラでHuluのアプリをapkとしてバックアップします。バックアップしたものをメールで送ってKindle Fire HDにインストール。めでたしめでたし。って、これじゃ自動でアップデートしてくれないのでめんどいじゃないですか! Amazonのストアに早くHuluが来てください。

狭い世界でPython3

$
0
0
Python3って、自分の周りでどれくらい使われているんだろう? と言うことで、細々とメンテナンスしているWebsocketのライブラリをPython3でも動くようにパッケージングしてpypiにのせています。ちなみに、一つのパッケージでsetup.pyでパッチをあてて動くようにしようと思っていたんですが、結局パッケージを分けてしまいました。ちなみに、会社のPythonはまだ2.7で、さらに悲しいことに古くて腐ったOSでも標準の状態で動くように2.4で動作確認しています。

さて、pypiにあげたパッケージのダウンロード数ですが、公開して一週間ぐらいで2.x用のパッケージが276です。さて、3.3用のパッケージですが、こちらは、ダウンロード数が92です。2.x用の方が3.3より3倍多く使われていますね。3.xを使わなくてももうしばらくは安心していられます。良かった良かった。

ちなみに、Websocketの仕様書、差分をみるのがめんどくさくって最近読んでいませんが、どうなっているんだろう?

iMacが壊れて直ったでござる

$
0
0
先週の金曜日にiMacが壊れました。悲しいです。スリープから復帰しようとしたら、起きてくれません。再起動すると、起動してくれません。リンゴが出現してくるくるが動きます。そのあと、プログレスバーみたいなのがでて途中で電源が落ちます。

僕のiMacは2010年の夏のモデルです。このモデル、ハードディスクがリコール対象なんですね。かなり前から知っていました。でも、めんどくさいし、iMacの次のモデルがでたら買い替えてたくて、そのための正当な理由はハードが壊れることです。それに、リコール対象とはいってもそんなに壊れることはないだろうと思っていました。もしくは、あと半年ぐらいは大丈夫だろうと。でも、でも、でも、ハードディスク壊れちゃいました。

まあ、数ヶ月前ぐらいからスリープの後、うまく復帰できないことがたびたびあったんですが、ひょっとしたらそれが前兆だったのかもしれません。ちなみに、リコール対象ということもあって、ちゃんとTimeCapsuleにバックアップはとってありましたとも。

ということで、初めてAppleのサポートに電話しました。いやいや、Webから申し込むと、向こうから電話がかかってきました。最初は男の人からかかってきたのですが、僕の操作ミスで電話をきっちゃいました。もう一度申し込むと、今度はおねーさんが電話をかけてきました。よかったよかった。
で、シリアル番号を教えてくれ、っていわれたんですが、そんなもの、起動できないのでわからない、って答えると、iMacの底に書いてあるって。iMacを裏返すと、シリアル番号が書いていました。しかし、小さい。読むのが大変。こんな見えないところに書いてあるんだから、もっと大きく書けばいいのに。このこだわりはわかりません。ちなみに、iMacは片手で持てます。モバイルマシンです。iMacのキャリーケースも売られているぐらい、モバイルです。

で、いろいろお話ししてとりあえず、ハードディスクは交換しようということになりました。翌日の土曜日の夜、黒猫さんが専用の箱を持ってきてとりにきてくれました。いつも来る黒猫さんの人で、重いですね、壊れちゃったんですよ、わはは、とお話しながら梱包されて運ばれていきました。
戻ってくるまで4、5日かかるって言われていたので、次はまたiMacを買うかMacBook Proでならどのスペックで買うかって妄想しながら待っていたら、月曜の夜に戻ってきちゃいました。48時間ぐらいですね。はやっ。妄想モードは終わらされてしまいました。

戻ってきたiMacはホコリもなくきれいでした。液晶もきれいに拭かれていていました。ハードディスクにはクリーンなMountain Lionのインストール直後の状態でした。

ということで、バックアップデータからの復旧とか、アプリのインストールとかが始まるのでした。

まあ、直ってよかった。まだまだ、現役で使えそうでちょっと悲しいかもです。

websocket-clientの0.11.0がリリースされた

$
0
0
と言うことです。先日来たVに「いつまであんなもん、メンテナンスしてるんだ?暇人め」と言われたような気もしますが、気にしません。そう言えば、雑談ばかりでやつは何しに来たんだ? と言うことはいいとして、Pythonのwebsocket-clientの0.11.0(python2.7, python3.3)をリリースしました。この人は、もともとはWebsocketのプロトコルの勉強のために作ったので、メンテナンスするつもりはありませんでした。なので、メンテナンスした人にはプレゼントします。spdyも何かやろうかとドキュメントを少し読んだのですが、control frameあたりで飽きちゃいました。

websocketとspdyだと、どちらかがあればいいように感じて、spdyの方が明るい未来を提供しているような気がします。いや、そんな話はこのタイトルで書いちゃいけない・・・。
Websocketはすばらしいので、このwebsocket-clientも使ってください。使い慣れた同期通信でコードが書けるのはちょっとしたものを作るときには楽だって偉い人が言っていました。一応、Python2.7と3.3では動作確認していますです。他はしりません。

変更点は、


  • close処理したときのログ出力が変わったこと
  • originヘッダーが不正になるケースの修正
  • filenoのサポート
filenoは僕はなぜ欲しいのか、よく分かりません。そんな感じです。

でわでわ



websocket-client 0.12.0がリリースされている

$
0
0
放置して何もしないでおこうと思っているのに、バグ報告は来るし、websocketのフラグメンテーションはサポートしていないのはどういうこっちゃ!、って外人におこられるし。フラグメンテーションは放置していたらテストコードだけ送られてくるし、僕は欲しいのは実装の方なのに…。で、気になって調べたら、フラグメンテーションは僕が昔スペックを読んだときのものと変わっているし…。

ということで、いろいろ直した0.12.0がリリースされました。pypiからいんすとーるできますです。
まあ、ほとんどがバグフィックスです。ちょっと大きめな変更は、timeoutはWebSocketTimeoutExceptionを投げるようにしました。2系のPythonでSSLを使っているとssl.SSLErrorがtimeoutの時に投げられるんですが、これがいろんなエラーとごっちゃになっていて、messageでtimeoutかどうか判別しないといけない。で、ssl使わないとsocket.timeoutが飛んできて残念な気持ちになるらしいということでした。Python3は3.2ぐらいからすべてのsocket.timeoutに統一されているので、あんまり気にしなくてもいいらしい。互換性のために2系には入れないって書いてあった気がする。

あとは最初にあったフラグメンテーションをサポートしました。opcodeがTEXTとかBINARYとかCLOSEとかPING/PONGとかにCONTが追加されていた。ということです。

それ以外の大きなところでは、timeoutしたときにその後はcloseしないとオブジェクトの状態が変になっていたのですが、timeoutしてもそのままrecvとかすれば処理を継続できるようになりました。

あとは、python3でのバグフィックスがいくつか。ぼくはまだ、ほとんどpython3使っていないです。

そんな感じ。

Fuelband SEがやってきた

$
0
0
アリエルにも健康ブームがやって来ています。まあ、人間、やることがないと健康とか美容にはしるのかも知れません。そんなこんなで、今話題のNike+ Fuelband SEがやって来ました。いや〜、買おうと思ったときは在庫切れで12月まで手に入らないんじゃないかと思っていましたが、割と潤沢。

 佐川急便が運んできました。えー、色は黄色いやつです。サイズはM/Lです。僕にはぴったしのサイズでした。手首は細いので・・・。

箱、小さいです。
あけると、こんな感じ。
まあ、シンプルです。説明書はいろんな言語で書いてあって、すぐに日本語が見当たりません。まあ、セットアップが終わって充電を始めてから日本語のページを発見。
最初から充電しておいてくれればいいのに・・・。セットアップはすぐに終わりますが、充電は長い・・・。

セットアップが終わらんとか、iPhoneのアプリと連携できないとか、きな臭い噂がありましたが、別段、不具合にあうこともなく、ちゃんと使えているっぽい。

Nike+ Moveの人とは闘えないっぽいので、それは残念です。もし、Fuelband盛っている人がいたら友達になってほしい今日この頃。

Mint Linux 16 petryをインストールしてやったこと

$
0
0
僕はUbuntuのデスクトップの雰囲気が好きになれなくて、でもubuntuのように簡単に色々やりたいのでmint linux使っています。もうすぐ、親会社で働くことになったので、そこのPCにMint Linuxの最新版を入れました。アリエルだと一つ古いバージョンを使い続けています。基本的にubuntuの13.10と同じです。日本語remixは使っていません。

Mint Linuxをインストール後、次のコマンドでフォルダ名を日本語から英語に。ターミナルで操作するときに日本語だとめんどいから。全部、英語でもいいんだけど、そこは気分です。

$ LANG=C xdg-user-dirs-gtk-update

それから、設定の言語設定から、よくわからないものが勝手にセットアップします。
次にmazcのセットアップ。
$ sudo apt-get install ibus-mozc mozc-utils-gui ibus-gtk ibus-gtk3

mozc-utils-guiを明示的に入れないと、mozcの設定画面が開きません。ibus-gtkとibus-gtk3を入れてあげないと、変換ウィンドウが変な位置に表示されます。必要なヒトはibus-qt4も入れてください。設定の入力メソッドを起動すると、ibusを使うように設定されるらしい。その後、ibus-setupを起動して、好きなように設定。

あとはフォントでrictyを追加で入れています。

あんまりこった使い方はしないので、このぐらいで十分かな。

OpenAMとか

$
0
0
最近、OpenAMを使ったので、その時のメモ。
セットアップの仕方とか、エージェントの設定の仕方は井上大先生のコラムを読めばいいです。OpenAMはOpenSSOからフォークしたものです。なので、名前が多少違いますが、セットアップの仕方とか、ほとんど同じです。それから、OpenAM ver. 10はtomcat 8.0 RC1とかじゃ起動しなかったので、tomcat 7などの安定したバージョンを使いましょう。

さて、OpenAMへの経緯ですが、要求として次のものがありました。

  • 複数のシステムでSSO
  • 認証基盤の統一
  • 認証強度をプラグイン的に変更可能
ごく一般的な要求ですね。

複数システムでのSSOは、OpenAMの前進のOpenSSOの名前が示す通り、シングルサインオンするものです。毎回、ログイン画面がでるのは嫌で、一度どこかで認証を済ませておけば、他のシステムへログインせずに入って行きたい、ってことですね。
OpenAMじゃなくっても、Windowsの世界であればWindows統合認証でSSOが可能です。AD FSをセットアップすれば、SAML認証が使えるようになるので、Google AppsなどでもSSOが可能になります。でも、会社によってはADを管理しているところがガチガチだと、ADにお触りするのは結構ハードルが高かったりします。反対に、ADが名前だけになっていて、まずADはあるけど意味がない状態のところもあったりで、なんとも悩ましいところです。

認証基盤の統一と言うか、 自前で認証をするのはそろそろやめるべきじゃなかろうか、と思い始めているからです。これは次の認証強度をプラグイン的に変更可能、っていうのもあるんですが、今後、認証まわりは強化される方向に行くんじゃないかな、って。最初はインターネットにさらされているものだけが、認証を強化する必要があると考えていましたが、イントラネット内でも同じ程度にセキュリティを意識しなければいけなくなりつつあると。
認証を次第に強化していく時に、プラグイン的に(設定で)強度を変更できるようにしておきたいです。例えば、フォーム認証から、2要素認証に変更したいとか、ログインを試行したロケーションによって制御したいとか。アリエルの製品はSpring FrameworkをベースにしていてSpring Securityを使えば、ある程度これらのことは実現可能ですが、これらの認証をもっと粗結合にして外部に切り出したいですね。これらを切り出せれば、他のシステムも少しの対応で認証が強化されます。

ということでOpenAMや、商用のSSOの製品を今後ちゃんと検討する必要があると感じています。

でも、SSOなので、最初の認証さえ突破されればおぞましい世界が待ち受けていますね。

おっとポリシーエージェントの動きとか説明しようと思っていたけど、そっちはまた、気が向いたら。

bcryptのラウンド回数と実行時間

$
0
0
「sha? md5? じじい!」って会社の@kirisに罵倒された気がして、「ナウでヤングな若者はbcryptだよ」と蔑んだ目で見られたので、bcryptでround回数を変更すると実行時間はどうなるんだろう?って言うことで、計測してみました。bcryptが何なのか、ってのは、自分で調べてね。
py-bcrypt使って計測していますが、計算処理はCのコードで書かれているっぽいです。

コードは、

import timeit
for i in range(1,20):
print timeit.timeit("bcrypt.hashpw('password', bcrypt.gensalt(" + str(i) + "))", setup="import bcrypt", number=1)

です。計測結果ですが、

ラウンド数時間(sec)
1 0.002
2 0.002
3 0.002
4 0.002
5 0.004
6 0.004
7 0.007
8 0.015
9 0.031
10 0.063
11 0.125
12 0.256
13 0.516
14 1.0121
15 1.9985
16 4.0332
17 8.0246
18 16.1026
19 32.1371
20 64.3373

グラフにするとこんな感じ。
いい感じに計算時間が伸びていきます。でも、デフォルトでは12回でそれが256m secはちょっと遅いですね。計測したスペックのマシンだと10回か11回が限界ですね。100m secには収めたい。

javaのenum

$
0
0
とあるところで書いたものの転載


昔のコード

  int sex = 0; // 1: male, 2: female, 0: other

数字の意味が思い出せない年寄りのために、昔のコードをちょっとだけリファクタリング

  public static final int SEX_MALE = 1;
  public static final int SEX_FEMALE = 2;
  public static final int SEX_OTHER = 0;

  int sex = SEX_OTHER;

でも、こんなコードが何処かで…

  this.sex = 3;

maleとfemaleを足しあわせたものはOTHERじゃなくって、3という発明をしちゃった開発者が…。そんな発明は素敵だけど、もう、させないぞ。

  public enum Sex {
      MALE(1),
      FEMALE(2),
      OTHER(0);

     private int v;
    
     private Sex(int v) {
         this.v = v;
     }
   
     public int getIntValue() {
        return v;
     }
  }

  Sex sex = Sex.OTHER;

※ public enum sex {OTHER, MALE, FEMALE}でもいいけど、特別な値もいれられるために、あえて上のように書いています。

これで、MALEとFEMALEを足しあわせたものは、勝手に作れなくなったよ。


でも、formがポストしてくるのはfemaleとかmaleとかの文字列です。どうやって、区別するんですか?

  if (value.equals("male")) {
     sex = Sex.MALE;
  } else if (value.equals("female")) {
    sex = Sex.FEMALE;
  } else {
    sex = Sex.OTHER;
  }

嘘です。こんなコード、書いていたら、アリエルのこわーい中山さんという人に袋たたきに会います。

  sex = Sex.valueOf(value.toUpperCase());


でも、フォームの場所によっては数字で来るんです。
じゃあ、Sexがもっといろいろできるようにしたちゃえ。

   public enum Sex {
     : 中略
     public Sex valueOf(int v) {
        for (Sex s: Sex.values()) {
            if (s.getIntValue() == v) {
                return s;
            }
         }
         return OTHER;
     }
   }

でも、変な値が来たら無条件にOTHERにするのはどうも・・・。ということで

     public Sex valueOf(int v) {
        for (Sex s: Sex.values()) {
            if (s.getIntValue() == v) {
                return s;
            }
         }
         throws IllegalArgumentException("sex : " + v);
     }

javaのEnumSet

$
0
0
とあるところで書いたものの転載 

EnumSetは、ビット集合を扱っていないとよくわかってもらえないんじゃないかと思ってるんですが、EnumSetについてのお話です。
Cの世代のビット演算大好きなおっさんの話は書かないので、そっちは自分で調べてください。それから、メモリの話もしないです。

それから、これを読むときはカービーダンスの樫木先生のしゃべり方を思い出しながら読んでね。

-----------------

さて、コードの中を見ていると、こんな感じでbooleanで設定のon/offを制御しているところが沢山あるんだよ。

class MySomeClass {
    private boolean opt_1 = false;
    private boolean opt_2 = false;
    private boolean opt_3 = false;
    private boolean opt_4 = false;
     :
}

多分、コードを書いている人はこんなの沢山見ているはずだよ。前回のenumの場合、オプションでとりうる値が複数あって、その中の一個を指定できるってことだったんだよね。でも、今回みたいに、booleanで複数のオプションがあって、その組み合わせがある場合、enumだけだと制御できないよね。

で、そんな組み合わせを簡単に扱えるようにするのがEnumSetなんだ。って言っても、わかんないよね。
コードで見ていったほうがいいかな。

オプション関係は一つのまとまりなので、まとまりはまとまりとしてわかりやすくしたいよね。で、enumでオプション関係をきり出しちゃいます。

class MySomeClass {
   static enum MyOpt { opt_1, opt_2, opt_3, opt4 };
}

それで、実際の値を保持する部分はEnumSetに指定するよ。

class MySomeClass {
   public static enum MyOpt { opt_1, opt_2, opt_3, opt_4 };
   private EnumSet opt = EnumSet.noneOf(MyOpt.class);
}

こんな感じで、4つあったオプションのフィールドが一個にまとまっちゃいました。
実際に使うときは、普通のSetと同じように扱えるよ。

  opt.add(MyOpt.opt_1)

って感じでオプションをセットできるよ。

  opt.contains(MyOpt.opt_2)

のようにして、値がセットされているかどうか判定できるよ。使うときにbooleanそのものよりもちょっと面倒だけどね。

値を削除するのはremoveだよ。


もうちょっと別の使い方は、メソッドの引数がbooleanの羅列で動作を変える場合だよね。
こんなメソッド、気がついたらよくできちゃっているのよね。

public void func(boolean opt1, boolean opt2, boolean opt3, boolean opt4) {
   :
}

で、さらに今回opt5が必要になった・・・。悪夢だよ。そんなら

public void func(EnumSet opt) {
   :
}

ほら、スッキリした。使う方は、メソッドのマニュアルを見ながら、オプションの意味を確認していたのが、enumの値を見ればオプションの意味をしることができるよ。
最後に呼び出し元を見てみよう。

func(true, false, false, true);

  ↓

func(EnumSet,of(MyOpt.opt1, MyOpt.opt4));

どっちが分かりやすい?




うーん、やっぱりビットのお話から入ったほうが良かった?

どきどきJavaの国際化

$
0
0
※ とあるところでかいたものの転載


それでは、それでは。

変数名とかに英語表記ではなく、ローマ字で記述しているコードって沢山あるじゃないですか?アリエルは開発フレームワークなので、Javaのコードにはローマ字表記はコーディング規約として許していませんが、その上で作るアプリケーション(JavaScriptで記述)はちょっとカオスなところがあって、変数名にローマ字表記されているところもあります。

あっ、今回もJavaのお題です。僕はJavaScriptは嫌いなので…。

例えばこんな感じ

  public class MyClass {
      private int hensu = 1;

      public int add(int v) {
          hensu += v;
          return hensu;
     }
          
      public static void main(String[] argv) {
          MyClass obj = new MyClass();
          System.out.println(obj.add(10));
      }
  }

英語でもそうですけど、ローマ字でも読みにくいですよね。日本人なら日本語(漢字とかひらがな、カタカナ)ですよね。
ということで、変数名も日本語にしちゃいましょう!


  public class MyClass {
      private int 変数 = 1;

      public int add(int v) {
          変数 += v;
          return 変数;
     }
          
      public static void main(String[] argv) {
          MyClass obj = new MyClass();
          System.out.println(obj.add(10));
      }  }

ほら、読みやすくなった。じゃあ、メソッドも日本語化したほうがわかりやすくなるんじゃない?


  public class MyClass {
      private int 変数 = 1;

      public int 加算(int 入力値) {
          変数 += 入力値;
          return 変数;
      }

      public static void main(String[] argv) {
          MyClass インスタンス = new MyClass();
          System.out.println(インスタンス.加算(10));
      }
  }

ほら、スッキリした。クラス名も日本語に…。えーと、僕は日本語のファイル名があまり好きではないので、それはしません。インナークラスだったら許せます。なので、


  public class MyClass {
      static class 算術クラス {
          private int 変数 = 1;
         
          public int 加算(int 入力値) {
              変数 += 入力値;
              return 変数;
          }
      }

      public static void main(String[] コマンドライン引数) {
          算術クラス インスタンス = new 算術クラス();
          System.out.println(インスタンス.加算(10));
      }
  }


ほら、すごーく分かりやすい。Javaって素敵。でも、悲しいことが2つあります。1つ目はIMEを切り替えながら使わないといけないこと。これは、慣れの問題なのでがんばりましょう。もうひとつは、エディタによっては、全角空白が入り込むと、見つけるのがちょっと大変になることかな。

そう言えば、アリエルもJavaのテストコードに日本語のメソッド名を使っているところがあったような気がする。
ちなみに、pythonで同じようなことをした時のもの。
  http://blog.liris.org/2012/02/python3.html


※ 今回はネタでした。
※ 次回はlombokかもしれない。でも、スレッドのお話かもしれない。グローバル変数についてのお話かもしれない。

try-with-resource statementはjava7からだったのか…

$
0
0
※ とあるところで書いたことの転載です

普段、Java7で生活しているとJava6だとめんどうだなー、って感じることがありますよね。みんな早くJava7とかJava8に移行したほうがいいよね。

って言うことで、IO関係の処理ってcloseメソッドってIOExceptionがつきまっとっていて、うざいよね。みんなこんな感じで書いていると思うんだ。

InputStream io = null;

try {
    io = new FileInputStream("somefile")
    いろんな処理
} catch (IOException e) {
    例外処理的な何か
} finally {
    if (io != null) {
        try {
            io.close();
        } catch (IOException e) {
            // なんもしない
       }
    }
}

沢山の行数が必要ですね。Javaはなんと生産性の高いことか!じゃあ、Java7だとどうなるのか、って言うと、

try (InputStream io = new FileInputStream("somefile")) {
     いろんな処理
} catch (IOException e) {
    例外処理的な何か
}

はい、おしまい。余分なことが抜けてスッキリして、必要最小限のことに
CloseableかAutoCloseableのインターフェースを継承している人なら、tryから抜けてfinallyに入る直前に後始末をしてくれます。ちょーべんりー。プログラマは怠惰なものさ、ってきっとATEの誰かが言っています。
自動でクローズされなくても、スコープがtry節の中に限定されるだけでもスッキリします。(変数はなるべく局所化したほうがいい)

でも、プロダクトでJava7に上げてもらえないんですぅ。そんなあなたにlombok。この子さえいれば、さらにハッピーに。


@Cleanup InputStream io = new FileInputStream("somefile")
いろんな処理


@Cleanupは http://projectlombok.org/features/Cleanup.html
もう、魔法ですね。ただしlombokはバイトコードをいじるので、導入には許可をとってからにしましょう。一度、この子に触れると、普通のJavaは書けない体になってしまうので、気をつけましょう。

ちなみに、上の奴はさらに短く…

@Cleanup val io = new FileInputStream("somefile")
いろんな処理

javaのiteratorとかiterable

$
0
0

※ とあるところに書いたものの転載です。
※ Java8の話はまた、あとで


こんなコードよく書くよね。


BufferedReader reader = new BufferedReader(new FileReader("myfile.txt"));
String line = null;
while ((line = reader.readLine()) != null) {
     System.out.println(line);
}

まあ、でも、ループの条件式とのとことか、微妙でわかりにくいし、変数のスコープも大きいよね。と言うか、どっかのスクリプト言語みたいに


BufferedReader reader = new BufferedReader(new FileReader("myfile.txt"));
for (String line: reader) {
     System.out.println(line);
}

みたいに書きたくない?
ということで、そこら辺のもの。拡張forループとか言っても、結局iterator使ってグルグルイテレートしているだけ。なんで、イテレートできるようにしてあげたら上みたいな感じで書けるはず。ちなみに、拡張forループ使わずに

for (Iterator iter = reader.iterator(); iter.hasNext();) {
    String line = iter.next();

みたいな書き方は全く嬉しくないので、forループが拡張されたからやりたくなることですね。
さて、実行時にbufferedReaderにメソッドを追加するとかは危険なので今回はBufferedReaderを拡張したIterableReaderを作っちゃいます。

import java.util.*;
import java.io.*;

public class A {
    public static class IterableReader extends BufferedReader implements Iterable {
        public IterableReader(Reader in) {
            super(in);
        }
        public IterableReader(Reader in, int sz) {
            super(in, sz);
        }
        public Iterator iterator() {
            try {
                final String l = readLine();
                return new Iterator() {
                    String last = l;
                    public boolean hasNext() {
                        return last != null;
                    }
   
                    public String next() {
                        String result = last;
                        if (last != null) {
                            try {
                                last = readLine();
                            } catch (IOException e) {
                                throw new RuntimeException(e);
                            }
                        }
                        return result;
                    }

                    public void remove() {
                    }
                };
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

        public static void main(String[] argv) {
        try (IterableReader reader = new IterableReader(new FileReader(argv[0]))) {
            for (String line: reader) {
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
       }

}

Iterableを実装したクラスを作ってあげて、その中でIteratorを返せばいいだけ。ちなみに、無名クラスにもコンストラクタ、書きたい…。
IOExceptionを投げられないので、RuntimeExceptionで代用しているのは許してください。

あれからJavaのリフレクションのスピードはどうなったのか?

$
0
0
僕が一番最近Javaのリフレクションのパフォーマンスを計測したのは、今のアリエルの開発を始めたぐらいで、ライブラリの選定をしている時でした。jdkのバージョンも覚えていません。それより前はいつやったのか覚えていません。
その時の結果の詳細は残っていませんが、リフレクションは通常のアクセスより10倍以上遅い、って印象だけが残っています。印象でものを語るのは良くないし、バージョンが上がるに連れて改善されているのかもしれないので、もう一度計測してみました。

以前は自分でコードを書いていたのですが、今回はサボって http://www.ibm.com/developerworks/jp/java/library/j-dyn0603/ にあるコードで試します。このページには1.4での計測結果ものっていて、いいかも。

ちなみに、今回はLinux上のSunのJDKでコンパイル・ビルド・実行しています。それから、結果に乗っている最初の一回目の数値は無視してください。

まず、リフレクションでオブジェクトを作るときの結果です。

Java version 1.7.0_51
Java HotSpot(TM) 64-Bit Server VM
24.51-b03
Oracle Corporation

Direct Object creation:
 49 1 2 1 2
 average time = 2 ms.
Reflection Object creation:
 44 3 3 2 3
 average time = 3 ms.
Direct byte[8] creation:
 10 7 8 11 10
 average time = 9 ms.
Reflection byte[8] creation:
 12 8 8 8 8
 average time = 8 ms.
Direct byte[64] creation:
 101 79 37 8 7
 average time = 33 ms.
Reflection byte[64] creation:
 7 7 7 8 8
 average time = 8 ms.

Direct Object creation:
 2 2 1 3 1
 average time = 2 ms.
Reflection Object creation:
 2 4 5 4 4
 average time = 4 ms.
Direct byte[8] creation:
 9 6 7 8 8
 average time = 7 ms.
Reflection byte[8] creation:
 8 8 10 9 8
 average time = 9 ms.
Direct byte[64] creation:
 9 8 11 9 7
 average time = 9 ms.
Reflection byte[64] creation:
 9 11 11 10 8
 average time = 10 ms.

オブジェクトの作成は若干リフレクションの方が遅いですが、使用用途にもよりますが、この程度であればリフレクションを使ってもそれほどオーバーヘッドもなく、問題ないでしょう。


次にオブジェクトの中のフィールドへのアクセスです。昔、偉い人が「privateなんて飾りです。リフレクションをシラン人はわからんのです。」って言っていましたが、それがこういうことです。
で、結果ですが、


Java version 1.7.0_51
Java HotSpot(TM) 64-Bit Server VM
24.51-b03
Oracle Corporation

Direct access using member field:
 8 6 6 7 6
 average time = 6 ms.
Reference access to member field:
 28 7 7 5 7
 average time = 7 ms.
Reflection access to member field:
 3544 3486 3437 3433 3482
 average time = 3460 ms.

Direct access using member field:
 7 5 7 6 6
 average time = 6 ms.
Reference access to member field:
 6 6 6 6 6
 average time = 6 ms.
Reflection access to member field:
 3538 3555 3515 3545 3482
 average time = 3524 ms.

で、reference accessはまあ、どうでもいいです。reflection accessだと、10倍どころじゃないですね。600倍ぐらい遅いです。数回だけならまだしも、アクセス数が増えると使い物にならないですね。JRubyとかJPythonは、基本的にメンバー変数に直接アクセスはしないんだろうか?

最後にメソッドの呼び出しです。

Java version 1.7.0_51
Java HotSpot(TM) 64-Bit Server VM
24.51-b03
Oracle Corporation

Direct call using member field:
 8 7 6 6 3
 average time = 6 ms.
Direct call using passed value:
 11 6 3 6 7
 average time = 6 ms.
Call to object using member field:
 10 6 7 7 6
 average time = 7 ms.
Call to object using passed value:
 8 6 5 7 6
 average time = 6 ms.
Reflection call using member field:
 71 32 30 29 33
 average time = 31 ms.
Reflection call using passed value:
 158 139 138 122 117
 average time = 129 ms.

引数なしでの呼び出しは、通常の5倍遅いです。引数ありでは20倍の遅さです。メンバー変数へ直接アクセスすするよりは、メソッドを通してアクセスするほうが効率は良さそうですね。

IBMのサイトの結果と比べると…、IBMのサイトのグラフが対数になっていて、よくわかりません。多分、あんまり変わっていないです。

ということで、

- リフレクションでのオブジェクトの作成はオーバーヘッドがほとんどない
- メンバーフィールドにアクセスするのは遅すぎるのでやらないほうがいい。
- メソッド呼び出しは5から20倍遅いので、使う場合は注意する

JITはすごいんだよ、とか

$
0
0
前回のリフレクションのベンチマークはJITの影響を受けています。Javaはコンパイル時だけじゃなくって実行時にももっと早くコードを実行できないか考えてくれるすごい子なのです。またはJITがないと使い物にならない速度でしか動かないかもしれません。普通に使用する分には可愛い子なのですが、ベンチマークするにはJITは厄介な子です。実際のソフトウエアとベンチマークでは最適化のされ方が異なるので、速度がかなり違ってきます。

で、前回の結果をJITのあるなしで計測すると次のようになります。

JITあり
=======
$ java timing.TimeCalls
Java version 1.7.0_51
Java HotSpot(TM) 64-Bit Server VM
24.51-b03
Oracle Corporation

Direct call using member field:
 231 7 6 6 6
 average time = 6 ms.
Direct call using passed value:
 8 6 6 6 6
 average time = 6 ms.
Call to object using member field:
 30 6 7 6 7
 average time = 7 ms.
Call to object using passed value:
 12 7 6 6 7
 average time = 7 ms.
Reflection call using member field:
 74 32 30 37 31
 average time = 33 ms.
Reflection call using passed value:
 179 151 145 127 120
 average time = 136 ms.

Direct call using member field:
 7 7 6 3 6
 average time = 6 ms.
Direct call using passed value:
 6 6 6 7 5
 average time = 6 ms.
Call to object using member field:
 6 6 5 7 6
 average time = 6 ms.
Call to object using passed value:
 6 6 6 6 6
 average time = 6 ms.
Reflection call using member field:
 39 31 34 38 28
 average time = 33 ms.
Reflection call using passed value:
 114 117 114 117 112
 average time = 115 ms.

JITなし
=======
$ java -Djava.compiler=none timing.TimeCalls
Java version 1.7.0_51
Java HotSpot(TM) 64-Bit Server VM
24.51-b03
Oracle Corporation

Direct call using member field:
 711 669 665 664 670
 average time = 667 ms.
Direct call using passed value:
 732 732 742 751 740
 average time = 741 ms.
Call to object using member field:
 730 696 675 676 676
 average time = 681 ms.
Call to object using passed value:
 673 686 673 681 677
 average time = 679 ms.
Reflection call using member field:
 4505 4487 4444 4448 4441
 average time = 4455 ms.
Reflection call using passed value:
 7293 7342 7386 7318 7359
 average time = 7351 ms.

Direct call using member field:
 680 666 672 679 667
 average time = 671 ms.
Direct call using passed value:
 742 736 736 744 742
 average time = 740 ms.
Call to object using member field:
 671 673 671 672 670
 average time = 672 ms.
Call to object using passed value:
 681 679 674 670 670
 average time = 673 ms.
Reflection call using member field:
 4453 4563 4521 4593 4565
 average time = 4561 ms.
Reflection call using passed value:
 7453 7307 7323 7348 7415
 average time = 7348 ms.


まあ、JITありに比べてない方は100倍遅いですね。ただし、今回は傾向は同じです。別の種類のベンチマークだと傾向が同じになるとは限りません。今回はループで何回も回していますが、最適化のされ方によってはループが回らなかったりします。

最終的にはDaoでDTOに値を詰めるって話にするつもりで、その場合メソッドの直接の呼び出しだとコストはほとんどかからない、リフレクションだとこれくらい、バイトコードを作るのはリフレクションよりは速そうだ、ってことぐらいがわかればイイかな、と。

本当はhibernateを使うのがいいのですが、これからのhibernateの導入は敷居が高いので、それじゃ似たようなコードのコピペをせずに、daoのコードをどれくらい少なくできるのか?ってことです。


それから、昔10倍遅かったと記憶していましたが、JITなしではちょうど10倍ぐらい遅いですね。記憶はあっていたのかもしれません。



http://www.ibm.com/developerworks/jp/java/library/j-jtp12214/

Java8のString::join

$
0
0
実際のコードを書きたかったのですが、すぐに思い出せないので、わずかながらの記憶で書きます。java8を使わない人も楽しめるはず。

SQL文を組み立てるときに、時々こんな感じのコードを見かけます。

コード1 ::
StringBuilder sb = new StringBuilder()
boolean isFirst = true;
for (int i=0; i<10; i++) {
    if (!isFirst) {
        sb.append(",");
    }
    sb.append("?");
}

もしくは、

コード2::
sb.append("column1");
sb.append(",");
sb.append("column2");
sb.append(",");
sb.append("column3");

ちょっと例が悪いですが、多分、こんな感じのコードにであったことはあると思います。アリエルのコードの場合、StringUtilsと言うクラスがいて、joinメソッドがあります。public static String StringUitls.join( Collection<String> elems, String delimiter)みたない感じです。

コード1のようなコードは、

String s = StringUtils.join(StringUtils.multiply("?", 10), ",")

って書けます。Javaは演算子のオーバーロードができないので、multipyってメソッドで*相当のことをしています。このへんはPythonの影響を受けているので、そっちを見るのがいいのかも。

コード2は

String s = StringUtils.join(new String[]{"column1", "column2", "column3"}, ",");

みたいな感じです。
アリエルの人たちは、「Stringにjoinがなくてめんどくさいな〜。でも、おれらはStringUtilsがあるからかんけーないね。」って思っていました。

さてさて、みんなが待ちに待ったJava8は華やかなlambdaやstream api、ついでにCalendar API(古いやつがスレッドセーフじゃないってどういうことじゃ!)も仲間に入れてあげるとして、そんな今どきの人に隠れてStringクラスの地味な拡張がjoinメソッドの追加です。アリエルはすぐにjava8に対応するので、これで十数行、全体のコード行が短くなるはず。えー、誤差の範囲です…。

で、Stringクラスにjoinメソッドが追加されて、コード1,2は次のようになります。

String s = String.join("," StringUtils.multiply("?", 10))
String s = String.join(", ", new String[]{"column1", "column2", "column3"});

スッキリ。
さて、Sting::joinはどうやって作っているのでしょうか?ちょっとだけコードを覗きます。3月11日のmercurialのリポジトリのコードです。

    public static String join(CharSequence delimiter,
            Iterable<? extends CharSequence> elements) {
        Objects.requireNonNull(delimiter);
        Objects.requireNonNull(elements);
        StringJoiner joiner = new StringJoiner(delimiter);  // ①
        for (CharSequence cs: elements) {
            joiner.add(cs);  // ②
        }
        return joiner.toString(); // ③
    }

StringJoinerという新しいクラスが登場しています(①)。このクラスは、addした文字列(②)をdelemiterで連結してくれるクラスですね。最期に、文字列の出力です(③)。アリエルのStringUtils.joinはStringBuilderで文字列をその場で組み立てていました。ちょうど、コード1を汎用化した感じですね。


StringJoinerはコンストラクタが2つあって、
  StringJoiner(delimiter)
  StringJoiner(delemiter, prefix, suffix)

こんな感じで使えますね

StringJoiner sj = new StringJoiner(", ");
sj.add("column1");
sj.add("column2");
sj.add("column3");
sj.toString();   // column1, column2, column3になる

SQL文の組み立てだと最初と最期に( )が追加したいので、そういう時は、

StringJoiner sj = new StringJoiner(", ", "(", ")");
sj.add("column1");
sj.add("column2");
sj.add("column3");
sj.toString();   // (column1, column2, column3)になる

ほら、べんり。StingJoinerの実装でも、内部的なデータの保持はStringBuilderのオブジェクトを作っていて、その人にappendをしているだけですが、APIとしてはスッキリしていて、クラスの目的も明確ですね。





次のコードはStringJoinerのStringBuilderを取得しているコードです。valueはStringBuilderのクラスフィールドです。コード1だとisFirstというbooleanの値を見て、delemiterを追加するかどうか決めていましたが、value自体をフラグの代わりに使って、こんな風に書くとそういうフラグはいらないんですね。

  private StringBuilder prepareBuilder() {
        if (value != null) {
            value.append(delimiter);
        } else {
            value = new StringBuilder().append(prefix);
        }
        return value;
    }

それから、状況によっては、value.length()>0でdelemiterを追加するかどうかを決めるというのもできますね。


「私は、Stream APIとlambdaがあれば十分よ。String::joinなんていらない子よ」って。ごめんなさい。そういう人はそっちを使ってあげてください。

拡張forループでループの回数も同時に欲しいよね。

$
0
0
ちょっとだけ、拡張forで質問があったので、追加です。
前回の記事の中で次のように書いています。

https://ckip.worksap.co.jp/aqua/a46fa1c4-701d-4279-af87-3ba10eedf94b/view?exa=blog

> 拡張forループはいいのですが、今がコレクションの何番目か、ってのが取れたらもっと良かったのに…。

これは言語仕様としてはインデックスの位置が取れないと言うだけです。ちょっと別の言語で、goの場合は次のように書けてインデックスも同時に取得できます。便利ですね。

array := []string {"hoge", "fuga"}
for index, value := range array {
   // do something...
}

Javaのforループでは2つの値をとることができませんが、自前でイテレータを書くことができます。イテレータを自分で書いた時のお話はこれ。
https://ckip.worksap.co.jp/aqua/8c23f0a7-585d-46ce-ac9e-01313b73d644/view?exa=blog

拡張forループで使えるようにするには、Iterableをimplementすればいいだけです。
で、こんな感じで使えるようになれば、まあ目的は達成できますね。

public class IndexableIterator<T> implements Iterable<T> {
   public static class Entry<T> {
        final int index;
        final T value;
        private Entry(int index, T value) {
            this.index = index;
            this.value = value;
        }
        public int getIndex() { return index; }
        public T getValue() { return value; }
    }


   // TODO: implement
}

というような感じで、IndexableIteratorを作って、実際に使う場面では

List<String> l = new ArrayList<String();
l.add("hoge");
l.add("fuga");
for (IndexableIterator.Entry<String> entry: new IndexableIterator<String>(l)) {
    int index = entry.getIndex();
    String v = entry.getValue();
    // do something...
}

みたいな感じですね。あとは、IndexableIteratorのTODOってところを実装すればいいだけです。



で、Java8のStream使って書こうかと思ったら、標準ライブラリからいつの間にかzipメソッドがなくなっているのね・・・。なので、Java8のstreamは池添さんが書いてくれるはず。

DaoでのResultSetへのアクセスはenumでいいよね

$
0
0
Java8でラムダが使えれば…。
で、DaoでResultSetへのアクセスでインデックスでアクセスする場合、

int index=0;

dto.setX(resultSet.getInt(++index);
dto.setY(resultSet.getInt(++index);
dto.setZ(resultSet.getInt(++index);

ってアクセスさせるとメンテナンス性が落ちるよね、って話しでした。個人的にはカラムでのアクセスで問題ないと思っていますが、インデックスでのアクセスもenumでアクセスさせれば、もう少し、メンテナンス性が上がります。

こんなかんじですね。

enum ColumnName  {
    column1,
    column2,
    column3;

    public int getIndex() {
        return ordinal() + 1;
    }

    public static String getSelectStatement() {
        StringBuilder sb = new StringBuilder();
        for (String s: ColumnName.values()) {
            if (sb.length()>0) {
                 sb.append(",")
             }
             sb.append(s):
          }
     }
}


SQL文を組み立てるときは


    String sql = "SELECT " + ColumnName.getSelectStatetement() + " FROM SOME_TABLE"

ResultSetは、

    dto.setX(rs.getInt(ColumnName.column1));
    dto.setY(rs.getInt(ColumnName.column2));
    dto.setZ(rs.getInt(ColumnName.column3));

ほら。フィールドが追加されてもenumに値をセットするだけで、順番も意識しなくてよくなりました。

まあ、enumに値を追加することに神経を集中してdtoに詰めるのを忘れちゃいそうですね。

で、これがもう少しメンテナンス性は挙げられるようになる、と書いていた理由です。
ということで、技術は楽をするための道具です。言語に新しく追加されたものは、世界中の頭のいい人が、もっと楽をしたいと思って追加されるものです。なので、マゾな人以外は積極的に新しいものを使って、楽をできるところは楽をして、本質的に難しいところに開発者は専念すべきなのです。そのために、新しい技術を追い求めるのです。いやいや、それは嘘です。僕は新しいものが好きだから、追い求めるだけです。


それから、そのうち、リフレクションしたくなってくるかもしれません。でも、それすると、メンテナンス性が更に高まりますが、パフォーマンスは少し落ちます。我慢してください。その次がバイトコード生成ですが、そこまで行くと、もう、あちらの世界の住人になって、もう、戻ってこれません。気をつけてください。

追記
======

最近は朝、家を出る時が夜ではなく朝になってきて、ちょっと嬉しいです。

ということで、昨日の続き。昨日のように慌ただしいタイミングじゃないのでゆっくりと書けます。

まず、前提としてenumはやれば出来る子です。どこかでenumは所詮はクラスだよ、と書いたつもりですが、所詮はクラスなので、クラスでできることは大体出来ます。Effective Javaにはシングルトンもenumでできるよ、って書いていたように思いますが、僕は実際にやったことはないです。

さて、所詮はクラス、されどクラスなので、enumもinterfaceを身にまとってかっこ良く振る舞ってくれます。
例えばこんな感じ。

interface Ge {
    public void urya();
}

enum Ho implements Ho {
    H {
        public void urya() { System.out.println("Hoo"); }
    },
    G {
        public void urya() { System.out.println("Gee"); }
    }
}

で、 Ho.H.urya()って感じで使えます。なので、

for (Ho h: Ho.values) {
    h.urya();
}

で全部回りますね。


じゃあ、本題です。Daoでdtoにブツを詰め込むときに、場所が離れていると詰めるのを忘れがちになります。頑張ればHibernateがやっているようにもっとスマートにできなくもないですが、それならHibernate使えよ、ということになってしまいます。なので、現実的な妥協点は次のような感じ。
変数名とかメソッド名は割と適当なので、適当に置き換えてください。。


interface Binder {
    public void bind(int position, ResultSet rs, Dto dto);
}

enum Column implements Binder {
    FIELD_A {
        public void bind(int position, ResultSet rs, Dto dto) {
            dto.setField_A(rs.getInt(position + 1);
        }
     },
     FIELD_B {
        public void bind(int position, ResultSet rs, Dto dto) {
            dto.setField_B(rs.getString(position + 1);
        }
     };


     public String listFields() {
         StringBuilder sb = new StringBuilder();
         for (Column c: Column.values()) {
             if (sb.length() > 0) {
                 sb.append(",");
              }
              sb.append(c.name());
          }

           return sb.toString();
    }
}


で、もう一度、SQL文を組み立てるときは、

    String sql = "Select " + Column.listFields() + " From Some_table";

Dtoに値を放り込むときは、前回の記事で書いたIndexableIteratorがある前提で

    for (IndxableIterator.Pair<Column> pair: new IndexableIterator<Column>(Column.values())) {
        c.getValue().bind(c.getIndex(), resultSet, dto);
     }

ってやれば関連が強いものが近くに置かれて忘れ難くなった。フィールドが追加されたら、enumのところとdtoに追加すればいい。で、interfaceとenumはDTOの中にInner Classとして宣言すれば、関連性がより強くなって忘れにくい、変更箇所が局所化できますね。
それに、DAOの方はコードの変更が必要なくなるおまけ付き。

Java8のラムダとか、FunctionalInterafaceが入ってくると、各bindメソッドがラムダ式でもっと簡単に書けて、初期化の引数として渡せるので、かなりスッキリするはずです。


ということで、これくらいがJava7までの現実的な妥協点じゃないでしょうか?

最期におさらいをすると、enumはあなたが思っている以上にできる子なのです。

拡張forループでループの回数も同時に欲しいよね、でこんなふうに書いた

$
0
0
昨日のアリエルであったJava8の勉強会で、iteratorをそのままstreamに流せないと初めて知って、いささかめんどくさい感があったりもしますが、世の中、そんなものです。あったかくなってきたとか、朝が夜ではなく朝になってきたとか、桜が咲いたとか、浮かれている場合ではありません。

前回、iterator自分で書いてみない?ってことで、だれも書いてくれなくってとても残念です。なので、自分で書いてみました。

import java.util.*;

public class CollectionUtil {
    public static class Entry<T> {
         int index;
         T value;
         Entry(int index, T value) {
             this.index = index;
             this.value = value;
         }

         public int getIndex() { return index; }
         public T getValue() { return value; }

    }

    public static <T> Iterable<Entry<T>> enumurate(Iterable<T> iterable) {
        final Iterator<T> iter = iterable.iterator();
        return new Iterable<Entry<T>>() {
            public Iterator<Entry<T>> iterator() {
                return new Iterator<Entry<T>>() {
                    int index = 0;
                    public boolean hasNext() {
                        return iter.hasNext();
                    }
           
                    public void remove() {
                        iter.remove();
                    }

                    public Entry<T> next() {
                        return new  Entry<T>(index++, iter.next());
                    }
                };
            }
        };
    }


    public static void main(String[] argv) {
        List<String> l = new ArrayList<String>();
        l.add("hoge");
        l.add("fuga");
        for (Entry<String> entry: CollectionUtil.<String>enumurate(l)) {
             int index = entry.getIndex();
             String v = entry.getValue();
             System.out.println(index + "" + v);
        }
    }
}

色がついていないと、ちょっと読みにくいですね。IDEにでも貼り付けて、綺麗にしてください。

で、僕はPythonista(Pythonを使う人)だったらしいので、enumurateってメソッドを作ってあげて、その人がiterableのオブジェクトを返すことにしてあげました。やっていることは基本的には同じです。なんとかクラスを実装してください、って課題なのに、設問をいきなり無視しています。年寄りはそんなものです。我慢してください。

この手のメソッドを作るときによくやるのが、引数とかで本当の具象クラスを指定することはさすがにないと思いますが、ListやCollectionを指定しちゃうことが多いです。enumurateの中身は引数からiteratorが取れればいいだけなので、Itarableインターフェースを指定します。曖昧にできるところはなるべく曖昧にしておいたほうが、メソッドがいろいろ使いまわせてよいのです。



無名クラス、いっぱい。なぜ、無名クラスにしたのかって言うと、クラス名を何にするか決められなったからです。

Iteratorは、Javaに限らず一般的なプログラミングの概念です。気になる人は、パーフェクトJavaの181ページを読んでください。あれ?無名クラスについては書いていない気がする。井上さん、追加してください。それから、マルチスレッド的なことも、Concurrentを追加してください。その代わりにGUIの部分はなくてもいいです。
それから、enumはやれば出来る子なので、もっと詳しくして欲しいです。

保土ヶ谷のジムとか

$
0
0
ほっといたら、だんだん書かなくなるので…

で、平塚から横浜の保土ヶ谷に引っ越して数カ月がたちました。平塚にいたころは、セントラルのフィットネスクラブか市のトレーニングルームに行っていました。まあ、市のトレーニングルームはちょっと遠かったので、セントラルが休みの時とか、数えるほどしか行ってませんが…

で、保土ヶ谷に引っ越して、近くにジムはいくつかあります。健康保険の福利厚生で利用できるのは天王町のコナミです。でも、ここ、狭い!まあ、狭いのはいいです。マシンが古い。使えなくもないのですが、狭い上にボロっちいマシンだとモチベーションが上がらないし、なんだか、筋トレコーナーが済に追いやられている感じがしてちょっと・・・。でも、スタッフのおねーさんは可愛かった。でも、一回行っただけで行くのをやめました。横浜のコナミは高いので無理です。

そのあと、保土ヶ谷区のスポーツセンター(横浜市のやつ)にしばらく、行っていました。一回300円でリーズナブルですが、それなりに混んでいます。 トレッドミルは結構使われていて、空くのをじっと待つのです。フリーウェイトのコーナーは強うそうな人たちが独占してます。あんなところ、怖くて入っていけません。まあ、そもそも、フリーウェイトのコーナーに入るには講習を受けないと行けないらしいですが、めんどくさくて受けてません。なので、あそこに入る資格すらありません。マシンは去年、入れ替えたばかりなので、どれも新しくて綺麗です。

で、そんなこんなで、もうちょっとジムにちゃんと行きたいな〜、って思って、駅ビルにあるJexerに行ったんですよ。見学に行った時、潰れるんじゃないかってぐらい、空いてるんです。いいですね。基本的に空いていて、混む時間帯でもそれなりみたいです。経営する方は大変かもしれませんが、利用する方はいいですね。2ヶ月ちょっと通っていますが、ほとんど順番待ちをすることがないです。有酸素系は全く待たないです。利用人数に対して有酸素マシンの数が多すぎます(笑)。

でも、ちょっと狭い。でも、狭すぎることはないです。で、筋トレと有酸素運動しかできません。プールはないし、スタジオもないです。プールもスタジオもどちらも使わないので、それらがない分、安いのはいいです。えーと、月5000円ぐらいです。あと、サウナは欲しい…。かも。

でもって、スタッフの人も暇なのか、いろいろ話しかけて来てくれるので、いい感じです。いや、最初は黙々とやれればいいと思っていたので、うっとおしかったです。でも、フォームがおかしかったらこちらから言わなくても教えてくれるし、何かを発見しても教えてくれるし、いい感じです。ただ、他の人に教えているのを見ていると、他の人には最初は軽い重量で教えているのに、僕には普通の重量を与えられます。

で、全体的に空いていて、フリーウェイトのところにも、とっても強うそうな人はいません。平塚のジムはバーベルに人がいると数十分ぐらい専有し続けていました、ここはそんなに長時間専有し続ける人がいないです。まあ、フリーウェイトはちょっと混み気味と時もありますが、そんな時も少し待てば使えます。

それと、スタッフの人は休憩時間とか仕事が終わったら、一緒にトレーニングしています。いいですね。

あっ、あと、このジム、社員のひとは人の名前をちゃんと覚えています。バイトの人はよくわからないですが・・・。普通に○○さん、って呼びかけてきます。
あと、3日行かないと、「久しぶりですね」って言われます…。

Javaとか

$
0
0
原稿の残りの部分。

コレクションAPI

Iterableインタフェースを実装してみよう

前節でIterableインタフェースを実装したオブジェクトであれば拡張forループで回すことができると書きました。つまり、自作のクラスでもIterableインタフェースを実装していれば、拡張forループに対応できます。
例えば、リストの要素をループで回すとき、一緒にインデックス番号を取得して処理したいケースがあります。インデックスアクセスをする場合は、次のように記述します。
List list = Arrays.asList("foo", "bar", "buzz");
for (int i=0; i
このコードを拡張forループで記述すると次のようになります。
List list = Arrays.asList("foo", "bar", "buzz");
int index=0; // (1)
for (String str: list) {
System.out.println(index + "" + str);
index++; // (2)
}
(1)でインデックス番号を保持する変数を宣言して、(2)でインデックス番号をインクリメントしています。せっかく、拡張forループで簡潔に記 述できるようになったのに、インデックスでのアクセスのようにインデックス番号をまた管理しなければならないのは煩雑です。イテレータでループするとき に、インデックス番号も合わせて管理できれば便利じゃないですか?
ここでは、インデックス番号とリストの要素を管理できるイテレータを作ってみましょう。利用方法は次のようになります。
List list = Arrays.asList("foo", "bar", "buzz");
for (CollectionUtils.Entry entry: CollectionUtils.enumurate(list)) { // (1)
System.out.println(entry.getIndex() + "" + entry.getValue()); // (2)
}
今回はCollectionUtilsというクラスを作成します。(1)のようにCollectionUtilsのenumurateメソッドに Iterableなオブジェクトを渡すと、インデックス番号と要素を管理するIterableなオブジェクトを返します。このIterableなオブジェ クトは、CollectionUtils.Entryオブジェクトを保持します。(2)ではentryからインデックス番号と要素の値を取り出して出力し ています。
それでは、ちょっと長いですが、このCollectonUtilsを実装したクラスが次のコードです。
import java.util.*;

public class CollectionUtil {
// (1) Entryクラス宣言
public static class Entry {
int index;
T value;
Entry(int index, T value) {
this.index = index;
this.value = value;
}

public int getIndex() { return index; }
public T getValue() { return value; }
}

// (2) enumurateメソッド
public static Iterable> enumurate(Iterable iterable) {
final Iterator iter = iterable.iterator(); // (3)
return new Iterable>() { // (4)
@Override
public Iterator> iterator() { // (5)
return new Iterator>() { // (6)
int index = 0; // (7)
@Override
public boolean hasNext() { //(8)
return iter.hasNext();
}

@Override
public void remove() { // (9)
iter.remove();
}

@Override
public Entry next() { // (10)
return new Entry(index++, iter.next());
}
};
}
};
}
(1)はEntryクラスの実装です。Entryクラスはインデックス番号(index)と値(value)を保持するバリューオブジェクトです。 (2)はIterableなオブジェクトを返すenumurateメソッドです。引数にはIterableなオブジェクトを受け取ります。上の例では Listオブジェクトを指定しましたが、イテレーション可能なオブジェクトであればすべて、インデックス番号付きのイテレータに変換できます。 (3)では、引数で受け取ったIterableなオブジェクトからイテレータを取得しています。(4)では、新たに新しいIterableなオブジェクト を返しています。ここでは、無名クラスとしてIterableなオブジェクトを宣言しています。
IterableインターフェースはIterator> iterator()を実装します(5)。このメソッドはIteratorを返すメソッドです。(6)でIteratorオブジェクトを無名クラスとして 宣言して返しています。この無名クラスは、内部データとしてインデックス番号を保持して(7)、enumurateメソッド内で宣言したiter変数 (Iteratorオブジェクト)を参照します。引数で渡されたイテレータと、新たに作成したイテレータの2つを同時に扱うので、少し複雑ですね。 Iteratorインターフェースは、hasNext, remove, nextの3つのメソッドを実装する必要があります((8),(9)(10))。(8)はhasNextを、(9)はremoveメソッドを実装していま す。それぞれ、(3)で設定したiter変数のhasNextとremoveメソッドを呼び出しているだけです。 (10)のnextメソッドでは、次のイテレータの要素として(1)で宣言したEntryをインデックスとオリジナルのイテレータの値 (iter.next())でインスタンス化して返しています。
これでインデックス番号と値を同時に管理できる汎用的なイテレータを利用できるようになりました。


例外処理

プログラムの実行中に異常事態が発生した場合に、Javaでは例外オブジェクトをメソッドの呼び出し元に送出します。例外オブジェクトはすべて、 Throwableクラスを継承したオブジェクトです。Throwableオブジェクトをthrow文で投げることによって、呼び出し元でエラー処理でき ます。
Throwable
+- Exception
+- RuntimeException
+- RuntimeException以外の例外クラス
+- Error
例外は実行時例外と検査例外の2つに分類されます。実行時例外は、RuntimeExceptionクラスとErrorクラス、また、それらの派生 クラスです。 Errorクラスとその派生クラスは、メモリ不足の時に発生するOutOfMemoryErrorなどJavaのVMが発生させるエラーです。深刻なエ ラーのため、通常はこのエラーはキャッチすべきではありません。 RuntimeExceptionは、配列で範囲外のインデックス値を指定した時に発生するIndexOutOfBoundsExceptionやメソッ ド呼び出しで変数がnull参照している時に発生するNullPointerExceptionなど、アプリケーションの通常の処理で発生する例外です。 この種の例外は通常はプログラム中で事前に値の検証を行って、例外を発生させないのが良いとされています。 これら2種類の実行時例外は、次に説明する検査例外と違いメソッドが送出する例外をメソッドシグネチャに含める必要はありません。
検査例外は次のようにメソッドシグネチャにthrowsに続けて呼び出し元に送出できる例外を指定します。呼び出し元では、try ... catch説で送出された例外を捕捉するか、さらにその呼び出し元に例外を送出する必要があります。
public void method() throws 例外1, 例外2 {
実行時例外と検査例外の使い分けとして、Effective Javaでは「 回復可能な条件にはチェック例外を、プログラミング・エラーにはランタイム例外を使う」と規定しています。しかし、最近は検査例外の弊害として
  • チェック例外が、実装の詳細を不用意にさらけ出している
  • 不安定なメソッド・シグニチャー
  • 読みとれないコード
  • 例外の飲み込み
  • 例外ラッピングが多すぎる
と批判して実行時例外を推奨しているフレームワークも存在します。例外についての議論はdeveloperWorksの「Javaの理論と実践: 例外をめぐる議論」( http://www.ibm.com/developerworks/jp/java/library/j-jtp05254/ )で詳しく議論されています。

try ... catch節

Javaの例外の補足はtry ... catch節を使います。catchブロックは次のように複数記述して、複数の例外を捕捉できます。finallyブロックは、例外が発生してもしなくても、常に実行されます。
少し長くなりますが、次のコードは例外補足のサンプルです。(2)のメソッドthrowExceptionでは、引数lineが文字 列"exception"の場合に、(1)で定義した例外MyExceptionを送出しています。(3)のmainメソッドの中で、ファイル in.txtを開いて((4))、(5)で一行ごとに読み込んでいます。この時、例外IOExceptionが発生する可能性があるため、(7)で補足し ています。また、このwhileループの中で(2)のthrowExceptionメソッドを呼び出しているので、例外MyExceptionが発生する 可能性があります。そのため、(8)で例外MyExceptionを補足しています。 (4)でReaderを開いているため、後片付けとして開いたreaderオブジェクトを閉じる必要があります。IOExceptionや MyExceptionが発生しても、開いたreaderオブジェクトはcloseする必要があるため、(9)のfinallyブロックでreaderオ ブジェクトのcloseメソッドを呼び出して、閉じます((10))。
import java.util.*;
import java.io.*;


public class MyTest {
// (1)
static class MyException extends Exception {}

// (2)
static void throwException(String line) throws MyException {
if (line.equals("exception")) {
throw new MyException();
}
}

// (3)
public static void main(String[] argv) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("in.txt")); // (4)
String line;
while ((line = reader.readLine()) != null ) { // (5)
System.out.println(line);
throwException(line); // (6)
}
} catch (IOException e) { // (7)
e.printStackTrace();
} catch (MyException e) { // (8)
e.printStackTrace();
} finally { // (9)
if (reader != null) {
try {
reader.close(); // (10)
} catch (IOException e) {
}
}
}
}
}
もう一度上のコードを見てくだだい。(7)と(8)の例外発生時のコードは、スタックトレースを出力するだけの全く同じコードです。実際のアプリ ケーションでも、複数の例外の対応で同じ処理をすることも多いです。Java8では、例外クラスを|でつなげることで、複数の例外をまとめて一つの catchブロックで捕捉できます。上のmainメエソッドの例外処理をJava8の記法で記述すると次のようになります(1)。
public static void main(String[] argv) {
BufferedReader reader = null;
try {
: 省略
}
} catch (IOException | MyException e) { // (1)
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
}
}
}
}

try-with-resources文

前節のBufferedReaderのように、後処理として必ず閉じる必要があるオブジェクトがあります。そのため、finallyブロックで常に オブジェクトのnullチェックを行って、closeメソッドを呼び出すことは煩雑で、しばしば閉じ忘れが発生します。Java7からはtry- with-resources文が導入され、閉じ忘れが発生しないようになりました。
前節のサンプルコードをtry-with-resources文を使って書き換えてみましょう。
public static void main(String[] argv) {
try (BufferedReader reader = new BufferedReader(new FileReader("in.txt"))){ // (1)
String line;
while ((line = reader.readLine()) != null ) {
System.out.println(line);
throwException(line);
}
} catch (IOException | MyException e) { // (2)
e.printStackTrace();
}
}
}
}
以前のコードではBufferedReaderの宣言がtry文の外にあり、変数のスコープが大きくなっていました。try-with- resources文を使うことで、BufferedReaderのスコープがtryブロックの中に限定され、コードがシンプルになります。 (1)はtry-with-resources文です。try-with-resources文では、tryのあとの()内で閉じる必要のあるオブジェク トを作成します。ここで作成したオブジェクトは、tryブロックを抜ける時に自動でcloseメソッドが呼ばれます。このため、前節のような finallyブロックが不要になります。 (2)では、catchブロックで通常のtryブロックの中で発生する例外を補足して処理できます。
上の例ではtry-with-resources文の中で、自動的に閉じられるオブジェクトはひとつだけです。次の例のように、複数個のオブジェクトを自動で閉じる場合は、「;」で連結して記述します((1))。
public static void main(String[] argv) {
// (1)
try (
BufferedReader reader = new BufferedReader(new FileReader("in.txt"));
BufferedWriter writer = new BufferedWriter(new FileWriter("out.txt"))
) {
String line;
while ((line = reader.readLine()) != null ) {
writer.write(line);
writer.newLine();
}
} catch (IOException e) {
e.printStackTrace();
}
}

AutoCloseableインタフェース

try-with-resources文のリソースとして使用できるクラスは、java.io.AutoCloseableインターフェースを実装 したクラスです。前節のBufferedReaderやBufferedWriterは、AutoCloseableインターフェースのサブインタフェー スのCloseableを実装しています。
AutoCloseable(または、Closeable)インタフェースは、次のcloseメソッドがひとつだけ定義されています。
  void close throws IOException
それでは、ストリームから一行ごとに読み込んで、各行を「,」で分割した文字列の配列を管理するCsvReaderクラスを作ってみましょう。 (1)は、CsvReaderのコンストラクタです。コンストラクタの中でBufferedReaderオブジェクトを作成しています。(2)の readLineメソッでは一行読み込んで、「,」で分割しています。(3)は、AutoCloseableのcloseメソッドの実装です。このメソッ ドでは、(1)で作成したBufferedReaderオブジェクトのcloseメソッドを読み込んでいます。
public class CsvReader implements AutoCloseable {
private BufferedReader reader;
public CsvReader(Reader reader) { // (1)
this.reader = new BufferedReader(reader);
}
public String[] readLine() { // (2)
String line = reader.readLine();
return line.split(",");
}

@Override
public void close() throws IOException { // (3)
System.out.println("closing...");
reader.close();
}
}
次のコードは、このクラスを実際に使用しています。AutoCloseableインタフェースを実装しているので、tryブロックを抜けるときに自動的にCsvReaderのcloseが呼ばれます。
try (CsvReader csv = new CsvReader(new FileReader("test.csv"))) {
String[] fields;
while ((fields = csv.readLine()) != null) {
System.out.println(fields);
}
}

クラス定義

初期のJavaではクラスの定義は、一つのソースファイルに一つのクラスしか作成できませんでした。現在でもpublicなトップレベルクラスにはその制約はありますが、内部クラスやプライベートなクラスは、一つのソースファイルに複数記述できます。

パッケージスコープのトップレベルクラス

次の例のように、一つのソースコードPublicClass.javaファイルに、publicなクラスPublicClassとパッケージスコー プのクラスPrivateClassの2つのクラスを定義できます。パッケージスコープのクラスは、この複数定義できます。このファイルをコンパイルする と、PrivateClass.classとPublicClass.classの2つのクラスファイルが生成されます。つまり、 PublicClass.javaと一緒にPrivateClass.javaファイルで別途PrivateClassクラスを定義できません。
```java:プライベートなトップレベルクラス(PublicClass.java) class PrivateClass { // (1) }
public class PublicClass { // (2) } ```

ネストしたクラス

クラスの中にさらにクラスを定義できます。クラスの中のクラスを、ネストしたクラスと呼びます。次のコードはネストしたクラスを定義しています。 (1)はトップレベルのクラスOuterで、(2)のInnerクラスがネストしたクラスになります。ネストしたクラスは、ここではpublicスコープ ですが、スコープの範囲に応じて、privateスコープやパッケージスコープやprotectedスコープで定義できます。ネストしたクラスではクラス にstaticをつけます。staticをつける理由は、次の内部クラスで説明します。 このクラスをコンパイルすると、Outer.classとOuter$Inner.classの2つが生成されます。
public class Outer { // (1)
public static class Inner { // (2)
}
}

内部クラス

内部クラスは、ネストしたクラスと同様に、クラスの中にクラスを定義できます。しかし、ネストしたクラスと違い、内部クラスは外部クラスのインスタ ンスに紐付いています。ネストしたクラスを利用する場合は、new Outer.Inner()としてインスタンス化できますが、内部クラスでは外部クラスをインスタンス化して、そのインスタンスから内部クラスをインスタ ンス化します。
次のコードは内部クラスの例です。(2)で内部クラスを定義しています。内部クラスはネストしたクラスと違い、staticは付けないこと注意して ください。(3)は、内部クラスInnerのオブジェクトから、外部クラスのオブジェクトのフィールドにアクセスしています。これはネストしたクラスと違 い、外部クラスのオブジェクトに紐付けられているために可能になります。ここでは直接変数を指定していますが、外部クラスの変数を明示するために Outer.this.strと指定することもできます。 (4)では、外部クラスのメソッドから内部クラスをインスタンス化しています。 このファイルをコンパイルするとOuter.classとOuter$Inner.classの2つのファイルが生成されます。
public class Outer {
private String str = "outer value"; // (1)
public class Inner { // (2)
public void print() { // (3)
System.out.println(str);
}
}
public void method() {
Inner inner = new Inner(); // (4)
}
}

ローカルクラス

クラスの中にクラスを定義できたように、メソッドの中にもクラスを定義できます。メソッドの中に定義したクラスは、クラスを定義したスコープに依存 します。 次のコードは、メソッドの中にローカルクラスを定義しています。(1)と(4)は実際にローカルクラスLocalClassを定義しています。同じ名前の クラスですが、それぞれ別のクラスとして認識されます。このファイルコンパイルすると、Outer.classと Outer$1LocalClass.classとOuter$2LocalClass.classの3つができていることからも、それらは別のクラスだ とわかります。(2)と(6)では、それぞれ(1)と(3)で定義したクラスをインスタンス化しています。 ローカルクラスからは、メソッド内で定義した変数にアクセスできます。アクセスできるのはfinal定義された変数だけです。そのため、メソッド内の変数 の値を変更することはできません。(5)のLocalClassのprintメソッドでは、メソッドのfinalで定義されたstr変数にアクセスしてい ます。final指定されていない変数にアクセスしようとすると、コンパイルエラーが発生します。
public class Outer {
public void method1() {
class LocalClass {}; // (1)
LocalClass lc = new LocalClass() // (2)
}
public void method2() {
final String str = "method2"; // (3)
class LocalClass { // (4)
public void print() { // (5)
System.out.println(str);
}
}
LocalClass lc = new LocalClass(); // (6)
lc.print();
}
}

無名クラス

無名クラスは匿名クラスとも呼ばれています。無名クラスは、インターフェースや抽象クラスを利用するときに、名前やクラス定義をせずに直接インスタ ンス化して、その実装を書くものです。メソッド内や、クラスフィールドのインスタンス化時に利用します。名前付きのクラスと違い、クラスのインスタンス化 を一箇所からしか行わない場合に無名クラスを利用することが多いです。 無名クラスもローカルクラスと同様にfinalで定義された外部の変数にアクセスできます。
次のコードは、java.lang.Runnableを無名クラスでインスタンス化したものです。(1)でRunnableインタフェースをインス タンス化しています。new Runnable()に続いて{}のブロック内で、Runnableインタフェースが持つrunメソッドを実装しています(3)。無名クラスはコンストラ クタを持てませんが、フィールドに初期値を設定できます(2)。また、ローカルクラスと同様に、finalで定義された変数にはアクセスできます。 (4)の(1)から始まった{}ブロックの最後に「;」を忘れないでください。
Runnable runnable = new Runnable() { // (1)
String str = "running"; // (2)
@Override
public void run() { // (3)
System.out.println(str);
}
}; // (4)
new Thread(runnable).start();

可変長引数

可変長引数は、引数の数を複数指定でき、実際の引数の数はその呼び出し元によってきまります。

基本的な利用例

java.lang.Stringクラスのformatメソッドではpublic String format(String fmt, Object... args)のように定義されています。可変長引数は、引数の型宣言のあとに「...」を追加します。可変長引数を指定できるのは、一番最後の引数だけで す。 Stringクラスのformatメソッドは次のように利用します。
str = String.format("out: nothing"); // (1) "out: nothing"と出力
str = String.format("out: %d", 1); // (2) "out: 1"と出力
str = String.format("out: %d %s", 1, "foo"); // (3) "out: 1 foo"と出力
(1)はフォーマット用の文字列だけとり、可変長引数を取らないケースです。(2)は可変長引数に「1」を指定しています。(3)は可変長引数とし て「1」と「foo」の2つを指定しています。引数の数に関わらず、呼び出されるformatメソッドはひとつだけで、オーバロードされていません。

メソッドから使用例

可変長引数はメソッド内では配列として扱います。次のコードは可変長引数を出力するメソッドです。 (1)でargvを可変長引数としてとります。(2)で可変長引数を直接出力しています。[Ljava.lang.String;@15db9742のよ うに出力されます。これはargvがStringの配列を意味しています。(3)は可変長引数を拡張forループで回して、内容を出力しています。
public void print(String... argv) { // (1)
System.out.println(argv); // (2)
for (String s: argv) { // (3)
System.out.println(s);
}
}
上のメソッドは、メソッドシグネチャがpublic void print(String[] argv)とほぼ、同義です。しかし、配列で指定した場合は、argvがnullのケースがありますが、可変長引数では、必ず非null値になります。つ まり、引数に何も指定されない場合は、空の配列になります。

配列として呼び出し例

このメソッドを利用するときは、通常はprint("foo", "bar", "buzz");のように利用します。 さて、可変長引数はメソッド内で配列として扱われます。実はメソッドの呼び出し元からも配列として扱うこともできます。次の例は、可変長引数に配列として 値を指定しています。これは、print("foo", "bar", "buzz");と同義です。
String[] argv = new String[]{"foo", "bar", "buzz"};
print(argv);
ただし、配列として値を渡す場合、print((String[])null);のように配列として明示的にnullを渡すと、printメソッド の可変長引数argv自体もnullになるので気をつけてください。print(null)の場合は、可変長引数(配列)の最初の値がnullになり、配 列自体は実体があります。





Latest Images