【问题标题】:Why is the generated name for a lambda class not the same for identical programs为什么相同程序的 lambda 类的生成名称不同
【发布时间】:2016-03-10 07:47:31
【问题描述】:

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

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:\Users\shell\Documents\workplace\bak\1

d:\Users\shell\Documents\workplace\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函数的个数不一样?

有什么办法可以使它们相同吗?

【问题讨论】:

  • 为什么lamba方法的名字对你很重要?请注意,它也是私有的,因此不应影响任何其他类。
  • fork=true 对我不起作用。
  • @Thilo 不能代表 OP,但具有确定性、一致的输出可以通过跳过某些部分来帮助加快大型复杂构建
  • @JB Nizet:private 方法的名称(无论是否确定)如何影响复杂构建的速度?这听起来像是软件项目模块化的一大失败。
  • @Holger 当后续任务需要复制文件或将它们 jar 然后复制到远程位置时,具有最终完全相同的类文件和 jar 文件允许构建过程跳过某些任务。例如,gradle 可以检测到任务的输入与之前的输入相同,并跳过该任务,以实现更快的增量构建

标签: maven lambda java-8


【解决方案1】:

查看 javac 源代码,您可能会注意到 the corresponding counter(附加到 lambda 方法名称)被定义为 LambdaAnalyzerPreprocessor 中的一个实例字段,可在整个编译过程中重复使用。它在每次出现 lambda 时递增。所以如果我只编译你的类,我的数字将从 0 开始:

> 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 = () -> {};
}

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

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

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

如果您确实需要稳定的编译结果,我可能建议您尝试 Eclipse Compiler for Java。好像没有这个问题:

>java -jar org.eclipse.jdt.core_3.11.1.v20150902-1521.jar -8 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 java.util.stream.Stream lambda$0(java.util.List);
  private static boolean lambda$1(java.util.Map, java.lang.Object);
  private static void lambda$2(java.lang.Object);
}

如何将ecj与maven集成参考this question

【讨论】:

    【解决方案2】:

    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 = () -> { };
    }
    

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

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

    【讨论】:

      猜你喜欢
      • 2015-07-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-11
      • 2013-12-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多