Java8の新機能に関するメモ

  • 108
    Like
  • 0
    Comment
More than 1 year has passed since last update.

はじめに

ベースはこの辺の情報です。
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/


インターフェースの仕様変更

Iterable#forEach
    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));

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);
}); 

http://qiita.com/kamatama_41/items/82fb16a1f81c2996c12c

パフォーマンス

Java7とJava8を同一構成で比較して12から41パーセント性能が向上しているという結果も。
http://japanmediacentre.oracle.com/content/detail.aspx?ReleaseID=3195&NewsAreaId=2

Webフレームワーク

Spring

Play

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は素晴らしい構文の魔法で他のメジャーな関数型プログラミング機能をもつ言語と同等、かつシームレスな後方互換性を手に入れることに成功した、的なことが書いてある(と思う)