我有一个需求,其中我需要从事件列表中构建如下的雇员对象。 目前,我的代码如下所示,但是QE发表评论说可能使用枚举而不是多个。
有人可以建议我如何用枚举实现这一点。
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感谢您的快速回复。 您可以张贴关于如何执行此操作的示例代码片段吗?还有,我使用Java 6而不是7
检查这个问题
您可以在同一示例上查看以下答案。
如果您控制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> 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()));
}
我建议您将处理事件的逻辑移到enum中。如果您使用的是Java 8,则它将类似于:
enum EmployeeField {
ID("empid", Employee::setEmployeeID),
NAME("empname", Employee::setEmployeeName),
SALARY("empsalary", Employee::setEmployeeSalary),
...
private final String key;
private final BiConsumer valueSetter;
EmployeeField(String key, BiConsumer 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()));
这也意味着有关雇员字段的所有信息(包括如何设置雇员值)都封装在枚举中,并且可以轻松更改或扩展而不会影响其他任何内容。
请注意,您可以在不使用lambda的情况下在Java 8之前执行类似的操作,但是(在我看来)它并不那么优雅,因为匿名接口实例需要显式化,这会使代码复杂得多。或者,您可以为每个枚举成员重写方法(在我看来),这些方法甚至更丑陋。
有关Java 8之前的版本的信息,请参见stackoverflow.com/questions/7413872 /(setEmployeeField是抽象方法)
@RC那就是我在上一段中提到的方法。我怀疑我们所有人都认为Java 8整洁了很多!
我只是评论链接以说明目的;)
@RC谢谢。很多人似乎仍然是Java 8之前的人。现在,我曾经习惯于lambda和流,我无法想象没有它们:-)
尽管该解决方案有效,但是如果您再看一眼,在这里使用enum几乎毫无意义。您仅有的"优势"只是访问values以获得可用的"字段"列表,对此您实际上并不需要enum。
@AdrianShum我不确定我是否完全理解您的观点。使用枚举的唯一原因是拥有一组预定义的值。这几乎是所有枚举所要做的。您总是可以使用带有一组静态字段的类来代替,但是枚举更整洁。您能否进一步解释一下关于枚举在这里毫无意义的观点?
问题实际上是您没有将枚举本身用作预定义的值集。您只是使用它来保存字符串值。也许是这样:即使您将枚举值重命名为无意义的东西(E1,E2 ...),也不会对程序造成任何影响。您试图实现的只是从字符串到要调用的方法的映射。您只需制作一张地图即可。使用Map实际上更好,因为每次尝试查找要调用的方法时实际上都在进行顺序搜索,而使用Map则效率更高
使用以下代码创建一个枚举
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这个问题要求使用字符串和枚举来替代多号。我已经尝试在此解决方案中使用枚举。
eeek。我真的不喜欢覆盖枚举名称以匹配事件键的样式。那是一个非常脆弱的方法(我认为)。最好在枚举中包含键。