【问题标题】:Loading properties and injecting to final variables - Java加载属性并注入最终变量 - Java
【发布时间】:2021-01-05 12:51:25
【问题描述】:

我想将属性值加载到常量类。我可以通过在类构造函数中注入值或静态初始化来实现,如下所示。

public class MyConstants {
    public final String CONSTANT;

    Myconstants() {
        //read property and set to this.CONSTANT
    }
}

以上初始化工作正常。但是当我必须在 switch case 语句中使用 CONSTANT 时,就会出现问题。它会给我错误,因为此时的 CONSTANT 不是恒定的,而是空白的最终字段。

有什么方法可以读取属性文件并将值设置为 CONSTANT 以便不存在编译错误? [就像在编译时加载属性和设置一样]。我正在使用 spring,对于这个用例是否有任何 Spring 或 java 解决方法。我的意图是不为每次构建一个不断的变化。另外,您将如何处理此用例?

谢谢

【问题讨论】:

  • 您提供导致某些错误的版本会有所帮助。
  • @MikheilZhghenti 我认为错误是java错误(所有版本都通用),说明常量应该在case语句中。我理解错误。但我想知道用例的其他方法。

标签: java spring spring-boot properties switch-statement


【解决方案1】:

switch 语句中的字符串是“硬编码”的。在编译时没有锁定“case”元素的 java 中创建 switch/case 语句实际上是不可能的。如果您想在应用程序初始化期间从属性文件加载这些字符串“常量”,它们不是常量。

或者至少,就 java 的基于字符串的 switch/case 的需求而言,不是恒定的

改为使用某种java.util.Map(将字符串值映射到runnables或其他不代表您现在放入case块中的内容)或一堆if/else-if语句。

编辑:如何使用地图来做到这一点。

@FunctionalInterface
public interface CommandProcessor {
    String apply(String cmd);
}

public class CommandHandler {
    private Map<String, CommandProcessor> processors = Map.of(
        "hello", cmd -> "Hello, " + cmd,
        "time", cmd -> "It is " + System.currentTimeMillis() + " past 1970.",
        "capitalize", String::toUpperCase);

    public static void main(String[] args) throws Exception {
        Scanner s = new Scanner(System.in);
        s.useDelimiter("\r?\n");
        CommandProcessor unknownCommand =
            cmd -> "Known commands: " + processors.keySet();

        while (true) {
            String line = s.next();
            String[] parts = line.split("\\s+", 2);
            var processor = processors.getOrDefault(parts[0], unknownCommand);
            String answer = processor.apply(parts.length > 1 ? parts[1] : "");
            System.out.println(answer);
        }
    }
}

【讨论】:

  • 我可以做if-else流程但是if else会有很多。我没看懂你提到的runnable方法。你能解释一下吗?
  • @sachin 我已经编辑了答案以包含一个示例。
  • 在您的示例中,映射键仍然是常量。很难想象键不是常量的用例……
【解决方案2】:

通常,属性文件由可在运行时加载的“key=value”对组成。可以类似地使用环境变量。通常,常量是键,值用于影响应用程序逻辑。只要不改变key,就可以根据需要改变属性值而无需重新编译,并且可以在switch语句中使用可能值的范围。例如:

    public static void main(String[] args)
    {
        AppConfigParam<Type1> type1   = new AppConfigParam<>("Param1", Type1::valueOf);
        AppConfigParam<Integer> type2 = new AppConfigParam<>("Param2", Integer::parseInt);
        switch(type1.value().orElseThrow(() -> new IllegalStateException("Missing type"))) { case A: break; }
        switch(type2.value().orElseThrow(() -> new IllegalStateException("Missing type"))) { case 1: break; }
    }

    public enum Type1{ A, B, C }

    private static final class AppConfigParam<T>
    {
        private final String constant;
        private final Function<? super String, T> resolver;
        AppConfigParam(String constant, Function<? super String, T> resolver){ this.constant = constant; this.resolver = resolver; }
        public Optional<T> value(){ return Optional.ofNullable(PARAMS.get(constant)).map(resolver); }
        private static final Map<String, String> PARAMS = System.getenv();
    }

虽然无法动态设置常量,但可以通过两阶段构建过程在 switch 语句中使用动态常量。

  1. 读取属性并生成常量类。
  2. 编译项目的其余部分。

【讨论】:

    猜你喜欢
    • 2011-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多