为什么对于相同的程序,lambda类的生成名称不相同

时间:2016-03-10 07:47:31

标签: maven lambda java-8

源代码(当然项目还有很多其他类)

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Stream;


public class Test {
    public static void main(String[] args) {
        Map<Integer, Integer> src = new HashMap<>();
        Map<Integer, List<Integer>> dst = new HashMap<>();
        Optional<Object> f = dst.values().stream().flatMap((Function<List<Integer>, Stream<?>>) integers -> integers.stream()).filter(b -> !src.containsKey(b)).findFirst();
        f.ifPresent(b -> {
            throw new IllegalStateException("exception [" + b + "]");
        });
    }
}

1.将项目复制到不同的路径

d:\用户\壳\文件\工作场所\ BAK \ 1

d:\用户\壳\文件\工作场所\ BAK \ 2

2.在两个路径中执行mvn包

3.检查类文件

d:\ Users \ shell \ Documents \ workplace \ bak \ 1 \ data \ target \ classes

执行命令javap -p
public class Test {
    public Test();
    public static void main(java.lang.String[]);
    private static void lambda$main$84(java.lang.Object);
    private static boolean lambda$main$83(java.util.Map, java.lang.Object);
    private static java.util.stream.Stream lambda$main$82(java.util.List);
}

d:\ Users \ shell \ Documents \ workplace \ bak \ 2 \ data \ target \ classes

执行命令javap -p
public class Test {
    public Test();
    public static void main(java.lang.String[]);
    private static void lambda$main$75(java.lang.Object);
    private static boolean lambda$main$74(java.util.Map, java.lang.Object);
    private static java.util.stream.Stream lambda$main$73(java.util.List);
}

为什么lambda函数的数量不同?

有什么方法可以让它们变得相同吗?

2 个答案:

答案 0 :(得分:13)

查看javac源代码,您可能会注意到the corresponding counter(附加到lambda方法名称)被定义为$ grep -w -f f1 f2 2015-10-30,1234,zxcfgdk,kyfz 2015-10-30,2567,askjfkj,aaaa $ grep -v -w -f f1 f2 2015-10-30,8888,bsjfjah,iojk 中的一个实例字段,该字段在整个编译过程中被重用。它会在每次lambda事件中递增。所以如果我只编译你的类,我会从0开始编号:

LambdaAnalyzerPreprocessor

但是,如果我再创建一个类

> javac Test.java
> javap -p Test
Compiled from "Test.java"
public class Test {
  public Test();
  public static void main(java.lang.String[]);
  private static void lambda$main$2(java.lang.Object);
  private static boolean lambda$main$1(java.util.Map, java.lang.Object);
  private static java.util.stream.Stream lambda$main$0(java.util.List);
}

将它们编译在一起我会看到计数器递增:

public class Test2 { 
    Runnable r = () -> {};
}

所以这不是maven问题,这就是javac编译器的工作原理。

如果您肯定需要稳定的编译结果,我建议您尝试使用Eclipse Compiler for Java。似乎没有这样的问题:

> javac Test2.java Test.java 
> javap -p Test
Compiled from "Test.java"
public class Test {
  public Test();
  public static void main(java.lang.String[]);
  private static void lambda$main$3(java.lang.Object);
  private static boolean lambda$main$2(java.util.Map, java.lang.Object);
  private static java.util.stream.Stream lambda$main$1(java.util.List);
}

关于如何将ecj与maven集成,请参阅this question

答案 1 :(得分:0)

FWIW,这曾经是由 OpenJDK 中的错误引起的。已于 2016 年 12 月修复:https://bugs.openjdk.java.net/browse/JDK-8067422

<块引用>

目前,当生成 lambda 名称(对于不可序列化的 lambda)时,确切的名称取决于当前 javac 实例到目前为止生成的(不可序列化的)lamdbas 的数量。原因是 lambda 名称的计数器不是每个文件,而是每个 javac 实例。例如,考虑:

public class L1 {
   private Runnable r = () -> { };
}

public class L2 {
    private Runnable r = () -> { };
}

doing: javac L1.java L2.java 将使 L1 的 lambda 使用 lambda$new$0 和 L2 的 lambda$new$1,而:javac L2.java L1.java 将导致相反的名称分配。

问题似乎很简单:LambdaToMethod.LambdaAnalyzerPreprocessor.lambdaCount 在开始新的顶级之前没有重置。