【问题标题】:How to ensure that a switch/case statement has all the options like using enum?如何确保 switch/case 语句具有使用枚举等所有选项?
【发布时间】:2019-03-14 12:20:12
【问题描述】:

我想在 Java 中创建一个 switch/case 语句,并确保所有字符串都在语句中。

但是,在 Java 中使用简单的字符串(即 NORTH、SOUTH、EAST、WEST)很容易创建枚举。

如何处理带有点和空格的字符串?即“这是描述”,“com.stackoverflow.ClassName”

【问题讨论】:

  • 恐怕你的问题不清楚。 “确保所有字符串都在语句中”是什么意思。那些字符串是什么?
  • 通过将它们添加到您的案例列表中
  • Java 编译器不知道“NORTH”是一组基本方向的一部分。会怎么样?
  • 通过使用枚举。他们正在做你所要求的。
  • @kumesana 警告,是的,毫无疑问,像声纳这样的库也会接受它。不幸的是,这并不能保证所有案件都得到处理,它只会通知您有些案件没有处理。至于默认值:就个人而言,我在打开枚举时会尽量避免它。毕竟:如果我希望他们被同等对待,我不需要不同的价值观。这里的危险是一切都确实被处理了。但是如果你在某个地方错过了一个 switch(myEnum) 来适应,如果默认处理与你需要的不同,它会给出错误的结果。

标签: java enums switch-statement


【解决方案1】:

我认为这个问题的主要问题是,您的 IDE 告诉您在 switch 语句中缺少枚举值。并询问您是否要添加它们而不是您的编译器。这当然不能确保您的枚举类的用户必须使用每个值。

Joshua Bloch 在他的 Effective Java 书(第 Emulated extensible enum using an interface 章中提到了一种方法,可以将其更改为使用此处显示的开关:Java Enum Switch。但我认为开关解决方案并不能提供完全的安全性使用所有枚举。

但既然您想知道是否有使用字符串的解决方案,我们也可以尝试使用如下所示的函数式方法:Enum Switch Functional Approach 并使其使用字符串字段而不是枚举。

这可能如下所示:

public class Direction {
    private static final String NORTH = "north";
    private static final String SOUTH = "south";
    private static final String EAST = "east";
    private static final String WEST = "west";

    public interface SwitchResult {
        void NORTH();
        void SOUTH();
        void EAST();
        void WEST();
    }

    public static void switchValue(String direction, SwitchResult result){
        switch (direction){
            case NORTH:
                result.NORTH();
                break;
            case SOUTH:
                result.SOUTH();
                break;
            case EAST:
                result.EAST();
                break;
            case WEST:
                result.WEST();
                break;
        }
    }

    public static void main(String[] args) {
        String direction = "west";
        Direction.switchValue(direction, new SwitchResult() {
            @Override public void NORTH() {
                System.out.println("this time north");
            }

            @Override public void SOUTH() {
                System.out.println("this time south");
            }

            @Override public void EAST() {
                System.out.println("this time east");
            }

            @Override public void WEST() {
                System.out.println("this time west");
            }
        });
    }
}

正如您在 main 方法中看到的,如果您想调用 switchValue 函数,您必须传递您的字符串和接口的实现,这样可以确保您覆盖所有可能性。作为交换,代码是非常多余的。 如果您只有对提供一堆字符串值的类具有读取权限并且您想围绕它构建一个 switch 语句,则可以使用这种方法。在其他任何地方,您都应该真正坚持使用枚举的方法。

如果您想使用第三方工具来真正确保无需编写任何多余的样板代码,请查看:

  1. FindBugs SF_SWITCH_NO_DEFAULT:但这仅涵盖 switch 语句的默认分支。
  2. @EnumMapper:注解处理器在编译时检查所有枚举常量是否已处理

【讨论】:

    【解决方案2】:

    如果您问是否可以创建一个enum,其中常量有空格,那么答案是''。

    枚举常量是普通的 Java 标识符,如类或变量名,因此它们不能包含空格或特殊字符。


    但是不可能将枚举与字符串链接起来吗?没有。
    如果出于某种原因您希望您的 switch case 使用enum 以提高可读性/简洁性,但您的输入是Strings 可以有空格特殊字符...,那么有办法。

    您需要扩展您的enum 以拥有一个额外的字段(我们称之为标签)来保存此String
    在使用enum 的switch case 方法中,您可以调用findByLabel 方法
    返回与提供的String 对应的enum

    这是一个小示例类,它使用您的 enum 值 NORTH、EAST、SOUTH、WEST,
    链接到不同(无效枚举命名)结构的Strings

    public class EnumExample {
    
        enum SwitchEnum {
            NORTH   ("North star"),
            EAST    ("Eastpack rulez!"),
            SOUTH   ("https://www.southafrica.net/"),
            WEST    ("java.awt.BorderLayout.WEST");
    
            private final String label;
            SwitchEnum(final String label) {
                this.label = label;
            }
    
            @Override
            public String toString() {
                return this.label;
            }
    
            private static final Map<String,SwitchEnum> map;
            static {
                map = new HashMap<String,SwitchEnum>();
                for (SwitchEnum v : SwitchEnum.values()) {
                    map.put(v.label, v);
                }
            }
            public static SwitchEnum findByLabel(String label) {
                return map.get(label);
            }
        }
    
        public static String doEnumSwitch(String enumString) {
            SwitchEnum enm = SwitchEnum.findByLabel(enumString);
            if (enm != null) {
                String enumReturn = enm.name() +" : "+ enm;
                switch (enm) {
                    case NORTH:
                        return enumReturn +" - Up there.";
                    case EAST:
                        return enumReturn +" - Now for sale.";
                    case SOUTH:
                        return enumReturn +" - Now with 50% more elephants.";
                    default:
                        return "UNHANDLED ENUM : "+ enm.name() +" - "+ enm;
                }
            } else {
                return "UNKNOWN ENUM : "+ enumString;
            }
        }
    
        public static void main(String[] args) {
            System.out.println(doEnumSwitch("North star"));
            System.out.println(doEnumSwitch("Eastpack rulez!"));
            System.out.println(doEnumSwitch("https://www.southafrica.net/"));
            System.out.println(doEnumSwitch("java.awt.BorderLayout.WEST"));
            System.out.println(doEnumSwitch("I only want to get out of here."));
        }
    }
    

    这会输出以下内容

    NORTH:北极星 - 在那里。
    东:东包规则! - 现在出售。
    南部:https://www.southafrica.net/ - 现在大象数量增加了 50%。
    未处理的枚举:WEST - java.awt.BorderLayout.WEST
    未知枚举:我只想离开这里。

    【讨论】:

      猜你喜欢
      • 2012-04-30
      • 1970-01-01
      • 2011-12-27
      • 1970-01-01
      • 2014-03-27
      • 1970-01-01
      • 2012-02-22
      • 1970-01-01
      相关资源
      最近更新 更多