Java 8:重复的方法名称和签名 lambda

问题描述 投票:0回答:2

我正在研究 Java 8 lambda、方法引用和接口默认方法来探索柯里化的奇妙世界,然后我得到了这个我无法理解的 Java 错误。

这是代码:

public class Main {

    public interface CurryBiConsumer<T, U> extends BiConsumer<T, U> {
        default public CurryConsumer<U> curryFirst(T t) {
            return (u) -> accept(t, u);
        }
        default public CurryConsumer<T> currySecond(U u) {
            return (t) -> accept(t, u);
        }
    }

    public interface CurryConsumer<T> extends Consumer<T> {
        default public Runnable curry(T t) {
            return () -> accept(t);
        }
    }

    static void execute(Runnable r) {
        System.out.println("BEFORE");
        r.run();
        System.out.println("AFTER");
    }

    static void display(String str, int count) {
        System.out.println("DISP: " + str + " " + count);
    }

    public static void main(String[] args) {
        CurryBiConsumer<String, Integer> bc = Main::display;

        execute(bc.curryFirst("Salomon").curry(42));
    }
}

Eclipse 没有给我任何错误,但是当我运行它时,我收到此运行时错误:

Exception in thread "main" java.lang.BootstrapMethodError: call site initialization exception
    at java.lang.invoke.CallSite.makeSite(CallSite.java:328)
    at java.lang.invoke.MethodHandleNatives.linkCallSite(MethodHandleNatives.java:296)
    at com.test8.Main.main(Main.java:34)
Caused by: java.lang.ClassFormatError: Duplicate method name&signature in class file com/test8/Main$$Lambda$1
    at sun.misc.Unsafe.defineAnonymousClass(Native Method)
    at java.lang.invoke.InnerClassLambdaMetafactory.spinInnerClass(InnerClassLambdaMetafactory.java:324)
    at java.lang.invoke.InnerClassLambdaMetafactory.buildCallSite(InnerClassLambdaMetafactory.java:194)
    at java.lang.invoke.LambdaMetafactory.altMetafactory(LambdaMetafactory.java:473)
    at java.lang.invoke.CallSite.makeSite(CallSite.java:301)
    ... 2 more

有人可以解释一下这个错误是什么,为什么会发生以及如何解决它?

谢谢:)

java java-8
2个回答
13
投票

设置系统属性

jdk.internal.lambda.dumpProxyClasses
以指向文件系统上的目录。您将获得转储到该位置的合成匿名类
com/test8/Main$$Lambda$1
的字节码。使用
javap
打开该类文件以查看发生了什么。您应该在那里找到同一方法的两个声明。

更新

这是使用 Eclipse 编译时上述过程产生的

javap
输出:

最终类 test.Main$$Lambda$1 实现 test.Main$CurryBiConsumer {
  公共无效接受(java.lang.Object,java.lang.Object);
    代码:
       0:aload_1
       1: checkcast #14 // 类 java/lang/String
       4:aload_2
       5: checkcast #16 // 类 java/lang/Integer
       8: invokestatic #22 // 方法 test/Main.lambda$0:(Ljava/lang/String;Ljava/lang/Integer;)V
      11:返回

  公共无效接受(java.lang.Object,java.lang.Object);
    代码:
       0:aload_1
       1: checkcast #14 // 类 java/lang/String
       4:aload_2
       5: checkcast #16 // 类 java/lang/Integer
       8: invokestatic #22 // 方法 test/Main.lambda$0:(Ljava/lang/String;Ljava/lang/Integer;)V
      11:返回
}

这就是它应该的样子,以及

javac
的作用:

最终类 test.Main$$Lambda$1 实现 test.Main$CurryBiConsumer {
  公共无效接受(java.lang.Object,java.lang.Object);
    代码:
       0:aload_1
       1: checkcast #14 // 类 java/lang/String
       4:aload_2
       5: checkcast #16 // 类 java/lang/Integer
       8: invokevirtual #20 // 方法 java/lang/Integer.intValue:()I
      11: invokestatic #26 // 方法 test/Main.display:(Ljava/lang/String;I)V
      14:返回
}

结论:这是 Eclipse JDT 编译器的问题。应该有人举报:)

更新

自 Eclipse Luna 起,此错误已得到修复。


0
投票

就我而言,更改 eclipse 中安装的 JRE 运行时解决了问题

© www.soinside.com 2019 - 2024. All rights reserved.