2014年12月23日火曜日

H2データベースでテーブルが存在しない時だけテーブルを作成

H2データベースでテーブルが存在しない時だけテーブルを作成する方法です。

CREATE時に、IF NOT EXISTSを使用することで、テーブルが存在しない時のみ作成することができます。
これを使うことで、テーブル定義済み例外の発生を防ぐことができます。

CREATE TABLE IF NOT EXISTS USER (
  ID BIGINT NOT NULL AUTO_INCREMENT,
  NAME VARCHAR(100 CHAR) NOT NULL,
  PRIMARY KEY (ID)
);

このIF NOT EXISTSはVIEWの作成やカラムの追加時などにも使用できます。

2014年12月22日月曜日

[Oracle12c]generatedカラムの値をJDBC経由でinsert後に取得する

Oracle12cで追加された自動生成カラムの値を、JDBC経由でINSERTを行った際に取得する方法です。

コードサンプル

テーブル定義

CREATE TABLE USER_INFO
(
    ID INTEGER PRIMARY KEY NOT NULL,
    NAME VARCHAR2(100)
)

Javaコード

PreparedStatement statement = connection
        .prepareStatement(
                "insert into USER_INFO (name) values (?)",
                new String[]{"id"});
statement.setString(1, "なまえ");
int count = statement.executeUpdate();
System.out.println("count = " + count);

try (ResultSet generatedKeys = statement.getGeneratedKeys()) {
    if (generatedKeys.next()) {
        System.out.println(generatedKeys.getInt(1));
    }
}

解説

PreparedStatement生成時に、自動生成キーを返す機能を持つPreparedStatementを生成します。
上のサンプルでは、自動生成カラムはID列なので、prepareStatementの2番めの引数にID列を指定しています。

必要な値をバインド後に、executeUpdateを呼び出してINSERT処理を実行します。

INSERT処理が正常に終了後、getGeneratedKeysを呼び出して、自動生成カラムに対して自動的に採番されて設定された値を取得します。
getGeneratedKeysは、ResultSetを返すのでフェッチ(nextメソッドの呼び出し)しながら値を取得していきます。
Oracleでは、getGeneratedKeysで返されるResultSetからの値の取得はインデックスのみ可能なので、カラム名によるアクセスは出来ません。

[Java8]インタフェースのデフォルトメソッド

Java8から新しく追加されたインタフェースのデフォルトメソッド。

デフォルトメソッドの定義

デフォルトメソッドは、defaultキーワードと共にメソッドを宣言します。
この例では、printメソッドがデフォルトメソッドとして宣言されています。
interface Hoge {
    default void print() {
        System.out.println("hoge");
    }
}

同じデフォルトメソッドを持つ複数のインタフェースを実装した場合

何もしなければコンパイルエラーとなります。
例えば、下のコードではImplクラスが同じ定義のデフォルトメソッドを持つI1とI2インターフェースを実装しているので、コンパイル時にエラーとして報告されます。
interface I1 {
    default void print() {
        System.out.println("I1");
    }
}
interface I2 {
    default void print() {
        System.out.println("I2");
    }
}

class Impl implements I1, I2 {
}

もしどちらか一方の実装を使用したいのであれば、superキーワードを使用して一方のインタフェースの実装を選択します。
下の例では、I2インタフェースのデフォルト実装を選択しています。
class Impl implements I1, I2 {
    @Override
    public void print() {
        I2.super.print();
    }
}

もちろん、下のコードのように実装を上書きすることもできます。
class Impl implements I1, I2 {
    @Override
    public void print() {
        System.out.println("Impl");
    }
}

片方がデフォルトメソッドで片方が抽象メソッドの場合も、コンパイルエラーとなります。
この場合も、上で説明したようにデフォルトメソッドを選択するか、このクラスで新たな実装をするか選択する必要があります。
interface I1 {
    default void print() {
        System.out.println("I1");
    }
}
interface I2 {
    void print();
}

class Impl implements I1, I2 {
}

一方が抽象クラスの場合には、抽象クラスに定義されたメソッドが優先されて選択されます。
例えば下のコードの場合、A1抽象クラスに定義されたprintメソッドが呼び出されます。
interface I1 {
    default void print() {
        System.out.println("I1");
    }
}

abstract class A1 {
    public void print() {
        System.out.println("A1");
    }
}

class Impl extends A1 implements I1 {
}

2014年11月3日月曜日

[Java8]メソッド参照

lambda式で定義したい処理内容と全く同じ処理をするメソッドがすでに提供されている場合には、
そのメソッドをメソッド参照という機能を使用してメソッドを渡してあげれば良い。

メソッド参照は、以下のように::演算子でクラス名(オブジェクト名)とメソッド名を連結して使用する。
使用できるパターンは、以下のとおり。

* オブジェクト::instanceメソッド
* クラス名::staticメソッド
* クラス名::instanceメソッド

使用例

System.out.printlnを使用した例は以下のようになる。
list.forEach(System.out::println);

// 上記は、以下と全く同じ
list.forEach(s -> System.out.println(s));

オーバロードされたメソッドがある場合

メソッド参照使用時で、オーバロードされたメソッドが存在していた場合にどのメソッドを呼びだそうとしているかについては、コンパイラがコードの内容から判断しようとする。

例えば、以下の例だとメソッド参照が使用された箇所の関数型インタフェースが受け取る型に対応したメソッドが使用される。

public class Hoge {

    public static void main(String[] args) {
        List strings = Arrays.asList("1", "2", "3");
        strings.forEach(Hoge::output);  // Stringを引数に取るoutputが選択される

        List numbers = Arrays.asList(1, 2, 3);
        numbers.forEach(Hoge::output);  // intを引数に取るoutputが選択される
    }

    public static void output(String s) {
        System.out.println("string");
    }

    public static void output(int i) {
        System.out.println("int");
    }
}

2014年11月2日日曜日

[Java8]Lambda式の形式

ラムダ式は、引数 -> 式本体の形式で記述する。

基本パターン

(String first, String second) -> {
  return Integer.compare(first.length, second.length)
}

型推論可能な場合は、引数の型を省略出来る

左辺の総称型などから推論可能な場合などに型推論される。
(first, second) -> {
  return Integer.compare(first.length, second.length)
}

型推論された引数を一つだけ保つ場合には、カッコも省略可能

Arrays.asList(1, 2, 3, 4, 5).forEach(n -> System.out.println(n));

アノテーションなど

メソッドの引数と同じように、、アノテーションやfinal修飾子をつけることも可能
(final String first, final String second) -> {
  return Integer.compare(first.length, second.length)
}

戻り値について

lambdaの戻り値は明示しない。常に文脈から型が判断される。
以下の例だとintが期待されているところで使用できる。

※分岐などで結果を返したり返さなかったりするようなlambda式は不正となる。(コンパイルエラー)
(final String first, final String second) -> {
  return Integer.compare(first.length, second.length)
}

2014年10月22日水曜日

Java8のFunctionalInterfaceアノテーション

FunctionalInterfaceは、関数型インタフェースであることを示すために使用するアノテーション。

基本的に、関数型インタフェースの要件(インタフェースで抽象メソッドは1つなど・・・)を満たしていれば良いが、
FunctionalInterfaceアノテーションを付加するとコンパイル時に関数型インタフェースの要件を満たしていない場合コンパイルエラーとしてくれる。
また、このインタフェースが関数型インタフェースであることが、明確なので関数型インタフェースにはこのアノテーションを付加するとよい。

例えば、以下の様なインタフェース定義は関数型インタフェースの要件を満たさないためコンパイルエラーとなる

@FunctionalInterface
interface Hoge {
    void hoge();
    void fuga();
}

エラー内容としては以下の様なものが出力される。
Error:(1, 1) java: 予期しない@FunctionalInterface注釈
  Hogeは機能インタフェースではありません
    インタフェース Hogeで複数のオーバーライドしない抽象メソッドが見つかりました

2014年10月5日日曜日

[jQuery]first-of-typeセレクタ

バージョン1.9から追加されたセレクタ。

親要素内で、セレクタで指定した要素が最初に出現する要素が選択される。

この例だと、div要素内で最初に出現するspanタグが選択される。
(hogeとあいうえおのspanタグ)
<div>
  <span>hgoe</span>
  <span>fuga</span>
</div>
<div>
  <span>あいうえお</span>
  <span>かきくけこ</span>
  <span>さしすせそ</span>
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
  $("span:first-of-type").css({
    color: 'red'
  });

</script>

表示結果

選択された最初のspanタグにスタイルが設定されているのがわかる。

※first-of-typeと逆のlast-of-typeセレクタもある。