JavaOne2010 9/20 -- Java SE: The Road Ahead

JavaOneも先週終わってもう一週間経とうとしている今日この頃、今更感が超濃厚ですが、セッション内容をまとめざるを得ない事情が色々とあり、せっかく書くならということでここにも晒しておきます。変なところがあったら突っ込んで下さい。


 ***


Java SE 7はどうなるのか?という超注目のセッションです。
ただ、どうやら以前よりウォッチしてる人からみると、特に新しいことはなかったようです。
JavaOne期間中に、Java7とJava8のリリースがどうなるか、という予定が決まったくらい?


さて、内容ですが、Java7,8,9...のつまり次世代Javaのテーマは、以下の6つだそうです。

  • Productivity
  • Performance
  • Universality
  • Modularity
  • Integration
  • Serviceability

テーマごとに新しい仕様/機能が紹介されていきましたが、いろんなところでまとめられてると思うので、ここでもつまみ食い程度に紹介しておきます。

Project Coin

開発効率を改善をする小粒で便利な機能改善/追加仕様を寄せ集めたプロジェクトです。

  • Diamond

Genericsのインスタンスをnewするところで

  Map<String, Map<String, List<Employee>>> map = new  Map<String, Map<String, List<Employee>>>();

と同じようなGenericsの型情報を書かなければならなかったのが、

  Map<String, Map<String, List<Employee>>> map = new  Map<>();

で済むようになります。
<>の形が菱形というかダイアモンドに似てるのでこの仕様はDiamondと呼ばれてます。

  • Try-with-resources

従来のtryが拡張されて、tryスコープでのみ有効なリソースの変数を宣言できるようになりました。
http://www.baptiste-wicht.com/2010/08/java-7-try-with-resources-statement/ から借りたサンプルコードで示すと、↓こんな感じ。

try (InputStream fis = new FileInputStream(source);
     OutputStream fos = new FileOutputStream(target)){
    byte[] buf = new byte[8192];
    int i;
    while ((i = fis.read(buf)) != -1) {
        fos.write(buf, 0, i);
    }
} catch (Exception e) {
    e.printStackTrace();
}

fisもfosもtryスコープを抜けると自動的にcloseされます。
tryの括弧内に書けるリソースは、java.lang.AutoCloseableを実装したオブジェクトの変数宣言でなければなりません。

  • Improved integral literals
  • Strings in switch

従来のswitch文では条件にintしか使えませんでしたが、Stringが使えるようになります。
ちょっと前進ですね。
ちなみにGroovyではどんなオブジェクトでも普通に使えます。

  • Varargs warnings
  • Multi-catch & precise rethrow

Fork/Join Framework

マルチコアを十分に生かすためにコレクションに並行処理関連APIが追加されたりします。
たとえば以下のようなコードが書けるようになります。

Collection<String> names = ....
names.filter(new Predicate<String>() {
    public boolean accept(String name) {
        return name != null && name.matches("[a-z]*"); // 小文字だけで構成された名前のみ抽出
    }
}).map(new Extractor<String, String>() {
    public String get(String name) {
        return name.toUpperCase(); // 大文字に変換して出力する
    }
});
9/30追記

id:skrbさんにツッコミをいただいたので訂正します!

http://www.infoq.com/news/2008/03/fork_join
↑によると、ホントのFork/Joinのサンプルコードは

ParallelArray students = new ParallelArray(fjPool, data);
double bestGpa = students.withFilter(isSenior)
                         .withMapping(selectGpa)
                         .max();

という感じですね。

僕が書いた例は、JDK7でコレクションクラスに新たに内部イテレータ*1的なAPIを用意することで、要素をぐるぐるまわすのがいい感じになるよー、さらにはクロージャ記法によってもっと簡単に書けるよ!、という話であって、並行に処理されるわけではないですね。はい、その通りです。

(内部イテレータと記法に似てはいるけども)Fork/Joinフレームワークを使うと、並行でいい感じに高速実行してくれる、という点で全然別物ですね。

Groovyな人は、Groovyのlist.findAll()と、GParsのlist.findAllParallel()の違いと考えればわかりやすいですね。

腑に落ちました。ありがとうございます!>id:skrb

9/30追記(2)

id:skrbさんから再びコメントいただきました!今度はTwitter

@nobeans Fork/Join FWはJSR166yなのですが、ParallelArrayはextraJSR166yに含まれていて、JSR166yには含まれないんです。RecursiveTaskのJavadocの例がよく使われています。 http://download.java.net/jdk7/docs/api/java/util/concurrent/RecursiveTask.html

http://twitter.com/skrb/status/25960231321

なるほど、ParallelArrayはFork/Joinの例としては不適切だったわけですね。失礼しました。
教えていただいたURLのRecursiveTaskのサンプルコードは↓になります。

 class Fibonacci extends RecursiveTask<Integer> {
   final int n;
   Fibonacci(int n) { this.n = n; }
   Integer compute() {
     if (n <= 1)
        return n;
     Fibonacci f1 = new Fibonacci(n - 1);
     f1.fork();
     Fibonacci f2 = new Fibonacci(n - 2);
     return f2.compute() + f1.join();
   }
 }

えーと、内部イテレータ的な表記とはだいぶ違うので、話の流れがぶったぎられてる風に見えますが、気にしない気にしない。

ともあれ、これがFork/Join Framework(JSR166y)の真のサンプルコードなのです!*2

Project Lambda

噂のクロージャの導入です。
クロージャといっても、SAM方式のちょっとしたシンタックスシュガー的なものに落ち着いたようです。

単品セッションにも参加したので、ここでは簡単にキーワードだけを述べておきます。

  • Lambda expression
  • Default methods for interface evolution
  • SAM convention with target typing
  • Method references
  • Library enhancements for internal iteration

前述の並行処理のサンプルコードは、クロージャの導入によって以下のように簡潔に書けるようになります。

Collection<String> names = ....
names.filter(#{ name ->
    name != null && name.matches("[a-z]*"); // 小文字だけで構成された名前のみ抽出
}).map(#{ name ->
    name.toUpperCase(); // 大文字に変換して出力する
});

今のところの最新仕様では、 #{ 仮引数 -> 処理 } と書くようです。#が付く以外はGroovyと同じですね。

ちなみにGroovyなら現状の1.7.xにおいても、↓と書けます。

Collection<String> names = ....
names.filter { name ->
    name != null && name.matches("[a-z]*"); // 小文字だけで構成された名前のみ抽出
}.map { name ->
    name.toUpperCase(); // 大文字に変換して出力する
}

Project Jigsaw

Jar地獄から脱出するためのノアの箱船となるかProject Jigsaw。
OSGiを採用すると言ったりやめたり言ったりやめたりと忙しい感じだったようですが、結局はOSGiとは全くの別物に仕上がったようです。

これも単品セッションに参加したので、詳しくは別途整理します。

簡単に書くと、Maven/IvyのようにJarをモジュールとして管理するもので、module-info.javaに見慣れない記法で色々書けば、もうクラスパスで悩む必要はなくなるよ!というもの。
Classpath=Legacyとなる時代は果たしてくるのでしょうかね。

Value Class/Properties

これ結構びっくりしたんですけど、新しい予約語のvalue, propertyを使って、

value class Node {
    property Node parent;
    property Node lefChild;
    property Node rightChild;
}

とか書くと、getter/setterを自動生成してくれたりするそうです。
今更感があるなぁ。

ちなみにGroovyでは、

class Node {
    Node parent
    Node lefChild
    Node rightChild
}

でgetter/setterを自動生成してくれますね。

リリース予定日

JavaOne前にプランAだとかBだとかいくつかの案がでてましたが、結局JigsawとLamdaとCoinのいくつかをのぞいたものがJava7として2011年央にリリースされて、残りはJava8として2012年末までにリリース予定ということです。


こんなところで。

*1:"内部"ですよね?

*2:であることを祈る