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();
            }