【问题标题】:How to Load Values for Java Enum Elements from A File如何从文件中加载 Java 枚举元素的值
【发布时间】:2014-02-02 07:44:15
【问题描述】:

我有一个 Java 枚举:

public enum CodeType {
  BRONZE("00001BP", "BAP"),
  SILVER("00002SL", "SAP"),
  GOLD("00003GL", "GAP"),
  MOBILE("00004MB", "TCM"),
  SOCIAL("00005SM", "ASM"),
  WEB_PRESENCE("00006WP", "GLO"),
  EMAIL_MARKETING("00007EM", "PEM"),
  CUSTOM_DIAMOND("00008CD", "PCS"),
  CONSUMER_PORTAL("00009CP", "CPS");

  private String code;
  private String key;

  CodeType(String code, String key) {
    this.code = code;
    this.key = key;
  }

  ...
}

如您所见,我有九个元素,每个元素都有两个值。我的问题是如何从属性或 xml 等文件中加载这些元素的值?我的意思是:

BRONZE(isLoadedFromFile, isLoadedFromFile),
...
CONSUMER_PORTAL(isLoadedFromFile, isLoadedFromFile);

非常感谢。

【问题讨论】:

  • 枚举是一组常量。动态创建它没有多大意义。它可以通过一些反射黑客来完成,但我 99% 确信最好进行重新设计。
  • 简而言之:你不能。枚举应该是静态的。如果您需要动态的东西,请使用例如java.util.Properties.
  • 感谢您的回答,我知道这是不可能的。
  • @Hoang Nguyen huu 只需检查我发布的答案,它可能会对您有所帮助..

标签: java xml properties enums


【解决方案1】:

一种选择是根据枚举类中的资源文件生成静态映射,将枚举值映射到文件中的数据。然后可以将地图用于 getter。

例如,格式如下的资源文件:

A=red
B=blue
C=yellow

可以这样初始化:

public enum MyEnum {
    A, B, C;
    
    public String getFoo() {
        return enumFooValuesFromResourceFile.get(this);
    }

    private static final Map<MyEnum, String> enumFooValuesFromResourceFile;
    static {
        Map<MyEnum, String> temp = Collections.emptyMap();
        try {
            String data = new String(MyEnum.class.getResourceAsStream("resourcepath").readAllBytes());
            temp = Arrays.stream(data.split("\n"))
                    .map(line -> line.split("="))
                    .collect(Collectors.<String[], MyEnum, String>toMap(
                            key_val -> MyEnum.valueOf(key_val[0]),
                            key_val -> key_val[1]));
        } catch (IOException iE) {
            // helpful message.
        } finally { enumFooValuesFromResourceFile = temp; }
    }
}

我认为,一个更好的选择是对资源文件数据使用静态字符串,并在初始化期间将值直接存储在枚举项上。在枚举初始化期间,您无法访问枚举的静态属性,因此它必须在枚举之外,或者在使用整洁的Initialization-on-demand holder idiom (credit to) 的内部类中,因为它是如果从未访问过枚举,则惰性且不加载。

(我发现我可以在枚举声明的末尾将(非最终)字符串设置为 null,从而释放内存。)

public enum MyEnum {
    A, B, C;

    public String getFoo() { return foo; }

    final String foo;

    MyEnum() {
        foo = getFooValue();
    }

    private String getFooValue() {
        return Arrays.stream(ResourceHolder.resourceFileString.split("\n"))
                .filter(str -> str.startsWith(this.name() + '='))
                .findFirst()
                .map(str -> str.replaceAll("^" + this.name() + '=', ""))
                .orElseThrow(() ->
                        new IllegalArgumentException(this.name() + " not found in resourcefile."));
    }
    // Release resources (string) from memory after enum initialization.
    static {ResourceHolder.resourceFileString = null;}

    private static class ResourceHolder {
        // Lazily initialized if/when MyEnum is accessed.
        // Cleared after initialization.
        private static String resourceFileString;
        static {
            try {
                InputStream lResource =
                        Objects.requireNonNull(MyEnum.class.getResourceAsStream("resourcepath"));
                resourceFileString = new String(lResource.readAllBytes());
            } catch (IOException iE) {
                // helpful message.
                iE.printStackTrace();
            }
        }

    }

}

【讨论】:

    【解决方案2】:

    试试这样的..

    public enum EnumTest {
    
        BRONZE, SILVER;
    
        public String getProperty(String keyOrCode) {
            Properties prop = new Properties();
            try {
                prop.load(new FileInputStream("E:\\EnumMapper.properties"));
            } catch (Exception e) {
                e.printStackTrace();
            }
            return prop.getProperty(this.name() + "." + keyOrCode);
        }
    
        public String getCode() {
            return getProperty("CODE");
        }
    
        public String getKey() {
            return getProperty("KEY");
        }
    
        public static void main(String[] args) {
            System.out.println(EnumTest.BRONZE.getCode());
            System.out.println(EnumTest.BRONZE.getKey());
    
        }
    
    }
    

    EnumMapper.properties 包含的位置

    BRONZE.CODE=00001BP
    BRONZE.KEY=BAP
    SILVER.CODE=00002SL
    SILVER.KEY=SAP
    

    只是想分享一些可能性..

    【讨论】:

    • 非常感谢@Sinto K Itteera,这是一个有趣的解决方案,我讨厌我没有足够的权限来投票支持这个有用的答案。
    • @Hoang Nguyen huu 很高兴看到它对你有帮助:)
    【解决方案3】:

    如果我正确理解您的问题,您需要在构造函数中这样做(在您的示例中命名错误)。

    您显示的硬编码默认值将用作默认值,但在构造函数中您将检查/加载一些属性文件并覆盖它们。

    不过,总的来说,这闻起来有点奇怪/糟糕的设计。您需要在枚举中对该属性文件/资源​​进行硬编码。您还动态加载了表示常量值的内容。

    看来您真的应该使用自己的类来保存这些值。

    【讨论】:

    • 嗨@Brian Roach 我知道这是一个糟糕的设计,但这是我可以选择的最佳方式,因此我不必对代码进行大的更改。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-19
    相关资源
    最近更新 更多