2011年12月31日土曜日

[Intellij]InttelijでjQueryを使ってみよう

IntelliJ IDEA Ultimate EditionではjQueryをサポートしているので、関数補完などを使いながら開発を行うことができます。
IDEでごりごり書いた方が、生産性あがるはずなので、IntellijでのjQueryライブラリの使い方を調べてみたと。

jQueryのライブラリを自分でダウンロードする場合

1.jQueryのサイトからjQueryのライブラリをダウンロードして任意のディレクトリに保存する。

2.Project Structure画面を開く

3.左側のメニューからGlobal Librariesを選択する。

4.「+ボタン」→「JavaScript」の順に選択する。(下の画像のように選択していく)

5.1で保存したjQueryのライブラリ(jquery-<バージョン番号>.js)を選択する。

6.左側のメニューからModulesを選択する。

7.jQueryを使用するModuleを選択して、依存ライブラリに5で追加したjQueryのライブラリを登録する。
登録すると下の画像のようにjQueryのライブラリが依存ライブラリにでてきます。
※Dependenciesタブを選択し、左下の「+ボタン」→「Library...」から5で登録したライブラリを選択出来ます。

Intellijの機能でダウンロードする場合

Inttelijには、JavaScriptのライブラリをダウンロードしてくれる機能があるので、
この機能を使うと依存ライブラリの設定まで簡単に行うことが出来ます。

1.Settings画面を開く

2.左側のメニューからJavaScriptLibrariesを選択する。(Project Settingsにあります)

3.Download from...のリンクをクリックしDownload LibraryのWindowでjQueryを選択してダウンロードする。(ちょっと古いバージョンみたいです。)
これで、依存ライブラリとしてjQueryのライブラリが設定されます。簡単ですね。

動作を確認してみよう

補完がちゃんと有効になってるみたい。使いやすいかわからないけど、とりあえずjQueryの勉強しつつ使ってみよう。

2011年12月13日火曜日

[Oracle]テキストリレラルの使用方法

Oracleでシングルクォート(')を文字列中で使う場合、シングルクォートでエスケープ必須だと思ってましたが、
代替引用メカニズムなるものを使用してrubyっぽくエスケープをせずにリテラルが定義できるみたいです。

マニュアルはこちら
http://docs.oracle.com/cd/E16338_01/server.112/b56299/sql_elements003.htm#i42617

従来までのリテラルの使い方
SQL> select 'hoge''s' from dual;

'HOGE''S'
------------
hoge's

大替引用メカニズムなるものを使用するとかんな感じになります。
q(Q)'任意の文字(開始)<文字列>任意の文字(開始文字に対応した終了文字)'

SQL> select Q'{hoge's}' from dual;

Q'{HOGE'S}'
------------
hoge's

任意の文字の部分には、何でも使用できるのでこんな感じでもいけちゃいます。ものすごくわかりづらいですが。
SQL> select Q'ahoge'sa' from dual;

Q'AHOGE'SA'
------------
hoge's

2011年12月9日金曜日

[Intellij]コード補完を使いこなそう

Intellijには、3種類の補完方法が存在します。
Eclipseだと、補完といったらCtrl + Spaceだけ使っていたらいいと思うけど、Intellijだとこの3種類をうまく使いこなせないと、ちょっと残念な感じになってしまう。

ちなみに、3種類の補完は下の画像のように「Code」→「Completion」から使うことが出来ます。(マウス操作で使うことはまずないと思うけど)

それぞれの補完機能の説明

Basic補完

基本的な補完機能。EclipseのCtrl + Spaceで出来る補完機能と同じ感じの補完となる。(Eclipseとは少し違うかもしれませんが、勝手な想像で書いています)
そのスコープ内で使用可能な変数などをもとに補完候補を表示するので、変数やパラメータとして使用出来ないデータ型のものも候補として表示される。

使いどころとしては、変数やパラメータの補完よりかはメソッドの修飾子やthrows節の例外のようにそこで使用する修飾子やクラスや変数が自明な場合に使用します。(と勝手に思っています。)
こんな感じに補完候補が表示されます。

例えばメソッドの引数でBasic補完を使うと、データ型が一致していて代入可能なものがあればその変数を候補として上位に表示してくれます。
下の画像のように、mのパラメータがStringなのでString型の変数が上位に表示されます。

使い方を間違えるとこんな感じに意味のないものが列挙されちゃったりもします。これは間違った使い方だと勝手に思ってますが。

ほかにもpropertyファイルのキー値をこんな感じで補完してくれたりします。ほかにも色々やってくれると思います。(たぶん)


SmartType補完

SmartType補完は、そこで利用可能なもののみにフィルタをかけて候補を表示してくれます。Basic補完のように使用可能な変数やクラスを候補として列挙することはなく、使用可能なものがなければ、ないよと教えてくれます。
この補完にであって、IDEってすげーって思った記憶があります。

使い方としては、変数宣言時の右辺やreturn文などで使います。俺は、補完よりもリファクタリング機能のIntroduce Variable使っちゃうことが多いけど、なれてきたら補完とリファクタリングをうまく使い分けれるようなると思います。

SmartType補完が有効に使える場所
  • 変数宣言時の初期化
  • 初期化で必要なコンストラクタ呼び出しや、メソッド呼び出しなど
  • 変数呼び出しのパラメータ
  • return文
Basic補完との違いは、下の画像を見るとわかると思います。

ClassName補完

補完候補としてクラス名を列挙してくれる機能です。
主に変数宣言時に使いますが、この補完機能を文字列内で使うと選択したクラスの完全修飾名を挿入してくれます。

例えば・・・
java.util.ArrayListを補完候補から選択した場合、文字列には"java.util.ArrayList"が挿入されます。

また、Class Name補完はクラスパス配下にあるファイルも候補として表示してくれます。
なので、クラスパス配下にあるpropertiesやxmlなどのパスを入力する時に、この補完をつかうと入力の手間を減らすことが出来ます。

イメージ的には、こんな感じに補完されます。

補完の俺設定

こだわりがあるのは、Case sensitive completionはFirst letterにしるのと、
ドキュメントとパラメータのポップアップを切ってる部分かな。

2011年11月27日日曜日

[oracle]DBの値をバイナリでダンプする方法

DUMP関数を使用して、
任意の値をバイナリでダンプすることができる。

構文

dump(任意の値(列名), フォーマット, スタートポジション, 長さ)
  • 任意の値(列名)
  • 文字列をリテラルで指定するか、カラム名を指定する。
  • フォーマット(任意)
  • 以下の値を指定する。
    8→8進数でダンプ
    10→10進数でダンプ
    16→16進数でダンプ
    上記の値に1000をプラスすると、ダンプ時にキャラクタセットを表示してくれる。
  • スタートポジション(任意)
  • ダンプの開始位置
  • 長さ(任意)
  • ダンプする長さ

使用例


普通にSQLを実行した場合
SQL> select col1 from test;

COL1
----------
12345

16進数でダンプした場合
SQL> select dump(col1, 16) from test;

DUMP(COL1,16)
--------------------------------------------------------------------------------
Typ=1 Len=5: 31,32,33,34,35

キャラクタセットを表示しつつダンプした場合

SQL> select dump(col1, 1016) from test;

DUMP(COL1,1016)
--------------------------------------------------------------------------------
Typ=1 Len=5 CharacterSet=AL32UTF8: 31,32,33,34,35

macでIntellijのpluginプロジェクトを実行出来なかった場合の対処

macでIntellijのpluginプロジェクトからpluginの実行したら、実行時エラーがでて実行できない・・・
本来であれば、新たにIntellijが起動してそこでpluginの挙動を確認出来るのに。

原因なんだろと思って調べてたら、実行時のvmoptionがとんでもないことに。
下の画像のように、なんかxmlになってるし。

なにが正しいかよくわかんなかったので、Windowsで起動したときのvm option(以下のオプション)をもってきたら、うまいこと起動した。
-Xms128m -Xmx800m -XX:MaxPermSize=350m -XX:ReservedCodeCacheSize=64m -XX:+UseCompressedOops

Intelijのバグチケットに同じ事象のがあがってて、中の人のコメントによるとworkspase.xml($PROJECT_HOME$/.idea配下にある)を削除してからプロジェクト起動するとよいらしい。
http://youtrack.jetbrains.net/issue/IDEA-76854?projectKey=IDEA&query=plugin+run

2011年11月13日日曜日

[Scala]値の遅延評価

val定義にlazy修飾子をつけることによって、右辺の初期化処理の実行を遅延させることが出来る。

lazyなvalは、初めてその変数にアクセスが行われたときに初期化(右辺の初期化式の実行)が行われる。
2度目にアクセスした時には、既に初期化されているので初期化は行われない。

サンプルコード

object Hoge {
  val hoge = {
    println("init hoge")
    "hoge"
  }
  
  lazy val lazyHoge = {
    println("init lazyHoge")
    "lazyHoge"
  }

  def main(args: Array[String]) {
    println(Hoge)
    println("========== hoge ==========")
    println(Hoge.hoge)
    println("========== lazy hoge ==========")
    println(Hoge.lazyHoge)
    println("========== lazy hoge2 ==========")
    println(Hoge.lazyHoge)
  }
}

実行結果

以下の点を確認出来る。
  • 通常のvalは、クラス参照時に初期化されていることがわかる
  • lazyなvalは、その変数に初回にアクセスしたときに初期化されていることがわかる
init hoge
Hoge
========== hoge ==========
hoge
========== lazy hoge ==========
init lazyHoge
lazyHoge
========== lazy hoge2 ==========
lazyHoge

2011年11月6日日曜日

Excel列名変換

また、こちらのブログを見てチャレンジ。

http://d.hatena.ne.jp/JunichiIto/20111102/1320253815


Scalaで書いてみたけど、Scalaっぽいのかわからない。

object Main {

  val cols = Range('A'.toInt, 'Z'.toInt + 1, 1).map {
    n => n.toChar
  }

  val stringPattern = "[A-Z]+".r

  def toNumber(alpha: String, num: Int): Int = {
    if (alpha.isEmpty) {
      num
    } else {
      toNumber(alpha.drop(1), num * 26 + (cols.indexOf(alpha.head) + 1))
    }
  }

  def toAlpha(num: Int, alpha: String): String = {
    if (num <= 0) {
      alpha
    } else {
      (num % 26) match {
        case 0 => cols(25) + alpha
        case n: Int => toAlpha(num / 26, cols(n - 1) + alpha)
      }
    }
  }

  def main(args: Array[String]) {
    args(0) match {
      case stringPattern() =>
        println(toNumber(args(0), 0))
      case _ =>
        println(toAlpha(args(0).toInt, ""))
    }
  }
}

2011年11月5日土曜日

Oracle NoSQLをCentOSインストール


NoSQL Databaseのダウンロード

Oracleのサイト(下記リンク)から、NoSQL Databaseのアーカイブをダウンロードする。
http://www.oracle.com/technetwork/database/nosqldb/downloads/index.html

ダウンロードしたファイルは、任意のディレクトリに解凍してあげる。

インストールされたことを確認

以下のように、kvclient-1.1.100.jarを実行して標準出力に「11gR2.1.1.100」が出力されればOK
$ KVHOME=/opt/kv-1.1.100 
$ export KVHOME 
$ java -jar $KVHOME/lib/kvclient-1.1.100.jar 
11gR2.1.1.100

データベースの作成

testディレクトリを作成し、そこをルートとしてデータベースを作成。
-portには、データベースにアクセスするためのポートを指定。(Oracle Databaseの1521みたいなものかな?)
-adminには、管理者用のポートを設定。このポートにアクセスすれば、GUIベースの管理ができる。
-hrangeには、ノード自身が通信で使うポートの開始位置と終了位置を指定するらしい。(あんまりよく分かっていない。。)
$ mkdir test
$ $KVHOME/bin/kvctl makebootconfig -root test -port 5000 -admin 5001 -harange 5010,5020

データベースの起動

下記コマンドで起動する。
-rootには、データベースのルートディレクトリを設定する。
$ $KVHOME/bin/kvctl start -root test

起動されたことは、tnsping的な下記コマンドで確認する。
$ $KVHOME/bin/kvctl ping -port 5000

成功していると、こんなメッセージが出力されるみたい。
SNA at hostname: localhost.localdomain, registry port: 5000 is not registered.
        No further information is available

ためしに管理者用ポートにブラウザからアクセスしたらこんな画面が表示されました。

データベースの停止

$KVHOME/bin/kvctl stop -root test

2011年10月30日日曜日

[mysql]indexが使われていないSQLを調べる方法

log_queries_not_using_indexesというオプションを有効にすることによって、indexが使われていないSQLを抽出することができる。

log_queries_not_using_indexesオプションの値の確認・設定方法


global variablesの値が「on」になっていれば、indexが使われていないSQLが抽出できます。
mysql> show  global variables like '%indexes';
+-------------------------------+-------+
| Variable_name                 | Value |
+-------------------------------+-------+
| log_queries_not_using_indexes | ON    |
+-------------------------------+-------+
1 row in set (0.00 sec)

もし、offになっている場合には以下のコマンドで有効に変更できます。
mysql> set global log_queries_not_using_indexes = on;

抽出されたSQLの出力先

log_queries_not_using_indexesのログは、slow queryログに出力されるのでslow queryの設定で確認できます。

slow_query_logが、slow queryログを出力するかどうかの設定。onになっていれば、ログが出力されます。
slow_query_log_fileが、ログの出力先となります。
mysql> show global variables like '%slow%';
+---------------------+------------------+
| Variable_name       | Value            |
+---------------------+------------------+
| log_slow_queries    | ON               |
| slow_launch_time    | 2                |
| slow_query_log      | ON               | 
| slow_query_log_file | c:\work\slow.log |
+---------------------+------------------+
4 rows in set (0.00 sec)

slow queryの設定は、以下のように「set global」コマンドで変更できます。
mysql> set global slow_query_log = on;
Query OK, 0 rows affected (0.00 sec)

mysql> set global slow_query_log_file = 'c:\\slow.log';
Query OK, 0 rows affected (0.00 sec)

動作を確認してみよう


テスト用に主キーのみのテーブルを作成
mysql> create table test_table (col1 char(1), primary key (col1));
Query OK, 0 rows affected (0.02 sec)

以下の2種類のSQLを実行。前者のSQLは、主キー検索のためindexが使用される。
後者のSQLは、関数を使用しているのでindexは使用されずに検索が行われる。
mysql> select * from test_table where col1 = '1';
Empty set (0.00 sec)

mysql> select * from test_table where substr(col1, 1, 1) = '1';
Empty set (0.00 sec)

slow queryログには、以下のようにindexが使用されなかったSQLの情報が取得できる。
# Time: 111030 16:00:38
# User@Host: root[root] @ localhost [::1]
# Query_time: 0.000500  Lock_time: 0.000000 Rows_sent: 0  Rows_examined: 0
use test_db;
SET timestamp=1319958038;
select * from test_table where substr(col1, 1, 1) = '1';

これを使えばindexの張り忘れや、SQLのつくりが原因でindex使われていないSQLを機械的に抽出できるかなと。

2011年10月25日火曜日

WEB+DB PRESS 総集編

WEB+DB PRESS 総集編が届いたので、がっつりiPadに取り込んでみた。



iBooksで見るとかんな感じ。

iPadだとやや重いかなって感じです。普通に読むぶんにはまぁそこまで気にならないかなと。






2011年10月11日火曜日

FizzBuzz

http://d.hatena.ne.jp/JunichiIto/20111007/1317976730を見て俺もかけなかったらどうしようと不安になりつつScalaで書いてみた。
とりあえず、ちゃんと動くものかけて一安心と。

(1 to args(0).toInt).foreach {
  n =>
    (n % 3, n % 5) match {
      case (0, 0) => println("Fizz Buzz")
      case (0, _) => println("Fizz")
      case (_, 0) => println("Buzz")
      case _ => println(n)
    }
}

Excelの関数でもしてみた。。。現在の行番号を元に結果が出てくるようにしてます。
=IF(MOD(ROW(),15)=0,"Fizz Buzz",IF(MOD(ROW(),3)=0,"Fizz",IF(MOD(ROW(),5)=0,"Buzz",ROW())))

2011年9月29日木曜日

Vimテクニカルバイブルを買ったよ。

Vimユーザなので購入。


emacs版もあるらしい。emacs使えないから買うことはないけど。

2011年9月25日日曜日

[Scala]アクセッサの定義

scalaではとあるルールによってアクスメソッド(getterやsetter)が自動的に定義されるので、
Javaみたく明示的にアクセスメソッドを定義する必要はないようです。素敵ですね。


パターン1:publicなvarフィールドを定義した場合

このように、publicなvarフィールドを定義するとコンパイル時に自動的にアクセスメソッドを出力してくれます。
class Hoge {

  var hoge1: String = _

  var hoge2: Int = _
}
自動で生成されたアクセスメソッドを呼び出すには、フィールドに直接アクセスするようにしてあげればよいです。
val hoge = new Hoge
hoge.hoge1 = "hoge"     // hoge1に値を設定
hoge.hoge2 = 1             // hoge2に値を設定

println(hoge.hoge1)        // hoge1の値を取得
println(hoge.hoge2)        // hoge2の値を取得

コンパイル後に出力されたクラスファイルをjadって見てみると、こんなルールになっているのがわかる。
  • varなフィールドはprivateになっている。
  • setterは、プロパティ名 + "_="になっている。
    =は、コンパイル時にJavaで認識できる文字に置き換えられるので「$eq」となっている。
  • getterは、プロパティ名になっている。
//***********************************************
// Hogeクラス
//***********************************************
public class Hoge 
    implements ScalaObject 
{ 
    // hoge1のgetter
    public String hoge1() 
    { 
        return hoge1; 
    } 
    // hoge1のsetter
    public void hoge1_$eq(String s) 
    { 
        hoge1 = s; 
    } 
    // hoge2のgetter
    public int hoge2() 
    { 
        return hoge2; 
    } 
    // hoge2のsetter
    public void hoge2_$eq(int i) 
    { 
        hoge2 = i; 
    } 
 
    public Hoge() 
    { 
    } 
 
    // 公開フィールドは、privateなフィールドとなっている。
    private String hoge1; 
    private int hoge2; 
} 

//***********************************************
// アクセスメソッドを呼び出すコード
//***********************************************
Hoge hoge = new Hoge();
// setter(プロパティ名 + "_=")を呼び出すコードに変換されているのがわかる。
hoge.hoge1_$eq("hoge");
hoge.hoge2_$eq(1);

Predef$.MODULE$.println(hoge.hoge1());
Predef$.MODULE$.println(BoxesRunTime.boxToInteger(hoge.hoge2()));
ちなみち、varフィールドをprivateにするとアクセスメソッドが生成されないのでこんな感じにコンパイルエラーが出る。
    Error:Error:line (6)error: variable hoge1 in class Hoge cannot be accessed in Hoge
hoge.hoge1 = "hoge"
    Error:Error:line (7)error: variable hoge2 in class Hoge cannot be accessed in Hoge
hoge.hoge2 = 1
    Error:Error:line (9)error: variable hoge1 in class Hoge cannot be accessed in Hoge
println(hoge.hoge1)
    Error:Error:line (10)error: variable hoge2 in class Hoge cannot be accessed in Hoge
println(hoge.hoge2)

パターン2:明示的にアクセスメソッドを定義する方法

明示的にアクセスメソッドを定義するには、フィールドをprivateにしてあげてパターン1で自動生成された形式でsetterとgetterを宣言してあげればよいです。
例えば、アクセスメソッドで処理をしたい場合やgetterのみを宣言する場合に使います。(Javaのように、getHogeやsetHogeを宣言する必要はないです。)
気をつけないといけないのは、フィールド名とgetter名が同じになってはいけないのと、
setter名は、プロパティ名の後に「_=」をつけるのを忘れないこと。「_」と「=」の間にスペース入れちゃうのもダメ。
  // フィールドはprivateで宣言する。
  private var h1: String = _
  private var h2: Int = _

  // getter
  def hoge1: String = h1

  // setter
  def hoge2_=(hoge2: Int) {
    require(hoge2 > 100)
    h2 = hoge2;
  }
  // getter
  def hoge2: Int = h2

2011年9月17日土曜日

[scala]Listの色々

Listの操作のまとめ。

Listの生成

    // listの生成
    val list = 1::2::Nil            // Nilは、終端を示す
    val list2 = List("1", "2", "3")

    // 空のlistの生成
    val emp = Nil

パターンマッチでの分解

      val list = List(1, 2, 3)

      // Listの各要素を変数に分解
      // Listの要素数と、展開先の要素数が一致している必要がある。
      val List(n1, n2, n3) = list
      println("n1 = " + n1)    // 1
      println("n2 = " + n2)    // 2
      println("n3 = " + n3)    // 3

      // Listの要素が不確定の場合は、::(コンスと呼ぶらしい)を使って展開する。
      // この例だと1つ目の要素がnに代入され、残りの要素がListとしてnxに代入される。
      val n::nx = list
      println(n)                      // 1
      println("nx = " + nx)      // List(2, 3)

      // caseをつかったパターンマッチ
      list match {
        case List() => println("空のList")
        case n::nx => {
          println(n)           // 1
          println(nx)         // List(2, 3)
        }
      }

Listの結合

      val list = List(1, 2, 3)

      // :::を使ってList同士を結合出来る。
      val list2 = list ::: 1 :: 2 :: 3 :: Nil
      println("list2 = " + list2)    // List(1, 2, 3, 1, 2, 3)

Listのサイズ

Listの要素数は、lengthメソッドで取得出来ます。
      val list = List(1, 2, 3)

      list.length   // 3

lengthメソッドは要素数に比例してコストが高くなるらしいので要素が空か判定する場合には、length == 0ではなくisEmptyを使った方がよいそうです。
実際にListのコード見てみると要素が空になるまでtail(先頭の要素を除外したListを返すメソッド)してるのでかなりコスト高そう・・・。
  def length: Int = {
    var these = self
    var len = 0
    while (!these.isEmpty) {
      len += 1
      these = these.tail
    }
    len
  }

先頭、末尾へのアクセス

      val list = List(1, 2, 3)
      // 先頭の要素
      list.head    // 1
      // 先頭の要素を取り除いたList
      list.tail       // List(2, 3)
      // 最後の要素
      list.last      // 3
      // 最後の要素を取り除いたList
      list.init       // List(1, 2)
※最後の要素へアクセスするlastやinitはlengthと同じようにコストが高くつく。頻繁に末尾要素へアクセスする場合には、事前にreverseメソッドで要素を逆転するのがよいみたいです。

その他

      val list = List('a', 'b', 'c')
      // mapメソッド
      // 引数で指定された関数の結果から新たなListを生成する。
      // この例だと、list変数の各要素を大文字に変換したListを生成する。
      val upperList = list.map(_.toUpper)

      // Listをもとに繰り返し処理を行う場合には、foreachを使う
      // Javaでのfor文かな
      val builder = StringBuilder.newBuilder
      list.foreach(builder.append(_))
      builder     // abcとなる。

      // 条件に一致する値だけに絞り込んだListを生成する
      val abList = list.filter(c => c == 'a' || c == 'b')

      // 条件に一致した最初の要素を返す
      val n = List(1, 2, 3, 4, 5).find(_ % 2 == 0)

JDBCでORA-01000が出た場合の対処

OPEN_CURSORS初期パラメータが適切に設定されていない場合や、
JDBCを使用したアプリケーションでリソース開放を適切に行っていない場合に「ORA-01000: 最大オープン・カーソル数を超えました。」が発生する場合があります。

JDBCを使用したアプリケーションが適切にリソース開放を行えているのであれば、一つのDBセッションで発行するSQLの種類をもとにOPEN_CURSORSを設定してあげることができます。
マニュアルには、「OPEN_CURSORSに指定する値が実際に必要な数より大きくても、セッションでオープンするカーソル数が指定した値よりも小さければ、余分なオーバーヘッドはありません。」と書かれているのでかなり余裕をもった値を設定すればいいのかなとも思います。

OPEN_CURSORSを変更する方法

現在のOPEN_CURSORSの値の確認方法

sqlplusから下記コマンドを実行することにより確認できます。
show parameters open_cursors

※「SELECT ON V_$PARAMETERオブジェクト権限」が必要なので、権限をもったユーザでログインする必要があります。

OPEN_CURSORSの変更方法

例えば、1000に変更したい場
alter system set open_cursors = 1000;

上記コマンドを実行したあとのOPEN_CURSORS値
SQL> show parameters open_cursors;

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
open_cursors                         integer     1000

※「ALTER SYSTEMシステム権限」を持つユーザで実行する必要があります。

アプリケーションの実装を見直す場合

必ずリソース開放がされていることを確認する必要があります。ここで言うリソースとは、java.sql.Statementのことであってjava.sql.ResultSetでありません。
注意しないといけないのは、DML文に対応するStatementも1カーソルとしてカウントされてしまうことです。

※普通なシステム開発では、フレームワークでリソース開放してくれるはずなんでアプリでリソース開放なんてする必要はないはずです。
昔いけてないフレームワークでリソース開放してくれずにこのエラーが頻発したことありましたが・・・。

正しいリソース開放の例
        // DML文の場合
        PreparedStatement statement = connection.prepareStatement(
                "SQL文");
        try {
            statement.executeUpdate();
        } finally {
            // finallyでstatementをcloseする。
            statement.close();
        }

        // selectの場合
        PreparedStatement select = connection.prepareStatement(
                "SQL文");
        try {
            ResultSet rs = statement.executeQuery();
            while (rs.next()) {
                // 処理
            }
        } finally {
            // finallyでstatementをcloseする。
            // ResultSetは、statementクローズ時にcloseされる。
            select.close();
        }


2011年9月14日水曜日

[Intellij]Mac OS Xの場合の構成ファイルの場所

Windowsだと、IDEA_HOME/bin/idea.propertiesに記述されている内容通りに構成ファイル(pluginやlogが出力されるフォルダ)が配置されていたけど、
Mac OS Xにしてみたらidea.propertiesの設定通りの場所に構成ファイルを見つけることができず・・・。

Mac OS Xでも設定内容は、Windowsと一緒だったので普通に考えるとユーザホームはいかに「.IntellijIdea10」のディレクトリがあると思ったんだけど存在せず・・・。
頑張ってfindした結果Macでは、下記構成になっているらしい。
調べた後に気づいたんだけど、JetBrainsのサイトにOSごとの構成書いてあった。
http://devnet.jetbrains.net/docs/DOC-181

  • configディレクトリ
    ~/Library/Preferences/IntelliJIdea10
  • pluginディレクトリ
    ~/Library/Application Support/IntelliJIdea10
  • ログディレクトリ
    ~/Library/Logs/IntelliJIdea10

[JUnit]assertThat用のMatcherを作成してみる

assertThat用のMatherはデフォルトで色々用意されているけど、拡張可能になっているので用途にあわせて独自に追加可能となっている。

基本的には、タイプセーフな「org.junit.internal.matchers.TypeSafeMatcher」を継承して拡張を行えばよい。
TypeSafeMatcherを拡張するポイントは、こんな感じ。
  • matchesSafely
    期待値と実際の値の比較を行うメソッド。
    比較結果をbooleanで返却してあげる。
  • describeTo
    期待値と実際の値が異なる場合の実際のメッセージに表示する値を生成する。(下の画像の部分)

サンプル

このサンプルは、実際の値がjava.util.Dateの場合に、期待値に8桁の文字列を指定出来るようにするMatcher。
実際にisを使うと期待値と実際の値はタイプが一致していないといけないので、困難があると決行便利だったりする。

    @Test
    public void testGetDate() {
        // 実際の値はDateだが、期待値には8桁の文字列日付を指定する。
        assertThat(Hoge.getDate(), DateMatcher.isDate("20110910"));
    }

    /**
     * Date型と8桁の文字列をassertするクラス。
     * org.junit.internal.matchers.TypeSafeMatcherを継承して機能拡張する。
     */
    private static class DateMatcher extends TypeSafeMatcher {

        private String expected;
        private Date expectedDate;

        public DateMatcher(String expected) {
            this.expected = expected;
            if (expected == null) {
                return;
            }
            // 期待値が有効な日付かのチェックを事前に行う。
            SimpleDateFormat yyyyMMdd = new SimpleDateFormat("yyyyMMdd");
            try {
                expectedDate = yyyyMMdd.parse(expected);
            } catch (ParseException e) {
                throw new IllegalArgumentException("8桁の有効な日付を指定してください。", e);
            }
        }

        /**
         * assertThatの期待値に指定するMatcherのファクトリメソッド。
         * @param date 期待値(8桁の有効な日付)
         * @return Matcher
         */
        public static DateMatcher isDate(String date) {
            return new DateMatcher(date);
        }

        /**
         * メッセージの構築。
         * 期待値をDateに変換してメッセージに追加する。(時間部分は差分として出ちゃうけど、めんどいのでこの辺は適当)
         * @param description
         */
        public void describeTo(Description description) {
            if (expected == null) {
                description.appendText(expected);
            } else {
                description.appendValue(expectedDate);
            }
        }

        /**
         * 実際の値との比較を行う。
         * @param item 実際の値
         * @return 一致している場合はtrue
         */
        @Override
        public boolean matchesSafely(Date item) {
            if (item == null && expected == null)  {
                return true;
            }
            // 実際の値を8桁の文字列日付に変換して比較を行う。
            SimpleDateFormat yyyyMMdd = new SimpleDateFormat("yyyyMMdd");
            String actual = yyyyMMdd.format(item);
            return actual.equals(expected);
        }
    }

2011年9月13日火曜日

[Intellij]行番号の表示、非表示の切り替え

Intellijのコードエディタの行番号を表示する方法

ファイル単位で切り替える場合は、下の画像のように、メニューバーの「View」→「Show Line Numbers」で切り替えることができます。
※エディタがアクティブになっていないと出てくるメニュー内容が変わるのでご注意を。



すべてのファイルで常に行番号を表示させたい場合は、「settings」→「Editor」→「Appearance」の「Show Line Numbers」をオンにしてあげればよいです。


「Intellij 行番号」でのアクセスがあったので書いてみました。

Scalaで正規表現を使ったパターンマッチ

正規表現を使ったパターンマッチの例
    def patternMatch(args:String) {
      // 正規表現を定義する
      val pattern1 = "([0-9]+)".r
      val pattern2 = "([a-zA-Z]+)".r
      args match {
        // caseで定義した正規表現を指定する。
        // 前方参照可能なグループがある場合には、そのグループを代入する定数を指定する。
        case pattern1(n) => println("number = " + n)
        case pattern2(s) => println("string = " + s)
        case s:String => println("other = " + s)
      }
    }
    patternMatch("100")             // -> number = 100
    patternMatch("abc")             // -> string = abc
    patternMatch("abc100")        // -> other = abc100
こんな感じにいけるんかと思ってたけどコンパイルエラーで悩まされた・・・
      args match {
        case "([0-9])+".r => println("number")
        case "([a-zA-Z)+".r => println("string")
        case s: String => println("other = " + s)
      }

2011年9月4日日曜日

OracleのBLOBにJavaオブジェクトを保存

OracleデータベースのBLOB型のカラムにJavaオブジェクトを保存する方法。


サンプルコード

データベース定義

SQL> desc blob_test

 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 ID                                        NOT NULL CHAR(5)
 OBJECT_DATA                                        BLOB

データベースへの保存方法

        // DBへ保存するオブジェクトを生成
        // DBへ保存するオブジェクトは直列化可能でなければならない。
        // (Serializableをimplementsする必要がある)
        HogeInfo info = new HogeInfo();
        info.setId("ID");
        info.setName("なまえ");

        // 上記で生成したオブジェクトを直列化し、OutputStreamへ書き出す。
        // この例だと、ByteArrayOutputStreamに出力をしている。
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ObjectOutputStream stream = new ObjectOutputStream(out);
        stream.writeObject(info);

        PreparedStatement preparedStatement = con.prepareStatement(
                "insert into blob_test (id, OBJECT_DATA) values (?, ?)");

        try {
            preparedStatement.setString(1, "00001");
            // ByteArrayOutputStreamに出力したオブジェクトの情報を、byte配列で取得し
            // BLOBカラムにバインドする。
            preparedStatement.setBytes(2, out.toByteArray());
            preparedStatement.executeUpdate();
        } finally {
            preparedStatement.close();
        }

データベースからの取得方法

        PreparedStatement preparedStatement = connection.prepareStatement(
                "select object_data from blob_test where id = '00001'");
        byte[] bytes;
        try {
            ResultSet resultSet = preparedStatement.executeQuery();
            resultSet.next();
            // BLOBカラムの値をbyte配列で取得
            bytes = resultSet.getBytes(1);
        } finally {
            preparedStatement.close();
        }

        // 取得したオブジェクトをObjectInputStreamを使ってデシリアライズする。
        ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(bytes));
        HogeInfo hogeInfo = (HogeInfo) objectInputStream.readObject();

        // デシリアライズしたオブジェクトの属性を出力
        System.out.println("hogeInfo.getId() = " + hogeInfo.getId());
        System.out.println("hogeInfo.getName() = " + hogeInfo.getName());

実行結果

保存したオブジェクトの属性が、復元できていることが分かる。
hogeInfo.getId() = ID
hogeInfo.getName() = なまえ

2011年8月25日木曜日

Intellijでscala開発

IntellijにScala開発環境を導入する手順

scalaライブラリのダウンロード

下記サイトからscalaのライブラリをダウンロードしておきます。
http://www.scala-lang.org/downloads

ダウンロードしたDistributionは、任意のディレクトリに解凍しておきます。

Intellijのscalaプラグインをインストール

プラグインのインストール画面からscalaプラグインをインストールします。インストール後にIntellijを再起動する必要があります。

scalaプロジェクトの作成

1.「File」→「New Project」を選択

2.Create project from scratchを選択して次(Next)へ

3.プロジェクトを作成したいディレクトリを「Project file location」に入力して、select typeは、「Java Module」を選択します。


4.下記画面が表示されるまで次へ移動します。

5.下の画像のようにscalaを選択して、「use scala distribution」に、最初にダウンロードして解凍しておいたディレクトリを入力します。


6.「Finish」をクリックするとScalaプロジェクトの作成終了です。


hello worldってみる

「src」ディレクトリを右クリックし、「New」から「scala script」を選択する。

ファイル名を入力するダイアログが表示させるので任意のスクリプト名を入力。ここでは、ファイル名を「test.scala」としています。

エディタで、下記コードを入力する。

println("hello world.")


作成したスクリプトを実行するには、「F9」を押下するかメニューから「Run」→「Edit Configurations」を選択します。
選択すると下記画面が表示されるので「test.scala」を選択してEnterでスクリプトを実行します。


実行すると下記のようなRunウィンドウが表示され実行結果(hello world.)が表示されます。


これでscalaプロジェクトが正しく作成されたことが確認できたので、Intellijのscalaな開発環境でscalaをごりごり書いちゃいましょう。


追記
一時期Scala scriptの実行がIntellijから行えなかったけど、10/28にリリースされたpluginを適用すれば解消しています。

2011年8月23日火曜日

scala本を購入

scala本を購入してみた。

まだ少ししか読んでないけど、日本人の方が書いているので非常にわかりやすいと思います。
Scala初心者は下手な翻訳本を買うなら、この本の前半部で十分ではないかと思います。


2011年8月21日日曜日

Intellijの便利な正規表現編集

Javaソースコード上で正規表現を書く場合に、Javaのエスケープと正規表現のメタ文字に対するエスケープが同じ文字(\)なので、非常に面倒に思う場面がある。

その面倒な部分をうまく解消してくれる地味だけど非常に便利な正規表現編集機能がIntellijにはあります。

使用方法

正規表現部分にカーソルを移動して、クイックフィックスから「Edit RegExp Format」を選択する。
正規表現を編集するためのエディタが新規に開かれるので、正規表現を編集する。
この時には、Java文字列に対するエスケープは考えずに書けば良い。なので、純粋に正規表現のことだけを考えればよく直感的にコーディングが出来る。
また、正規表現がすでに書かれた状態でこのエディタ(Edit RegExp Format)を選択した場合も、Javaのエスキープ文字が削除されているので、正規表現を確認するときにも使うことができる。
画面的には、こんな感じになっている。


上記画面で編集を行っていると、リアルタイムにJavaコードに正規表現が反映されていきます。編集が終わったあとは「Esc」ボタンで閉じることが出来ます。
上記画面の正規表現がJavaコードに反映されると、Javaのエスケープ文字が追加されているのがわかります。

Intellijのすごいところは、正規表現を文字列定数とかで持っていても、この文字列は正規表現であると判断してこんな感じにクイックフィックスを表示してくれることです。

ここまでの例では、すべてJDK付属の正規表現ライブラリを使用していまいしたがオープンソースや自作の正規表現ライブラリに対しても上記と同じことができます。
例えば、こんな感じのクラスのsetRegexの引数を正規表現としたい場合の例
class HogeRegex {

    public void setRegex(String regex) {
        
    }
}
Settings画面から、Language Injectionを選択します。画面的には、こんな画面が表示されます。

「+」ボタンをクリックして「Java Parameter」を選択します。
表示されるサブウィンドウに下記のように入力します。
ID:RegExpを選択
Class-Name:正規表現ライブラリのクラス名入力する。(今回の例だとHogeRegexを入力する。)
Parameters:メソッド一覧とメソッドの持つパラメータ一覧が表示されるので正規表現を引数で受け取るパラメータにチェックを入れる。
設定を終えると、JDKのライブラリを使ったときと同じようにクイックフィックスに「Edit RegExp Format」が表示されるようになります。

ちなみにPatternクラスも、Language Injectionにちゃんと登録されていたりします。




2011年8月7日日曜日

rubyのリフレクション

eval

eval関数を使うと、指定した式を評価することができる。
式を文字列として指定するので、構文エラーとなるような文字列を指定したら例外が発生する。

使用例

# 計算を実行
eval("1 + 2")        # -> 3
eval("1 * 2")        # -> 2

# 変数を使用して計算の実行
num = 100
eval("num + num")    # -> 200

# 変数に値を設定
class Hoge
  attr_accessor :id
end

# idプロパティに値を設定
hoge = Hoge.new
eval("hoge.id=100")
puts hoge.id     # -> evalで設定された100が取得される

# インスタンス変数の宣言
eval("@hogehoge = 'hoge'")
puts @hogehoge   # -> @hogehogeが参照でき、'hoge'が取得できる。

# ローカル変数の宣言
# eval内で宣言されたローカル変数のスコープは、evalの処理を抜けたら参照できない。
eval("hogehoge = 12345; puts hogehoge")    # -> ここでは、ローカル変数を参照できる。

begin
  # evalを抜けているので参照すると、未定義ですよエラーが発生する
  puts hogehoge           
rescue => e
  puts e.message
end


インスタンスに対する操作

任意のインスタンス(クラス)のインスタンス変数やクラス変数の値参照や値設定方法

# インスタンス変数の操作
object = Object.new
# nameインスタンス変数は、存在していないのでfalse
object.instance_variable_defined?(:@name)
# nameインスタンス変数に値(instance_variable)を設定
object.instance_variable_set(:@name, "instance_variable")
# instance_variable_getが返される
object.instance_variable_get(:@name)
# nameインスタンス変数が追加されたのでtrue
object.instance_variable_defined?(:@name)
# nameインスタンス変数を削除
object.instance_eval { remove_instance_variable :@name }
# nameインスタンス変数は削除されたのでfalse
object.instance_variable_defined?(:@name)

# クラス変数に値をセット(宣言されていなければ追加される。)
# nameクラス変数は存在していないのでfalse
puts Object.class_variable_defined? :@@name
# nameクラス変数に値(class_variable)を設定
Object.class_variable_set(:@@name, "class_variable")
# class_variable_getが返される
puts Object.class_variable_get(:@@name)
# nameクラス変数が追加されたのでtrue
puts Object.class_variable_defined? :@@name
# nameクラス変数を削除
Object.class_eval { remove_class_variable :@@name }
# nameクラス変数は削除されたのでfalse
puts Object.class_variable_defined? :@@name

メソッドに対する操作

メソッド一覧の参照や、メソッドの実行ができる。また、動的にインスタンスにメソッドを追加することもできたりする。

object = Object.new
# public_methodsでも同じことができる。
object.methods
# 継承したメソッドを除外(自クラスで宣言したメソッドのみが出力される。)
# trueにすると、methodsと同じ動きになる。ちなみに引数省略した場合は、true
object.public_methods false

# 他にも、private_methodsやprotected_methodsがある。

# 特異メソッドの定義(このインスタンスのみがもつメソッド)
def object.hoge
  "fuga"
end
object.hoge
object.public_methods false

# メソッド呼び出し
hoge = "hogehoge"
hoge.send(:upcase)   # upcaseメソッドの呼び出し(メソッドは、シンボルとして指定する。)


2011年7月31日日曜日

java7とIntellij

Java7がリリースされたので、Intelijへの設定のまとめ。

SDKの追加

1.Project Structureを開く(「File」→「Project Structure」)
2.左側のメニューから「SDKs」を選択する。
3.「+」ボタンからjava7をSDKとして追加する。下の画像のように「+」ボタンで出てきたメニューから「JSDK」を選択する。
    4.Select Pathのサブウィンドウが表示されるので、java7のインストールディレクトリ(JAVA_HOME)を設定する。

    java7用のモジュールを作成

    1.Dependenciesタブを選択して、モジュールで使用するJDKを1.7に変更する。

    2.Sourcesタブを選択して、Language levelを7.0に変更する。

    java7用のInspectionを使ってみる

    Autoclosableへの置換え

    java6までのリソース管理(try-finallyでのリソース解放処理)を、java7のautoclosableに置き換えるInspectionを有効にすると、Quick Fixからautoclosableへの自動置き換えが可能となる。

    【変更前のコード】
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class Hoge {
    
        public static void main(String... args) throws IOException {
    
            FileOutputStream stream = new FileOutputStream("hoge.txt");
            try {
                stream.write(0);
            } finally {
                stream.close();
            }
        }
    }
    

    【Quick Fixの実行】
    「Replace with 'try' with resources」を実行する。

    【置き換え後のコード】
    自動で下のコードに置き換えが実行される。
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class Hoge {
    
        public static void main(String... args) throws IOException {
    
            try (FileOutputStream stream = new FileOutputStream("hoge.txt")) {
                stream.write(0);
            }
    
        }
    }
    

    これ以外のもこんなこともできるメモ。
    http://se-bikou.blogspot.com/2011/04/intellijjdk7.html

    2011年7月2日土曜日

    rubyのメソッド引数

    rubyのメソッド引数のまとめ

    通常の引数

    通常の引数をもつメソッド。当然ながら最も多く利用されると思われる。
    def print_message message
      print "[#{message}]"
    end
    

    デフォルト値をもつ引数

    デフォルト値をもつことでクライアントコードを簡略化できる。
    javaでオーバーロードを行い、引数の多いメソッドに固定値を渡すパターンの場合この実装で代用することが可能。
    ※rubyではオーバーロードを行うことができないので、デフォルト値を持つ引数をつかって実現するほかない。
    # p2を省略するとデフォルト値の0が適用される。
    def m1 p1, p2 = 0
      p1 + p2
    end
    
    m1 1      # p2を省略した場合
    m1 1, 2   # 明示的に指定した場合
    
    # p1を省略するとデフォルト値の1が適用される。
    def m2 p1 = 1, p2
      puts p1 + p2
    end
    
    m2 1      # p1を省略した場合
    m2 1, 2   # 明示的に指定した場合
    
    # p1を省略するとデフォルト値の1が適用される。
    # p2を省略するとデフォルト値の2が適用される。
    def m3 p1 = 1, p2 = 2
      puts p1 + p2
    end
    
    m3        # p1、p2を省略した場合
    m3 1      # p1を省略した場合
    m3 1, 2   # 明示的に指定した場合
    
    # 引数は、左から設定されるのでp1を省略してp2のみ値を指定することはできない。
    

    可変引数

    # 可変長引数は、変数名の前に「*」をつける。
    def hoge(*hoge)
      hoge.each do |val|
        puts val
      end
    end
    
    hoge("1", "2", "3")
    

    名前付き引数

    名前付き引数というのかわからないけど、引数を指定する際に名前をつけることができる。
    実際には、Hashで受け渡しを行うのだけれど、RubyのHashは簡易的にインスタンス化できるので、
    あたかも引数名に値を設定するかのように実装することができる。
    def m(args)
      puts "p1 : #{args[:p1]}"
      puts "p2 : #{args[:p2]}"
    end
    
    m p1:"hoge", p2:["fuga1", "fuga2"]
    

    2011年6月26日日曜日

    ローンパターンを使用したリソース開放

    リソースのオープンとクローズを共通化して、リソースをパラメータで受け取った関数にリソースを受け渡す実装方法。
    関数にリソースを貸し出すことからローンパターンと言われるらしい。

      def main(args: Array[String]) {
        // 第二引数に、PrintWriterを受けて
        // ファイル出力を行う関数を指定する。
        writeFile(new File("test.txt"),
          writer => writeData(writer))
      }
    
      private def writeData(printWriter: PrintWriter) {
        println("wite start")
        printWriter.println("1")
        printWriter.println("2")
        printWriter.println("3")
        printWriter.println("4")
        printWriter.println("5")
        println("wite end")
      }
    
      def writeFile(file: File, write: PrintWriter => Unit) {
        // リソースを開く
        println("open file.")
        val writer = new PrintWriter(file)
        try {
          // 第二引数の関数にリソースを貸し出す。
          write(writer)
        } finally {
          // 最後にリソースを閉じる
          println("close file.")
          writer.close();
        }
      }
    

    実行結果

    ファイルオープン→書き込み→ファイルクローズの順に処理が行われていることがわかる。
    open file.
    wite start
    wite end
    close file.
    

    ucpを使用したDB接続のプール

    JDK5以降(ojdbc5.jarやojdbc6.jar)を使用してOracleとの接続をキャッシュしたい場合、
    jdbcドライバのjar意外にucp.jarなるものが必要となる。

    ucpとは、ユニバーサルコネクションプールの略で、汎用的なプール機構を提供してくれる。
    汎用的な機構なので、別にOracle専用というわけではなくMySqlやDB2などの接続をプールすることができる。
    Webコンテナが提供してくれている接続のプーリング機構を、スタンドアロンアプリからも利用出来るようにしてくれてるイメージかな。

    マニュアルはこちら→http://download.oracle.com/docs/cd/E16338_01/java.112/b56283/toc.htm
    ucpは、http://www.oracle.com/technetwork/jp/database/enterprise-edition/ucp-096353-ja.htmlからダウンロード出来る。

    ※ojdbc5.jar以降のjdbcドライバには、ojdbc4.jarで使用していた接続プール機能はすべて非推奨となっている。
    しかも、その動作すら無効かされているため、プールを有効化しても完全に無視される。

    サンプルコード

    ucpを使用した接続キャッシュはこんな感じのコードで実装できる。
    PoolDataSourceには、ステートメントキャッシュ用のプロパティなどもあるが、そのへんはマニュアルを見て適宜設定すればよいかなと。
            // プールデータソースを生成
            PoolDataSource dataSource = PoolDataSourceFactory.getPoolDataSource();
    
            // コネクションファクトリクラス名を完全修飾名で設定する。
            // Oracleの場合は、「oracle.jdbc.pool.OracleDataSource」を設定すれば良い
            dataSource.setConnectionFactoryClassName(
                    "oracle.jdbc.pool.OracleDataSource");
    
            // DB接続情報(URL、ユーザ名、パスワード)を設定する。
            dataSource.setURL("jdbc:oracle:thin:@localhost:1521:xe");
            dataSource.setUser("hoge");
            dataSource.setPassword("hoge");
            // プール情報を設定する。
            dataSource.setInitialPoolSize(5);
            dataSource.setMaxPoolSize(5);
    
            // 接続を取得する。
            // このタイミングで、PoolDataSourceによって接続がプールされる。
            Connection connection = dataSource.getConnection();
    

    サンプルコード2

    接続先のデータベースがmysqlの場合の接続例。
    ConnectionFactoryClassNameをmysqlのデータソースに変えてあげて、接続設定をmysqlように変更する。
            // プールデータソースを生成
            PoolDataSource dataSource = PoolDataSourceFactory.getPoolDataSource();
    
            // コネクションファクトリクラス名を完全修飾名で設定する。
            // 「com.mysql.jdbc.jdbc2.optional.MysqlDataSource」を設定すれば良い
            dataSource.setConnectionFactoryClassName(
                    "com.mysql.jdbc.jdbc2.optional.MysqlDataSource");
            // DB接続情報(URL、ユーザ名、パスワード)を設定する。
            dataSource.setURL("jdbc:mysql://localhost/test");
            dataSource.setUser("hoge");
            dataSource.setPassword("hoge");
            // プール情報を設定する。
            dataSource.setInitialPoolSize(5);
            dataSource.setMaxPoolSize(5);
    
            // 接続を取得する。
            // このタイミングで、PoolDataSourceによって接続がプールされる。
            Connection connection = dataSource.getConnection();
    
    

    2011年6月12日日曜日

    intellijの行ブレークポイントのあれこれ

    Intellijのブレークポイントをいじり倒してみたので、メモとして残しておく。

    英語力が全く無いので理解が間違ってる部分があるかもだけど・・・。

    ブレークポイントを置く方法

    実行ステップに対するブレークポイントは、Eclipseと同じように行番号の隣の空白列をクリックすることによっておくことができる。
    (行番号は、「menu」→「View」→「Show Line Numbers」で表示される。)

    ブレークポイントを置くと、Eclipseと同じようにブレークポイントを示すマークが表示される。









    特定のコールスタックの場合のみブレークさせる方法

    Intellijでは、ブレークポイント間で依存関係を設定できるため、特定のコールスタックの場合のみブレークさせることができるようになっている。
    privateメソッドなどで処理を抽出した場合など、複数箇所から呼び出される場合に使えるかんじになっている。
    よく目的のコールスタックまで処理をスキップしようとして再開を連打してたら、目的のとこまで再開をクリックしちゃって最初からやり直しとかあるので、結構便利な機能かなと。

    まずは、ブレークしたい行と、ブレークしたいコールスタック上にブレークポイントを置く。
    この例だと、処理を中断したいhogeメソッド(7行目)と、hogeメソッドで処理を中断したい呼び出し元(12行目)にブレークポイントをおいている。













    次にブレークポイント間での依存関係を設定する。
    依存関係の設定は、View BreakPoints(「menu」→「Run」→「View BreakPoints」)で行う。
    デフォルトでは、ブレークポイントが下記画像のようにリスト表示される。
    右側のTree Viewボタンをクリックするとクラス単位やメソッド単位にグループ化して表示することができるので、見やすくなる。



















    今回は、12行目から呼び出された場合のみ7行目を止めたいのでその設定を行う。
    設定方法は、処理を中断したい7行目のブレークポイントを選択して、下の方にある「Depends on:」で12行目のブレークポイントを設定してあげる。



















    この設定だけだと、処理を中断したくない12行目でも処理が中断されてしまうので、12行目は処理を止めないようにする。
    View BreakPointsで12行目のブレークポイントを選択してSuspend policyでNoneを選択すると12行目のブレークポイントはスルーされる。






















    静止画だと、実際にデバッグ実行した際の動きを示せないので、実行した結果は割愛。。。


    処理を停止せずに標準出力に値のみ出力する方法

    デバッグする際に標準出力に値を出力するってよくやると思うけど、これだと「System.out.println」を消し忘れたりするので、ブレークポイントでのコンソール出力機能を使って値を確認する。

    この設定も「View BreakPoints」から行うことができる。
    値を出力したい行にブレークポイントを設定し、「Log evaluated expression」から、コンソールに出力したい値を設定してあげれば良い。変数名は、補完してくれます。

    ちなみに、標準出力には常に値が出力されるのではなく、処理中断の条件と一致した場合にのみ出力されます。
















    実際に実行した結果
    例がかなり行けてないけど、設定した値がコンソールに出力されていることがわかる。これで、余計な「System.out.println」を使わなくても、標準出力で値の確認ができるようになる。
    ただIntellijの場合、「Live Template」の「sysoutv」が非常に便利なんで普通に「System.out.println」使うだろうなと。






    条件を設定して処理を中断する方法

    これも「View BreakPoints」から設定できる。
    右側の「Condition」にBooleanを返す式を書いてあげると、結果がTrueの場合のみ処理が中断される。

    2011年5月14日土曜日

    scalaのプレースホルダ構文

    scalaには、プレースホルダ構文なるものがあって、関数をかなり簡潔にかけるようになっている。
    関数脳じゃないから理解するのにかなり苦労した。

    Listのforeachで使ってみると

        val list = List(1, 2, 3, 4, 5)
    
        // プレースホルダ構文を使用しない場合、
        // foreachに対してこんな感じに関数を渡す。
        list.foreach((x:Int) => println(x))
    
        // プレースホルダ構文を使った場合
        // 関数のパラメータをプレースホルダ(_)として書くことができる。
        list.foreach(println _)
    

    foreachに対して関数を渡すときと比べるとかなり簡潔になっている。
    ただし、プレースホルダ構文は関数内で1度のみの使用しか認められていない。
    なので、こんなコードはNGとなる。
        val list = List(1, 2, 3, 4, 5)
        // 関数内で、2度プレースホルダを使用しているので構文エラーとなる。
        list.foreach(
          println (_)
          println (_)
        )
    

    Listのsortで使ってみると

        
        val l = List(1, 3, 2, 5, 4)
        // sortは、引数を2つ必要とするので、それぞれをプレースホルダにできる。
        println(l.sort(_ < _))
    
        val hoges = List(new Hoge(3), new Hoge(1), new Hoge(2))
        // こんな感じにプレースホルダの属性を参照することもできる。
        println(hoges.sort(_.id < _.id))
    
        class Hoge(x:Int) {
          val id:Int = x
    
          override def toString = "Hoge{" + id + "}"
        }
    

    2011年5月6日金曜日

    JDBC経由でシーケンスを使用して採番した値の取得

    insert文などでシーケンスを使用して採番を行った値を取得する場合、
    JDBCの自動採番キー機能と、Oracleの拡張SQL文を使用する2パターンの方法がある。
    Oracle拡張機能を使用した場合、1レコード更新なら良いが複数レコード更新になると、
    クライアント側コードもOracleが拡張したJDBCの機能を使う必要があり、ちと面倒になる。

    JDBCの自動採番キー機能

            // Statement取得時に、自動採番キーの項目を第二引数で指定する。
            // この例では、ID列がシーケンスでの採番対象なので『ID』と指定している。
            PreparedStatement statement = con.prepareStatement(
                    "insert into test (ID, NAME) values (TEST_SEQ.nextval, ?)",
                    new String[]{"ID"});
            try {
                statement.setString(1, "hogehoge");
                statement.execute();
                // SQLを実行後、statementオブジェクトからgetGeneratedKeysを呼び出して、
                // 採番キーの結果を取得する。(1行だけなのにResultSetってのが面倒・・・)
                ResultSet keys = statement.getGeneratedKeys();
                try {
                    // ResultSetと同じ感じに値を取得する。
                    // ただし、カラム名指定でのアクセスは出来ないので、
                    // インデックス指定でアクセスする必要がある。
                    keys.next();
                    int id = keys.getInt(1);
                    System.out.println("id = " + id);
                } finally {
                    keys.close();
                }
            } finally {
                statement.close();
            }
            con.commit();
        }
    

    Oracleの拡張SQL機能

            // Oracleで拡張された、returning intoを使用して、
            // IDカラムの値をバインド変数(OUTパラメータに代入する。)
            // なお、SQL文はbegin endで囲い、無名pl/sqlにする必要がある。
            CallableStatement statement = con.prepareCall(
                    "begin insert into test (ID, NAME) "
                            + " values (TEST_SEQ.nextval, ?) returning id into ?; end;");
    
            try {
                statement.setString(1, "hoge");
                // OUTパラメータのタイプを指定する。
                statement.registerOutParameter(2, Types.INTEGER);
                statement.execute();
                // SQL実行後に、OUTパラメータの値を取得する。
                int id = statement.getInt(2);
                System.out.println("id = " + id);
                con.commit();
            } finally {
                statement.close();
            }
    

    Oracleの拡張SQL機能で複数行更新の場合

            // returning intoを使用してID列をOUTパラメータに代入する。
            // SQL文は、通常のSQL文形式で、statementはOracleJDBCのstatementにキャストする。
            OracleCallableStatement statement = (OracleCallableStatement)
                    con.prepareCall("update test set id = test_seq.nextval returning id into ?");
            try {
                // registerReturnParameterを呼び出して、データ型を設定する。
                // なお、この時に設定するデータ型はOracleTypesがもつ定数を使用する。
                statement.registerReturnParameter(1, OracleTypes.INTEGER);
                int count = statement.executeUpdate();
                System.out.println("count = " + count);
    
                // getReturnResultSetを呼び出して、OUTパラメータの結果セット(ResultSet)を取得する。
                ResultSet set = statement.getReturnResultSet();
                try {
                    while (set.next()) {
                        System.out.println("set.getInt(1) = " + set.getInt(1));
                    }
                } finally {
                    set.close();
                }
            } finally {
                statement.close();
            }
    

    2011年5月4日水曜日

    scalaのコンストラクタ

    scalaでコンストラクタの定義方法

    コード

    // 基本コンストラクタ
    // 基本コンストラクタは、クラス宣言で定義する(クラスのパラメータとして定義する)
    class Hoge(s: String, n: Int) {
    
      // 補助コンストラクタ(基本コンストラクタをオーバーロードする場合に定義する。)
      // 補助コンストラクタの最初のステップでは、必ず他のコンスとラクアを呼び出す必要がある。
      // この仕様に従うと、最後には必ず基本コンストラクタが呼び出される。
      def this(s: String) = this (s, 0)
      def this(n: Int) = this ("hoge", n)
    
      // コンストラクタの変数は、privateなインスタンス変数となる
      override def toString = s + ":" + n
    }
    
    object Hoge {
    
      def main(args: Array[String]) {
        // 基本コンストラクタに指定した値が出力される。
        println(new Hoge("string", 1))
    
        // 補助コンストラクタに指定した値と、補助コンストラクタで指定しているデフォルト値が出力される。
        println(new Hoge("hoge"))
        println(new Hoge(-1))
      }
    }
    

    実行結果

    string:1
    hoge:0
    hoge:-1
    

    2011年5月2日月曜日

    rubyで例外処理

    rubyでの例外処理方法

    javaで言うところのtry-catchに似たbegin-rescueブロックを使用した例外処理ができる。

    例外処理の基本

    下記コードだと、beginブロック内で発生した例外(StandardError)をrescueブロックで補足して処理をしている。
    rubyでは、rescueブロックで例外を指定しないとStandardError(JavaでのRuntimeException)が暗黙的に補足される。
    def hoge
      raise RuntimeError, "message"
    end
    
    begin     # javaでのtry
      hoge
    rescue    # javaでのcatch
    
      # 補足した例外は、グローバル変数の「$!」で参照できる。
      puts  "error, #{$!.message}"  
    end
    
    begin
      hoge
    # 例外を捕捉時に例外を変数に格納することも可能
    # 下記のように「=> 変数名」とすると、変数に代入することができる。
    rescue => exception
      puts "error, #{exception.message}"
    end
    

    特定の例外を捕捉

    rescueブロックで例外クラスを指定すると特定の例外のみを補足することができる。
    複数のrescueブロックを定義した場合、javaと同じように最初にマッチしたrescueブロックが実行される。
    def hoge(n)
      raise TypeError, "Type error." unless n.is_a? Integer
      n / 0
    end
    
    begin
      hoge(0)
    # ZeroDivisionErrorを捕捉
    rescue ZeroDivisionError => e
      puts  "error, #{e.message}"
    end
    
    begin
      hoge('a')
    # TypeErrorを捕捉
    rescue TypeError => e
      puts "error, #{e.message}"
    end
    
    begin
      hoge('a')
    # ZeroDivisionErrorとTypeErrorを捕捉
    rescue ZeroDivisionError, TypeError => e
      puts "error, #{e.message}"
    end
    

    2011年4月25日月曜日

    google日本語入力の候補移動キーの変更

    IMEの変換候補の移動を矢印キーでってのがどうにも面倒だったので、
    vimの補完候補の移動で使っているCtrl+nとCtrl+pで移動できるように変更してみた。
    これで生産性がだいぶ上がる気がすると、自己満足してみる。

    変更方法は、google日本語入力のなんでマイクロソフトのIMEでは出来るかはよくわからない。

    google日本語入力の設定画面を表示

    下記画像の工具のアイコン?を左クリックして、プロパティを選択する。






    キー設定の編集画面を開く

    キー設定の編集画面へ移動する。(赤枠のボタン)





















    キー設定を編集する

    変更するのは下記の3点。(変更ポイントは画像参照)
    • 変換前入力中の予測変換
    • 変換中の次候補へ移動
    • 変換中の前候補へ移動