今更ながらラムダで遊んでみる

超久しぶりの更新です。
久しぶり過ぎて何を書いていたかも忘れそうですが・・・。


Java8がいよいよリリースされました。
最近全然JavaについてWatchしていなかったので、
いろんな意味で隔壁の感があります。
Java8の機能を色々と触って行きたいと思います。


まずは、メインのラムダから。
といっても文法系は他のブログでいっぱい書かれているでしょうから、
ここではあまり触れませんw。


例えば、乱数を発生させてそれを出力させるサンプル。

List<Integer> list = new ArrayList<>();
Random rmd = new Random();
for (int i=0; i < 10_000_000;i++){
    list.add(rmd.nextInt(1_000_000));
}

list.forEach(in -> System.out.println(String.valueOf(in)));

in -> System.out〜の部分がラムダ表記を使っているところですね。


これだけだと寂しいので、sortしてみましょうか。
sortはColelctions.sortを使っても出来るのですが、
あえてStreamを使用してみます。

List<Integer> list = new ArrayList<>();
Random rmd = new Random();
for (int i=0; i < 10_000_000;i++){
    list.add(rmd.nextInt(1_000_000));
}
// Streamを使う
List<Integer> list2 = list.stream().sorted().collect(Collectors.toList());

list2.forEach(in -> System.out.println(String.valueOf(in)));


並列実行させたい場合にはstreamをparallelStreamにすれば並列実行します。

List<Integer> list = new ArrayList<>();
Random rmd = new Random();
for (int i=0; i < 10_000_000;i++){
    list.add(rmd.nextInt(1_000_000));
}
// Streamを使う
List<Integer> list2 = list.parallelStream().sorted().collect(Collectors.toList());

list2.forEach(in -> System.out.println(String.valueOf(in)));


因みにparallelStreamでSystem.out部分をコメントアウトした場合の実行時間は3回の平均で、7.672秒でした。
streamで実行した場合3回の平均が14.474秒だったので早くなっているのがわかります。
また、単純にCollections.sortを使用すると10.770秒だったので、
やはりstreamにする分オーバーヘッドがあるということでしょうか。


今回はsortという単純なもののでやっているので、
こうなっていますが、mapとかreduceとか使い出すとまた別の結果が出るでしょうね。
(というかstreamにすることのメリットはその辺が使えるからというのが大きいように思えます)


ということで、今回はこれまで。

Mercurialでコミット時に気をつけるちょっとしたこと


Mercurialでコミットしてたら、ときどき次のように怒られた。

abort: edit failed: vi exited with status 1


これは、コミット時にコミットメッセージを指定しないと、
コミットメッセージを編集しようとしてVimを立ち上げようとするらしく、
WindowsVimなんて入っていないから上記エラーが出ているらしい。

立ち上がるeditorをVimから変えればいいんだけど、
コミットメッセージを指定してコミットするようにしたほうが確実。
ということで、コミットメッセージをつけてコミットしよう。

> hg commit -m "コミットメッセージ"

MercurialをWindowsにレジストリを汚さない形でいれてみた


思い立ってローカルで分散バージョン管理を導入するために、Mercurialを入れてみた。
なぜGitじゃなくてMercurialかというと、
オフラインでも使えるようにしたかったのと、あわよくばbitbucketまで組み入れてみたかったため。
Windowsの場合はインストーラーを使えば簡単にインストールできるんですが、
あまりレジストリを汚したくなかったのでzipみたいにできないかと思っていました。
ということで、次のようにした。

  1. Bitbucket | The Git solution for professional teamsからmsiモジュールをダウンロードする。
  2. msiを解凍する方法を色々調べたが、結局Universal Extractor | LegRoom.netからuniextracorをダウンロードして使用することにした。
  3. 解凍したフォルダからTortoiseHgフォルダだけ抜き出す。
  4. TortoiseHgフォルダ直下にパスを通しておく。
  5. 同じくTortoiseHgフォルダ直下にMercurial.iniファイルを作成して中を次のように記載する。
[ui]
username = XXXXXXX

[extensions]
hgext.win32mbcs =

Windowsで日本語ファイル名を扱いたい場合はextensionsを記入しておく必要あり。


これで暫定的でも使えるようになります。


【リモートと連携しない超簡単な使い方】
フォルダをMercurialに登録する。

> hg init


ファイルを全部addする。

> hg sff


コミット

> hg commit


ログを見る

> hg log

ロールバック

> hg rollback


指定のリビジョンのファイルの取得

> hg cat -r [リビジョン名] -o [出力名] [指定ファイル]

今更ながらubuntu11.10にrvmを入れたので忘れないようにメモ


まあ、大したことやっていないのですが・・・。

まずはcurlが入っていなかったのでインストール。ついでにgit-coreもインストール。

$ sudo apt-get install curl git-core

次にrvmをインストール。次のコマンドを叩いたらインストールできた。

$ bash < <(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer)

次にrvmにruby 1.9.3をインストール。

$ rvm install 1.9.3

コンパイルに時間がかかるけど問題なくできた。
で、使おうとした使えねえよと怒られた。

$ rvm use 1.9.3
RVM is not a function, selecting rubies with ‘rvm use …’ will not work

ちょっとぐぐってみると.bashrcにsourceの設定がいるみたい。
PATHが自動的に追加されていたので問題ないかと思ったけど、追加しないとダメみたい。

ということで、.bashrcの一番下に追加。

source "$HOME/.rvm/scripts/rvm"

そうすると使えるようになりました。

$ rvm use 1.9.3
Using /home/XXX/.rvm/gems/ruby-1.9.3-p194

IE9のDOMイベントについて調べてみた


タイトルはかなり釣りです(ぇ


IEが忌み嫌われる原因の1つにIE独自仕様があります。
DOMイベントはその中の1つです。
W3Cで標準のDOMイベントについて規定されていますが、
IEでは別の命名で実装されているので、
IEのときだけ別のイベントを呼びだす必要があります。
(例えばイベントを起動するcreateEventはIEではcreateEventObjectになっている。)


例えばこんな感じです。

if (/*@cc_on!@*/false) { // IEかどうか判定
  var event = document.createEventObject();

  ・・・・

}else{
  var event = document.createEvent("HTMLEvents"); 

  ・・・

}


それがIE9からDOM level3に準拠するようになったので、
createEventが使えるようになり、createEventObjectが非推奨になりました。


Legacy DOM events are no longer supported (Windows) | Microsoft Docs


そのため、IE9の場合はcreateEventObjectではなく、createEventを実行しなければなりません。
ただし、上のようにIEで判定していると、createEventObjectのほうにいってしまうので、
IE9かどうかで更に判定を加える必要があります。


IE9かどうかの判定は次のブログを参考にしました。


JavaScript とかによるブラウザ判定方法のまとめ - A Memorandum

var appversion = window.navigator.appVersion.toLowerCase();
if ((/*@cc_on!@*/false) && appVersion.indexOf("msie 9.") == -1) { // IE8以前かどうかチェック
  var event = document.createEventObject();

  ・・・・

}else{
  var event = document.createEvent("HTMLEvents"); 

  ・・・

}


また、ブラウザのバージョンを見なくても、
createEventが実行可能かどうかで判定したほうがスマートです。

if (document.createEvent) { // I以前かどうかチェック
  var event = document.createEvent("HTMLEvents"); 

  ・・・

}else{
  var event = document.createEventObject();

  ・・・・

}


個人的に使っているライブラリがIE9だとエラーが発生したので、
その原因を色々と調べてみたところ、
上の原因でエラーが出ていたのでちょっとまとめてみました。

今更ながら2012年向けまして


さて、2012年に入りました。
2011年は色々とやってはきましたが、
もうちょっと色々やりたかったなと思う年でした。
今年も初っ端から大変そうなプロジェクトに入りましたが、
環境も違えば仕事の内容も今までと違うので
どのような感じになるか今から非常に楽しみだったりします。
心機一転頑張っていければなと思います。


今年は新規プロジェクトを頑張っていきたいと思っていますが、
それ以外にやりたいことがありまして・・・

  1. テスト自動化、およびデプロイ自動化の体系づけをして周りにはやらしたい。
  2. JavaOne Tokyoに絶対に行く。
  3. GroovyかScalaのどちらかを覚える。

ひとまず、上記のことを目標として頑張っていきたいと思っております。
本年もよろしくお願いいたします。

アプリケーションから発行されているSQLを取得したい


ちょっと訳ありで上記のようなことをおこないたいケースが出てきました。
大概はソースいじるなりなんなりすればいいのですが、
諸事情により残念ながらそのような選択肢がとれなかったので、
jarを入れ替えるなり、設定を追加するなりでできないかと調べていました。


やり方としてはJDBCのpreparedStatementにラッパーをかければよくて、
そのやり方ができるライブラリも幾つか転がっていたのですが、
使っているアプリケーションがDataSourceを使っており、
そこまで対応しているものが中々なくて色々と探し回っていました。


で、見つけたのが次。


http://code.google.com/p/jdbcdslog

インストール


jarなんで普通にlibフォルダにいれればOKです。
ただし、slf4jを使用しているので一緒にいれる必要があります。

設定方法


使うためにはJDBCドライバのクラスと接続するURLを変更する必要があります。


まずはJDBCドライバのクラスを変更します。
Oracleの場合は、oracle.jdbc.driver.OracleDriverになっているので、
それをorg.jdbcdslog.DriverLoggingProxyに変更します。

Class.forName("oracle.jdbc.driver.OracleDriver")
 ↓ 
Class.forName("org.jdbcdslog.DriverLoggingProxy")


もう一つ、接続先を次のように変更します。

jdbc:oracle:thin:@XXX.XXX.XXX.XXX:1521:XX
 ↓
jdbc:jdbcdslog:oracle:thin:@XXX.XXX.XXX.XXX:1521:XX;targetDriver=oracle.jdbc.driver.OracleDriver

ログの出力


ログは次の3種類でます。

  • DBに接続したログ
56 [main] INFO org.jdbcdslog.ConnectionLogger - connect to URL jdbc:hsqldb:. with properties: {user=sa} 
  • SQLを実行したログ
62627 [http-8080-1] INFO org.jdbcdslog.StatementLogger - java.sql.PreparedStatement.executeQuery select id, email from user where username = ? parameters: {'admin'} 12ms. 
  • SQLの結果のログ
62118 [http-8080-2] INFO org.jdbcdslog.ResultSetLogger - java.sql.ResultSet.next {1234, 'root@a.com'} 


SQLだけ取得したい場合はorg.jdbcdslog.StatementLoggerだけを取得するように出力すればOKですね。

DataSourceを使うときには


DataSourceを使うときには次のように設定します。


DataSourceでのドライバクラスは次のように設定します。

oracle.jdbc.xa.client.OracleXADataSource
 ↓
org.jdbcdslog.ConnectionPoolXADataSourceProxy


もう一つ接続先は次のようにします。

jdbc:oracle:thin:@XXX.XXX.XXX.XXX:1521:XX
 ↓
jdbc:oracle:thin:@XXX.XXX.XXX.XXX:1521:XX;targetDS=oracle.jdbc.xa.client.OracleXADataSource


これでログを仕込むことができます。


通常、永続化ライブラリを使用している場合は、
そのライブラリ内でSQLを出力する機構を持っていると思うので、
これが必要になる機会があるかという話がありますが、一応記しておきます。