【问题标题】:Enum vs If-else枚举与 If-else
【发布时间】:2016-01-29 04:20:40
【问题描述】:

我有一个要求,我需要从事件列表中构建如下的员工对象。目前我已经编写了如下代码,但 QE 给出了一条评论,说可能使用枚举而不是多个 if else。 有人可以建议我如何使用枚举来实现这一点。

Employee e= new Employee();
for(Event event:events){
if("empid".equals(event.getName())
   e.setEmployeeId(event.getvalue());
else if("empname".equals(event.getName())
   e.setEmployeeName(event.getvalue());
else if("empsal".equals(event.getName())
   e.setEmployeeSal(event.getvalue());
else if("empdob".equals(event.getName())
   e.setEmployeeDOB(event.getvalue());
else if("emprole".equals(event.getName())
   e.setEmployeeRole(event.getvalue());
}

【问题讨论】:

  • 是的。根据事件名称为 empname、empsal 等和 switch 创建一个枚举(假设您使用的是 java 7+)。删除凌乱的if-else 子句并且切换会更快,因为您不会扫描所有案例
  • 您好 Vinod 感谢您的快速回复。你能发布一个关于如何做到这一点的示例 sn-p...另外,我使用的是 Java 6 而不是 7
  • 检查this问题
  • 您可以查看以下示例 sn-p 的答案。

标签: java


【解决方案1】:

如果您控制 Event 的开发,我相信您的 QE 所说的是将事件名称替换为 enum(这是一个理智的设计,因为您已经决定了可能的事件类型) .但是,如果Event 的设计超出了您的控制范围,或者您不能拥有Event 的子类供您使用(例如创建EmployeeEvent),那么请忽略我要说的)

enum EventType {
    EMP_ID,
    EMP_NAME,
    ....
}


interface Event {
    EventType getType();   // instead of getName() which returns a String
}

那么你的代码可以简化为

Employee e= new Employee();
for (Event event: events) {
    switch (event.getType()) {
        case EMP_ID:
            e.setEmployeeId(event.getvalue());
            break;
        case EMP_NAME:
            e.setEmployeeName(event.getvalue());
            break;
        ....
    }
}

您甚至可以使用地图预设针对每种事件类型执行的操作(这与另一个答案的想法相似)

Map<EventType, BiConsumer<Employee, String>> eventActions = new EnumMap<>();
eventActions.put(EventType.EMPLOYEE_ID, Employee::setEmployeeID);
eventActions.put(EventType.EMPLOYEE_NAME, Employee::setEmployeeName);

因此您可以通过以下方式进一步简化上述开关:

Employee e= new Employee();
for (Event event: events) {
    eventActions.get(event.getType()).accept(e, event.getValue()));
}

【讨论】:

    【解决方案2】:

    使用以下代码创建一个枚举

    public enum  EMPLOYEE_FIELDS {EMPID, EMPNAME,EMPSAL, EMPDOB, EMPROLE};
    
    EMPLOYEE_FIELDS empField = EMPLOYEE_FIELDS.valueOf(event.getName().toUpperCase());
    
     switch(empField ){
        case EMPID:
            //do something here
            break;
        case EMPNAME:
            //do something here
            break;
        // other cases.
        // other cases.
        // other cases.
        default:
                //do something here
     }
    

    希望这会有所帮助!

    【讨论】:

    • 这将如何工作?字符串 "empname" 、 "empsal" 等应该映射到枚举中。
    • 请发布正确的答案 - 如果您需要枚举为 EMPNAME、EMPSAL 以使您的代码工作,那么在您的答案中使用它们!
    • 在枚举中所做的更改以匹配问题的字符串
    • @barakmanos 这个问题要求使用带有枚举的字符串替代多个 if else。我试图在这个解决方案中定义枚举的使用。
    • eeek。我真的不喜欢重写枚举名称以匹配事件键的风格。这是一种非常脆弱的方法(在我看来)。最好在枚举中包含键。
    【解决方案3】:

    我建议您将处理事件的逻辑移至enum。如果您使用的是 Java 8,那么它看起来像:

    enum EmployeeField {
        ID("empid", Employee::setEmployeeID),
        NAME("empname", Employee::setEmployeeName),
        SALARY("empsalary", Employee::setEmployeeSalary),
        ...
    
        private final String key;
        private final BiConsumer<Employee, String> valueSetter;
    
        EmployeeField(String key, BiConsumer<Employee, String> valueSetter) {
            this.key = key;
            this.valueSetter = valueSetter;
        }
    
        public void setEmployeeField(Employee employee, String value) {
            valueSetter.accept(employee, value);
        }
    
        public static EmployeeField getFieldForKey(String key) {
            return Arrays.stream(values[])
                .filter(ef -> ef.key.equals(key))
                .findAny()
                .orElseThrow(new IllegalArgumentException("No employee field " + key));
        }
    }
    

    然后你可以完全省去 switch 语句,只使用:

    events.stream()
        .forEach(ev -> EmployeeField.getFieldForKey(ev.getName())
            .setEmployeeField(emp, ev.getValue()));
    

    这也意味着关于员工字段的所有信息,包括如何设置员工值,都封装在枚举中,并且可以轻松更改或扩展,而不会影响其他任何内容。

    请注意,在 Java 8 之前,您可以在不使用 lambda 的情况下做类似的事情,但它不像匿名接口实例需要变得显式那样优雅(在我看来),这使得代码更加复杂。或者您可以覆盖每个枚举成员的方法,这(在我看来)更丑陋。

    【讨论】:

    • 对于 pre-java 8 的可能性,请参阅stackoverflow.com/questions/7413872/…setEmployeeField 是抽象方法)
    • @RC 这就是我在上一段中提到的方法。我怀疑我们都同意 Java 8 更简洁!
    • 我只是对链接进行了评论以进行说明;)
    • @RC 谢谢。很多人似乎仍然是 Java 8 之前的版本。现在我已经习惯了 lambda 和流,我无法想象没有它们 :-)
    • 虽然解决方案有效,但如果您再看一遍,这里使用enum 几乎没有意义。您拥有的唯一“优势”是简单地访问values 以获取可用“字段”的列表,您实际上并不需要enum
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-03
    • 1970-01-01
    • 2011-02-24
    相关资源
    最近更新 更多