はじめに
ベースはこの辺の情報です。
http://www.techempower.com/blog/2013/03/26/everything-about-java-8/
http://www.infoq.com/jp/news/2013/09/everything-about-java-8
http://yoshio3.com/2014/03/21/congrats-javase8-launch/
インターフェースの仕様変更
- デフォルトメソッドが定義できるようになった
- mixin(RubyでいうModuleみたいなの)が可能に
- http://equj65.net/tech/java8mixin/
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
- staticメソッドが定義できるようになった
ラムダ式
概要
Java7までは関数をオブジェクトとして渡せなかったので、関数型っぽい書き方をしたい場合は関数をインターフェースとして定義し無名クラスのインスタンスを生成する必要があった。
Collections.sort(students, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return Integer.compare(o1.getHeight(), o2.getHeight());
}
});
Java8からはラムダ式を利用することで以下のように書く事が出来る
Collections.sort(students, (o1, o2) -> Integer.compare(o1.getHeight(), o2.getHeight()));
ラムダ式の定義方法
// 基本の書き方: (引数) -> { (処理) }
(int x, int y) -> {
return x + y;
};
// 引数の型は省略可能
(x, y) -> {
return x + y;
};
// さらに1行処理の場合は{}とreturnも省略可能
(x, y) -> x + y;
// 引数が一つの場合は()が省略可能
name -> "Hello " + name;
ラムダ式を変数に代入する
ラムダ式を変数に代入するためには、_関数型インターフェース_を作成する必要がある
関数型インターフェースとは?
メソッドが一つしか無いインターフェースのこと。
ただし、Objectのメソッド(equalsとかtoStringとか)、Java8からinterfaceに導入されているstaticメソッドやdefaultメソッドは無視されるのであっても良い
/**
* 数値の計算処理を行う
*/
public interface Operator {
public int apply(int x, int y);
}
Operator plus = (x, y) -> x + y;
Operator minus = (x, y) -> x - y;
Operator multiply = (x, y) -> x * y;
Operator divide = (x, y) -> x / y;
@FunctionalInterface
@FunctionalInterfaceをインターフェースに付けるとコンパイル時に関数型インターフェースの条件を満たすかどうかをチェックしてコンパイルエラーにしてくれる(無くても関数型インターフェースとして利用する事はできる)。関数型の利用を想定しているインターフェースはこのアノテーションを付けるのが良い。
標準APIで用意されている関数型インターフェース
- Function - Tを入力として取り,Rを出力として返す
- Predicate - Tを入力として取り,論理型(boolean)を出力として返す
- Consumer - Tを入力として取り,何も返さない
- Supplier - 入力を取らず,Tを返す
- BinaryOperator - 2つのTを入力として取り,1つのTを出力として返す
その他にもあります、詳しくは以下を参照
http://www.ne.jp/asahi/hishidama/home/tech/java/functionalinterface.html#h_API
メソッド参照
既存のメソッドを(::)で呼び出すことでラムダ式化が出来る。
既存のメソッドをラムダ式にするための簡略形。
List<String> list = Arrays.asList("a", "b", "c", "d");
list.forEach(System.out::println);
//list.forEach((str) -> {
// System.out.println(str);
//});
Stream
概要
集合体を表すインターフェースで、集合に対する処理を簡潔に記述する事が可能になった
// Java7
int sum = 0;
for (int i = 1; i < 101; i++) {
sum += i;
}
// Java8
int sum = IntStream.range(1, 101).sum();
もうちょい複雑な処理(Mapreduce)だとこんな感じ
Path path = FileSystems.getDefault().getPath("./src/main/java/wordcount.txt");
Files.lines(path)
// Map
.flatMap(line -> Arrays.stream(line.split("( |\\.|,)+")))
// Reduce
.collect(Collectors.groupingBy(word -> word, Collectors.counting()))
// Output
.forEach((k, v) -> System.out.println(k + ":" + v));
- http://qiita.com/tfunato/items/a5744cec202af64573a5 を参考
- Java7までだとファイルを読んで1行ごとに分割してfor文で回して結果をMapに詰めて・・・
- Java6までだとリソースのクローズ処理も必要・・・
streamの並列実行
マルチスレッドでストリームを処理する場合はStream#parallelsを呼ぶだけでOK
基本的にストリーム処理は隠蔽されてるので、Javaのバージョンアップをするだけでパフォーマンス改善する可能性がある。
Path path = FileSystems.getDefault().getPath("./src/main/java/wordcount.txt");
Files.lines(path)
// Map
.flatMap(line -> Arrays.stream(line.split("( |\\.|,)+")))
// Concurrent
.parallel()
// Reduce
.collect(Collectors.groupingBy(word -> word, Collectors.counting()))
// Output
.forEach((k, v) -> System.out.println(k + ":" + v));
日付API
使いづらいのは相変わらずだけど高機能にはなっているらしい・・・
http://d.hatena.ne.jp/nowokay/20130917
Nashorn JavaScript エンジン
https://blogs.oracle.com/wlc/entry/javaee_c117
http://orablogs-jp.blogspot.jp/2014/03/oracle-nashorn-next-generation.html
元々JavaにはJavaScript実行エンジン(Rhino)があったが、invokeDynamicなどを使ってパフォーマンスが向上したエンジン(Nashorn)に置き換わった。
- ECMAScript-262 Edition 5.1準拠
- ナスホーンと読むらしい
JavaでJavaScriptを呼び出す
ScriptEngineManager engineManager = new ScriptEngineManager();
ScriptEngine engine =
engineManager.getEngineByName("nashorn");
engine.eval("function sum(a, b) { return a + b; }");
System.out.println(engine.eval("sum(1, 2);"));
JavaScriptからJavaを呼び出す
var list = java.util.Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
var odd = list.stream().filter(function(i) {
return i % 2 == 0;
});
odd.forEach(function(i) {
print(">>> " + i);
});
パフォーマンス
Java7とJava8を同一構成で比較して12から41パーセント性能が向上しているという結果も。
http://japanmediacentre.oracle.com/content/detail.aspx?ReleaseID=3195&NewsAreaId=2
Webフレームワーク
Spring
- Spring4.0からJava8対応
- http://d.hatena.ne.jp/tatsu-no-toshigo/20140116/1389886428
Play
- Play2.3から対応
- http://www.infoq.com/jp/news/2014/06/play-23
Spark
- 今はやりの軽量フレームワーク、RubyのSinatraインスパイアらしい
- spark2.0.0からラムダ式が使える
- http://www.sparkjava.com/
ThoughtWorksに認められたJava8
ThoughtWorks Technology RadarでJava8がいきなりAdaptになりました。(2014 July)
http://www.thoughtworks.com/radar/languages-and-frameworks/java-8
The team behind Java 8 had to fight two battles: the community forces encouraging forever backwards compatibility (a long hallmark of Java) and the technical challenge of making a deep language change mesh with existing libraries and features. They succeeded on both fronts, breathing new life into the Java Language and placing it on par with other mainstream languages in terms of functional programming features. In particular, Java 8 has excellent syntactic magic that allows seamless interoperability between Lambda blocks, the new higher-order function feature, and SAM (Single Abstract Method) interfaces, the traditional way of passing behavior.
Java8は素晴らしい構文の魔法で他のメジャーな関数型プログラミング機能をもつ言語と同等、かつシームレスな後方互換性を手に入れることに成功した、的なことが書いてある(と思う)