mike-neckのブログ

Java or Groovy or Swift or Golang

Java 8u60で、Mapの初期化とかがすごい楽になってる件

f:id:mike_neck:20150821023435p:plain

夜中に8/15頃のツイートが回ってきた。

曰く

Java8u60でラムダのパラメーターの名前に対してリフレクションができるようになってるよ


というわけで

早速、件のツイートにあったレポジトリーをダウンロードして(mavenレポジトリーにはない…(´・ω・`))、プロジェクトに追加して、試してみた。

コード

import com.benjiweber.typeref.NamedValue;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

import static java.util.Arrays.stream;

public final class HashLiteral {

    private HashLiteral() {}

    // めっちゃ感覚的にマップが構築できる!!!
    private static final Map<String, String> map = map(
            hello -> "world",
            john -> john,
            bill -> "not paid",
            うほっいいオトコ -> うほっいいオトコ
    );

    public static Optional<String> get(String key) {
        return Optional.ofNullable(map.get(key));
    }

    @SafeVarargs
    public static <T> Map<String, T> map(NamedValue<T>... kvPair) {
        Map<String, T> m = new HashMap<>();
        stream(kvPair)
                .forEach(kv -> m.put(kv.name(), kv.value()));
        return Collections.unmodifiableMap(m);
    }
}

テストコード

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;

import java.util.NoSuchElementException;
import java.util.Optional;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

public class HashLiteralTest {

    @Rule
    public TestName testName = new TestName();

    @Test
    public void hashLiteralTest() {
        Optional<String> opValue = HashLiteral.get("hello");
        opValue.ifPresent(v -> assertThat(v, is("world")));
        opValue.orElseThrow(NoSuchElementException::new);
    }

    @Test
    public void うほっいいオトコ() {
        Optional<String> opValue = HashLiteral.get(testName.getMethodName());
        opValue.ifPresent(v -> assertThat(v, is(testName.getMethodName())));
        opValue.orElseThrow(() -> new NoSuchElementException(testName.getMethodName()));
    }

    @Test(expected = NoSuchElementException.class)
    public void そんなキーはなかった() {
        HashLiteral.get(testName.getMethodName()).get();
    }
}

テストコードの方は、多少遊びが入っています(´・ω・`)

なお、IDEでテストを実行するときには多少注意が必要です。

f:id:mike_neck:20150821032525p:plain

この写真のように、Build, Execution, Deployment > Compiler > Java CompilerAdditional command line parameters-parametersを入れておかないと落ちます。

Caused by: java.lang.IllegalStateException: You need to compile with javac -parameters for parameter reflection to work; You also need java 8u60 or newer to use it with lambdas
    at com.benjiweber.typeref.NamedValue.checkParametersEnabled(NamedValue.java:13)
    at com.benjiweber.typeref.NamedValue.name(NamedValue.java:8)

Gradleでテスト…

compileJava {
    sourceCompatibility = jdkLevel
    targetCompatibility = jdkLevel
    options.encoding = encoding
    options.compilerArgs << '-parameters'
}

コンパイラーオプションに-parametersを渡しておいたんですけど…

$ gradle test
...
:test
Picked up _JAVA_OPTIONS: -Dfile.encoding=UTF-8

org.mikeneck.sample.HashLiteralTest > うほっいいオトコ FAILED
    java.lang.ExceptionInInitializerError at HashLiteralTest.java:42
        Caused by: java.lang.IllegalStateException at HashLiteralTest.java:42

org.mikeneck.sample.HashLiteralTest > そんなキーはなかった FAILED
    java.lang.Exception
        Caused by: java.lang.NoClassDefFoundError at HashLiteralTest.java:49

org.mikeneck.sample.HashLiteralTest > hashLiteralTest FAILED
    java.lang.NoClassDefFoundError at HashLiteralTest.java:35

3 tests completed, 3 failed
:test FAILED

...

BUILD FAILED

Total time: 4.028 secs
$

落ちた(´・ω・`)

なんでだろうorz


おわり???

後でGradle Forumで聞いてみます