われプログラミングする、ゆえにバグあり

私だって価値を創造してみたいのです

メソッド参照とジェネリクスの可変長引数があやしい

間違いや補足など、指摘していただければありがたいです。

今回の環境

Product Version: NetBeans IDE 8.0 (Build 201403101706)
Java: 1.8.0_05; Java HotSpot(TM) 64-Bit Server VM 25.5-b02
Runtime: Java(TM) SE Runtime Environment 1.8.0_05-b13
System: Mac OS X version 10.9.2 running on x86_64; UTF-8; ja_JP (nb)

 

java8への期待は過剰だった気がしてきているきょうこのごろです。

メソッド参照とジェネリクスの可変長引数を組み合わせたソースコードで、ビルド時にエラーが出て困ることがありました。
そのメモです。

ビルドでエラーが出て困ったコード

IDEはNetBeans8(日本語)を使っていましたが、ソースコードの編集中はNetBeansは一切警告等をだしてくれませんでした。

public class ExSet<T> {

    Collector<T, ?, Collection<T>> collector = Collectors.toCollection(ExSet::getCollection);

    public static <T> Collection<T> getCollection(T... es) {
        return Arrays.asList(es);
    }
}

 

NetBeansのコンソールに表示されたエラーメッセージ

コンパイラで例外が発生しました(1.8.0_05)。Bug Paradeに同じバグが登録されていないことをご確認の上、Java Developer Connection(http://java.sun.com/webapps/bugreport)でバグの登録をお願いいたします。レポートには、そのプログラムと下記の診断内容を含めてください。ご協力ありがとうございます。
java.lang.AssertionError: arraycode T
at com.sun.tools.javac.jvm.Code.arraycode(Code.java:302)
at com.sun.tools.javac.jvm.Gen.makeNewArray(Gen.java:2028)
at com.sun.tools.javac.jvm.Gen.visitNewArray(Gen.java:2001)
at com.sun.tools.javac.tree.JCTree$JCNewArray.accept(JCTree.java:1556)
at com.sun.tools.javac.jvm.Gen.genExpr(Gen.java:947)
at com.sun.tools.javac.jvm.Gen.genArgs(Gen.java:966)
at com.sun.tools.javac.jvm.Gen.visitApply(Gen.java:1905)
at com.sun.tools.javac.tree.JCTree$JCMethodInvocation.accept(JCTree.java:1459)
at com.sun.tools.javac.jvm.Gen.genExpr(Gen.java:947)
at com.sun.tools.javac.jvm.Gen.visitReturn(Gen.java:1863)
at com.sun.tools.javac.tree.JCTree$JCReturn.accept(JCTree.java:1378)
at com.sun.tools.javac.jvm.Gen.genDef(Gen.java:737)
at com.sun.tools.javac.jvm.Gen.genStat(Gen.java:772)
at com.sun.tools.javac.jvm.Gen.genStat(Gen.java:758)
at com.sun.tools.javac.jvm.Gen.genStats(Gen.java:809)
at com.sun.tools.javac.jvm.Gen.visitBlock(Gen.java:1158)
at com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:903)
at com.sun.tools.javac.jvm.Gen.genDef(Gen.java:737)
at com.sun.tools.javac.jvm.Gen.genStat(Gen.java:772)
at com.sun.tools.javac.jvm.Gen.genMethod(Gen.java:1031)
at com.sun.tools.javac.jvm.Gen.visitMethodDef(Gen.java:994)
at com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:772)
at com.sun.tools.javac.jvm.Gen.genDef(Gen.java:737)
at com.sun.tools.javac.jvm.Gen.genClass(Gen.java:2526)
at com.sun.tools.javac.main.JavaCompiler.genCode(JavaCompiler.java:748)
at com.sun.tools.javac.main.JavaCompiler.generate(JavaCompiler.java:1570)
at com.sun.tools.javac.main.JavaCompiler.generate(JavaCompiler.java:1534)
at com.sun.tools.javac.main.JavaCompiler.compile2(JavaCompiler.java:904)
at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:863)
at com.sun.tools.javac.main.Main.compile(Main.java:523)
at com.sun.tools.javac.main.Main.compile(Main.java:381)
at com.sun.tools.javac.main.Main.compile(Main.java:370)
at com.sun.tools.javac.main.Main.compile(Main.java:361)
at com.sun.tools.javac.Main.compile(Main.java:56)
at sun.reflect.GeneratedMethodAccessor458.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.apache.tools.ant.taskdefs.compilers.Javac13.execute(Javac13.java:56)
at org.apache.tools.ant.taskdefs.Javac.compile(Javac.java:1153)
at org.apache.tools.ant.taskdefs.Javac.execute(Javac.java:930)
at org.netbeans.modules.java.source.ant.JavacTask.execute(JavacTask.java:145)
at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:292)
at sun.reflect.GeneratedMethodAccessor342.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
at org.apache.tools.ant.Task.perform(Task.java:348)
at org.apache.tools.ant.taskdefs.Sequential.execute(Sequential.java:68)
at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:292)
at sun.reflect.GeneratedMethodAccessor342.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
at org.apache.tools.ant.Task.perform(Task.java:348)
at org.apache.tools.ant.taskdefs.MacroInstance.execute(MacroInstance.java:396)
at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:292)
at sun.reflect.GeneratedMethodAccessor342.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
at org.apache.tools.ant.Task.perform(Task.java:348)
at org.apache.tools.ant.Target.execute(Target.java:435)
at org.apache.tools.ant.Target.performTasks(Target.java:456)
at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1393)
at org.apache.tools.ant.Project.executeTarget(Project.java:1364)
at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
at org.apache.tools.ant.Project.executeTargets(Project.java:1248)
at org.apache.tools.ant.module.bridge.impl.BridgeImpl.run(BridgeImpl.java:286)
at org.apache.tools.ant.module.run.TargetExecutor.run(TargetExecutor.java:555)
at org.netbeans.core.execution.RunClassThread.run(RunClassThread.java:153)

 
ググってみると、似たような情報がありました。Java 8 compiler error - how to get more information? - Stack Overflow
 

可変長引数を使っているあたりに原因がありそうなので、そのあたりのソースコードを書き換えて回避してみます。
 

回避策1

メソッド参照を諦める

Collector<T, ?, Collection<T>> collector = Collectors.toCollection(() -> {
    return ExSet.getCollection();
});

public static <T> Collection<T> getCollection(T... es) {
    return Arrays.asList(es);
}

これはシンタックスシュガーを無くしただけです。

 

回避策2

ジェネリクスを諦める

Collector<T, ?, Collection<T>> collector = Collectors.toCollection(() -> {
    return ExSet.getCollection();
});

public static <T> Collection<T> getCollection(Object... es) {
    // return Arrays.asList(es); // もちろん無理!!
    return Arrays.asList();
}

これではわけがわかりません。

 

回避策3

Collectors.toCollectionが引数にとるのはSupplierなので、引数なしでgetCollection()が呼ばれます。
なので、この場合は可変長引数はとらなくてもよいわけです。

Collector<T, ?, Collection<T>> collector = Collectors.toCollection(ExSet::getCollection);

public static <T> Collection<T> getCollection() {
    return Arrays.asList();
}

個人的には却下です。

 

まとめ

これと同じ事で困った人、いるのかなぁ…