Java7 の新機能

Java 7 がやっとリリースされたそうで。C#Scala のような先進的な機能が無く、後方互換を気にするあまり Java は古臭い言語になってしまいつつあるが、
JVM 上で動く言語がちらほら出てきてるので今後20年くらいは Java は主流で居続けるだろうな。きっと。

それでは Java7 の新機能(の一部)を試してみる。

1. switch 文で String を評価できるようになった
1.6 までの Java では switch 文は int か enum 型にしか使えなかった。Java7 からは int と enum に加えて String でも使えるように。

public static void main(String[] args) {
    String s = "hoge";
    switch( s )
    {
        case "huga":
            System.out.println("piyo");
            break;
        case "hoge":
            System.out.println("Hooo!");
            break;
        default :
            System.out.println("piyo");
    }
}

// 実行結果
Hooo!


ちなみに case null: は使えないので注意。


2. 数値リテラルにアンダースコアが使えるようになった
あまり需要のなさそうな新機能。以下のコードはコンパイルが通る。

public static void main(String[] args) {
    long creditCardNumber = 1234_5678_9012_3456L;
    long socialSecurityNumber = 999_99_9999L;
    float pi =       3.14_15F;
    long hexBytes = 0xFF_EC_DE_5E;
    long hexWords = 0xCAFE_BABE;
    long maxLong = 0x7fff_ffff_ffff_ffffL;
    byte nybbles = 0b0010_0101;
    long bytes = 0b11010010_01101001_10010100_10010010;
         
    System.out.println(socialSecurityNumber);
}

//実行結果
999999999

値を表示する際や評価する際はアンダースコアは無視され、以前と同様通常の数値として扱われる。


3. バイナリリテラルが定義された
新たに定義されたプレフィクス、 0b ( 0B でも可 ) を数値につけることでバイナリ値として表せるようになった。

public static void main(String[] args) {
    int bin = 0B00001101;
    System.out.println(bin);
}

//実行結果
13

メリットは、値を明示的にバイナリ値と表せること、かな?微妙や。

4. try-catch + リソース 文ができた。
キタ。やっと熱い機能がキタ。
try catch 内でリソースを扱う場合、finaly で resource.close() をする必要がある。場合によっては try-catch がたくさん出来たり、 try-catch のネストが発生してしまう場合があった。
しかし Java7 様のおかげで、勝手に close してくれるようになります。C# の using 文とほぼ同等の機能。もちろん、通常終了時だけじゃなく Exception 発生時にも close してくれる。( close 以外の場所で Exception が発生した場合 )

public static void main(String[] args) throws IOException {
    try ( FileWriter fw = new FileWriter("sample.txt") ) {
        fw.write("hoge");
        fw.write("huga");
    }
}

うむ、これだよこれ。この機能が欲しかった。
この構文は try-with-resources と呼ばれ、resouces からわかるように複数のリソースを定義できる。
ちなみに C# の using 文は 1 つしか定義できない ← 間違い。C#でも実装できるらしい。(コメント欄参照)
複数定義する場合はセミコロンで区切る。

try (
      ZipFile zf = new ZipFile(zipFileName);
      BufferedWriter writer = Files.newBufferedWriter(outputFilePath, charset)
    ) {
        ...
      }

うーむ、素晴らしい。今までのリソース関係の処理は煩わしかったが、これで少しは楽になる。

この try-with-resource 文で使えるリソースは、 java.lang.AutoCloseable か java.io.Closeable を実装している必要がある。それでは自前リソースでテスト。

public class TestResource implements Closeable {
    public void close() {
        System.out.println("close!");
    }
    
    public String toString() {
        return "This is a TestResource Object";
    }
}

使う。

public static void main(String[] args) {
    try ( TestResource test = new TestResource() ) {
        System.out.println( test );
    }

    System.out.println("bye!");
}

実行結果

This is a TestResource Object
close!
bye

おお!ちゃんとプログラム実行中に勝手に close が呼ばれているではないか!さすがっす!


5. try-catch 文で catch 文が省略できるようになった。
上記リソースを勝手に close してくれる例を見ると分かる通り、catch 文が省略できる。
これは Suppressed Exceptions と呼ばれており、メソッドの throws の後に宣言した Exception と同じ型、
または継承している Exception の場合にのみ省略可能。
もちろん、以前のように catch 文をつけてエラー処理をすることもできる。

6. 複数の Exception を一つの catch 文でキャッチできるようになった。
今までは以下のようなコードが頻発していた。

catch (IOException ex) {
     logger.log(ex);
     throw ex;
catch (SQLException ex) {
     logger.log(ex);
     throw ex;
}


エラー処理内容は同じなのに、発生する Exception の種類だけ似た catch 文を書かなければならなかった。
これが改善され、1 つの catch 文で複数の Exception をキャッチできるようになった。

catch (IOException|SQLException ex) {
    logger.log(ex);
    throw ex;
}


見ての通り、Exception の種類を | で区切る。

次世代バージョンの Java に望む機能
・finalize が呼び出されることを保証
・クロージャ

かな。finalize を呼び出すことが保証されないからリソースの解放に苦労するのであって、もし finalize が呼び出されることが保証されるなら finalize メソッド内で this.close(); を呼び出すだけでリソースの解放が保証される。Exception の発生が問題になるが、その辺は上手いことやってくれないかなー。
クロージャもいい加減使えるようにして欲しい。


まとめ
これから Java負の遺産的言語になる。
Scala 使おう。

参考
Java7 リリースノート
http://www.oracle.com/technetwork/java/javase/jdk7-relnotes-418459.html