ImmutableMap.Builder是否有限制?

问题描述

我有一堂课,看起来像这样:

public enum Animal {
   BEAR,SHEEP,LION;

   private static final Map<String,Animal> MAPPING = new ImmutableMap.Builder<String,Animal>()
      .put("BLACK_BEAR",BEAR)
      .put("WHITE_BEAR",BEAR)
      ...
      .put("African Lion",LION)
      .build()
}

大约1500个地图条目。

我尝试构建我的应用程序,但出现以下错误

    [javac] An annotation processor threw an uncaught exception.
    [javac] Consult the following stack trace for details.
    [javac] java.lang.StackOverflowError
    [javac]     at lombok.javac.JavacAST.buildTree(JavacAST.java:200)
    [javac]     at lombok.javac.JavacAST.buildTree(JavacAST.java:67)
    [javac]     at lombok.core.AST.buildWithField0(AST.java:386)
    [javac]     at lombok.core.AST.buildWithField(AST.java:284)
    [javac]     at lombok.javac.JavacAST.drill(JavacAST.java:374)
    [javac]     at lombok.javac.JavacAST.buildStatementOrExpression(JavacAST.java:340)
    [javac]     at lombok.javac.JavacAST.buildTree(JavacAST.java:200)
    [javac]     at lombok.javac.JavacAST.buildTree(JavacAST.java:67)
    [javac]     at lombok.core.AST.buildWithField0(AST.java:386)
    [javac]     at lombok.core.AST.buildWithField(AST.java:284)
    [javac]     at lombok.javac.JavacAST.drill(JavacAST.java:374)
    [javac]     at lombok.javac.JavacAST.buildStatementOrExpression(JavacAST.java:340)
    [javac]     at lombok.javac.JavacAST.buildTree(JavacAST.java:200)
    [javac]     at lombok.javac.JavacAST.buildTree(JavacAST.java:67)
    [javac]     at lombok.core.AST.buildWithField0(AST.java:386)
    [javac]     at lombok.core.AST.buildWithField(AST.java:284)
    [javac]     at lombok.javac.JavacAST.drill(JavacAST.java:374)
    [javac]     at lombok.javac.JavacAST.buildStatementOrExpression(JavacAST.java:340)
    [javac]     at lombok.javac.JavacAST.buildTree(JavacAST.java:200)
    [javac]     at lombok.javac.JavacAST.buildTree(JavacAST.java:67)
    [javac]     at lombok.core.AST.buildWithField0(AST.java:386)
    [javac]     at lombok.core.AST.buildWithField(AST.java:284)

我尝试将地图的尺寸​​减小到15ish,并且可以正常显示。我们可以编码静态不可变地图的大小是否有限制?我在文档中没有看到任何限制。问题可能是什么?

解决方法

它不是ImmutableBuilder;这是事实,因为您的源文件现在是一堆巨大的AST节点,以至于lombok的处理最终占用了太多内存,我想,鉴于javac可以处理它,从技术上讲,这在lombok中是一个错误。换句话说,编译器无法将您的Java文件转换为类文件,但是如果可以的话,它将可以正常工作*。

通常,我会将任何试图将源中的大量数据定义为代码气味的源文件视为

我建议您获取所有数据并将其放在文本文件中。

将此文本文件与源文件一起放置;如果您使用maven /或多或少的标准源目录结构,则必须说:

src/main/java/com/foo/yourpkg/Animal.java
src/main/resources/com/foo/yourpkg/AnimalData.txt

这将自动导致txt文件与类文件位于同一位置,即使是在jar中也是如此。然后,从您的动物文件中读取它:

public enum Animal {

    private static final Map<String,Animal> MAPPING;
    static {
        try {
            Map<String,String> example = new HashMap<String,String>();
            try (var in = Animal.class.getResourceAsStream("AnimalData.txt")) {
                BufferedReader br = new BufferedReader(new InputStreamReader(
                  in,StandardCharsets.UTF_8));

                for (String line = br.readLine(); line != null; line = br.readLine()) {
                    String[] p = line.split("\t",2);
                    map.put(p[0],p[1]);
                }
            }
            MAPPING = Collections.unmodifiableMap(map);
        } catch (IOException e) {
            throw new InternalError("data corrupted");
        }
    }
}

此假设示例要求您将制表符分隔的字符串对放入文本文件中。您可以使用此示例,并根据需要进行调整。

免责声明:我是lombok的核心贡献者,但是这比我想象的要低得多,在您遇到内存不足的问题之前,我们有很多错误报告需要深入研究。尝试在源代码中创建一个1500大小的不可变地图构建器。

*)可能;类文件也有限制,如果您删除lombok或添加内存,则编译器可能会在以后的阶段中仍然最终拒绝编译该代码,因为它会超出初始化的64k字节码限制。

,

我同意上面的@rzwitserloot,但是您可以尝试以下操作:

  1. 只需在运行构建的jvm中添加-Xss4m(或更高版本)来增加堆栈大小。
  2. edit 由于枚举本身很小,您可以这样做:
package org.example;

import java.util.HashMap;
import java.util.Map;

public enum Animal {
    BEAR("white bear","black bear","brown bear"),DOG("mongrel","cross"),CAT("blah3");

    private final String[] blah1;

    private static final Map<String,Animal> MAPPING = new HashMap<>();

    static {
        for (Animal animal: Animal.values()) {
            for (String tag : animal.blah1) {
                MAPPING.put(tag,animal);
            }
        }
    }

    Animal(String... blah1) {
        this.blah1 = blah1;
    }


    public static void main(String... s) {
        String animal = "black bear";
        System.out.println(" A " + animal + " is a " + MAPPING.get(animal));
    }
}