Java7の実験。
正式リリースも近いのでいじってみた。
文法上の変更や新しい記法などを中心に、いざソースを読む際にちょっと困ったりしないような視点でみてみました。
AutoCloseable
どうでもいいけど、Closableじゃないんだね。
http://oxforddictionaries.com/noresults?dictionaryVersion=region-uk&isWritersAndEditors=true&noresults=true&page=1&pageSize=20&q=closeable&searchUri=All&sort=alpha&type=dictionarysearch
って該当なしにされるんだけど・・・まぁいいか。
コンパイルは対応していなくてもコードアシストレベルではeclipseが現状でも頑張ってくれるし。
匿名なのでわかりにくいかもしれないけど・・・
try(ここで初期化) {
} catch(Exception e) {
}
といった文法
catchは省略不可っぽい。
(匿名インナークラスの場合throws宣言なしでも不可。インナークラスなんかをちゃんと定義してやれば可能)
try ( AutoCloseable ac1 = new AutoCloseable() { @Override public void close() throws Exception { System.out.println("ac1 close"); } }; ) { //処理 } catch(Exception e) { System.out.println("catch"); } finally { System.out.println("try finally"); }
結果
ac1 close try finally
どうやら、finally前でcloseされるようだ。
というわけで、finallyでそのリソースは使用できないようですね。
※catchや、finallyだとそもそもスコープ外。場合によっては中でtry-catchブロックが必要になることもあるかと。
以下のように外側で変数定義だけ済ましておくなんてのはコンパイルエラー
AutoCloseable ac1 = null; try (ac1 = new AutoCloseable() { @Override public void close() throws Exception { System.out.println("ac1 close"); } };) { } catch(Exception e) { System.out.println("catch"); } finally { System.out.println("try finally"); }
ちなみに、以下のようにtryの中での変数への代入に関してもコンパイルエラー
エラー: 自動クローズ可能なリソースac1に値を代入することはできません
try (AutoCloseable ac1 = null) { ac1 = new AutoCloseable() { @Override public void close() throws Exception { System.out.println("ac1 close"); } }; } catch(Exception e) { System.out.println("catch"); } finally { System.out.println("try finally"); }
複数のリソース初期化にも対応
try ( AutoCloseable ac1 = new AutoCloseable() { @Override public void close() throws Exception { System.out.println("ac1 close"); } }; AutoCloseable ac2 = new AutoCloseable() { @Override public void close() throws Exception { System.out.println("ac2 close"); } }; ) { } catch (Exception e) { e.printStackTrace(); } finally { System.out.println("try finally"); }
結果
ac2 close ac1 close try finally
だそうで、開いたのと逆に閉じていくという鉄則どおりの挙動ですね。
んじゃまぁ、例外が発生した場合どうなるのか?
両方とも例外が発生した場合
try ( AutoCloseable ac1 = new AutoCloseable() { @Override public void close() throws Exception { System.out.println("ac1 close"); throw new Exception("close exception"); } }; AutoCloseable ac2 = new AutoCloseable() { @Override public void close() throws Exception { System.out.println("ac2 close"); throw new Exception("close exception"); } }; ) { } catch (Exception e) { e.printStackTrace(); } finally { System.out.println("try finally"); }
ac2 close ac1 close java.lang.Exception: close exception at java7.autoclose.AutoCloseMain$2.close(AutoCloseMain.java:20) at java7.autoclose.AutoCloseMain.main(AutoCloseMain.java:24) Suppressed: java.lang.Exception: close exception at java7.autoclose.AutoCloseMain$1.close(AutoCloseMain.java:12) ... 1 more
と、Suppressedが追加されていますね。
最初を主として、その後はsuppressedとして追加されていくようです。
例外が発生しても残りのclose処理はちゃんと実行されていきます。
ThrowableにはaddSuppressedと、getSuppressedが追加されています(protectedのコンストラクタも)
try ( AutoCloseable ac1 = new AutoCloseable() { @Override public void close() throws Exception { System.out.println("ac1 close"); throw new Exception("close exception"); } }; AutoCloseable ac2 = new AutoCloseable() { @Override public void close() throws Exception { System.out.println("ac2 close"); throw new Exception("close exception"); } }; ) { } catch (Exception e) { e.printStackTrace(); System.out.println("ここからgetSuppressed"); Throwable[] suppressed = e.getSuppressed(); for (Throwable throwable : suppressed) { throwable.printStackTrace(); } } finally { System.out.println("try finally"); }
ac2 close ac1 close java.lang.Exception: close exception at java7.autoclose.AutoCloseMain$2.close(AutoCloseMain.java:20) at java7.autoclose.AutoCloseMain.main(AutoCloseMain.java:24) Suppressed: java.lang.Exception: close exception at java7.autoclose.AutoCloseMain$1.close(AutoCloseMain.java:12) ... 1 more ここからgetSuppressed java.lang.Exception: close exception at java7.autoclose.AutoCloseMain$1.close(AutoCloseMain.java:12) at java7.autoclose.AutoCloseMain.main(AutoCloseMain.java:24) try finally
マルチキャッチ
マルチキャッチは
} catch (IOException | AssertionError e) {
まさかのパイプ。変数名は最後のみというのがポイント。
てっきりセミコロン区切だと思っていたのに・・・
数値表現
//数値表現に_を入れて、区切を意識させられる BigDecimal currency = new BigDecimal(123_456_789); System.out.println(currency); //123456789 //2進を16進の0xのように、0bで表現可能 int bit = 0b10101; System.out.println(bit); //21
ジェネリクスまわり
型推論の進化
基本的には右辺を書いてからアシストで左辺を定義ってコーディングなのでちょっと困るような・・・・
List<String> l = new ArrayList<>(); l.add("test1"); l.add("test2"); for (String string : l) { System.out.println(string); }
JDBC4.1
さて・・・今まで見ないことにされていたRowSetだけど・・・
やはり今回も気にしない方向で、AutoCloseable対応位のつもりでいればいいかも?
http://download.java.net/jdk7/docs/technotes/guides/jdbc/jdbc_41.html
その他
後は細かいクラスやNIOやスレッドまわりは適宜。
switchでStringってのも記述に関しては新しくないので問題ないと思うので
きっとこのあたりだけ押さえておけばひとまずは困らないのかなぁ・・・なんて。