3

I have a requirement wherein I need to build an employee object as below from an event list. Currently I've written my code as below, but QE gave a comment saying possible use of enums instead of multiple if else's. Can someone suggest me on how to achieve this with enums.

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());
}
pathfinder
  • 127
  • 4
  • 18
  • 1
    Ya. Create an enum for empname, empsal etc and `switch` based on the event name (assuming you are using java 7+). Removes messy `if-else` clauses and switch will be faster since you don't scan all cases – TheLostMind Oct 29 '15 at 06:23
  • Hi Vinod thanks for the quick reply. Can you post an sample snippet on how to do that... Also fyi, I'm using Java 6 not 7 – pathfinder Oct 29 '15 at 06:29
  • Check [this](http://stackoverflow.com/questions/3978654/best-way-to-create-enum-of-strings) question – TheLostMind Oct 29 '15 at 06:40
  • You can view the below answer for the sample snippet on the same. – Vivek Singh Oct 29 '15 at 06:42

3 Answers3

3

If you are in control of development of Event, I believe what your QE saying is to replace event name by an enum (which is a sane design as you have already decide what is the possible types of event). However, if Event's design is out of your control, or you cannot have a child class of Event for your use (e.g. make an EmployeeEvent), then just ignore what I am going to say)

i.e.

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


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

Then your code can be simplified to

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;
        ....
    }
}

You may even preset the action to do against each event type, using a map (which is of similar idea of another answer)

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

so you can further simplify the above switch by:

Employee e= new Employee();
for (Event event: events) {
    eventActions.get(event.getType()).accept(e, event.getValue()));
}
Adrian Shum
  • 38,812
  • 10
  • 83
  • 131
2

Create an enum with the below codes

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
 }

Hope this helps!

Vivek Singh
  • 2,047
  • 11
  • 24
  • 1
    How will this work?. Strings "empname" , "empsal" etc should be mapped in the enum. – TheLostMind Oct 29 '15 at 06:47
  • Please post answers that are correct - if you need the enum to be EMPNAME, EMPSAL for your code to work, then make them that way in your answer! – Erwin Bolwidt Oct 29 '15 at 07:00
  • Changes done in enum to match the question's strings – Vivek Singh Oct 29 '15 at 07:04
  • @barakmanos This question asks an alternative to multiple if else with string with an enum. I have tried to frame the usage of enums in this solution. – Vivek Singh Oct 29 '15 at 07:08
  • 1
    eeek. I really don't like the style of overriding the enum names to match the event keys. That's a pretty fragile approach (in my opinion). Better to include the keys in the enum. – sprinter Oct 29 '15 at 07:13
2

I would suggest you move the logic of what to do with events into the enum. If you are using Java 8 then it would look something like:

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));
    }
}

Then you can dispense with the switch statement altogether and just use:

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

This also means that all the information about employee fields, including how to set employee values, is encapsulated in the enum and can be easily changed or extended without anything else being impacted.

Note that you can do a similar thing prior to Java 8 without using the lambdas but it's not as elegant (in my view) as the anonymous interface instances need to become explicit which makes the code a lot more complicated. Or you can override methods for each enum member which (in my view) is even uglier.

sprinter
  • 27,148
  • 6
  • 47
  • 78
  • For a pre-java 8 possibility, see http://stackoverflow.com/questions/7413872/can-an-enum-have-abstract-methods (`setEmployeeField` being the abstract method) –  Oct 29 '15 at 07:14
  • @RC That's the approach I was referring to in my last para. I suspect we all agree that it's a lot neater in Java 8! – sprinter Oct 29 '15 at 07:16
  • I did just comment with the link for illustrating purposes ;) –  Oct 29 '15 at 07:17
  • @RC thanks. Lots of people still seem to be pre-Java 8. Now that I'm used to lambdas and streams I can't imagine not having them :-) – sprinter Oct 29 '15 at 07:18
  • Though the solution works, if you have second look, there is almost meaningless using `enum` here. Only "advantage" you have is simply access to `values` to get the list of available "fields", for which you do not really need `enum` for that. – Adrian Shum Oct 30 '15 at 01:53
  • @AdrianShum I'm not sure I understand your point at all. The only reason ever to use enum is to have a predefined set of values. That's pretty much all enums do. You could always use a class with a set of static fields instead but enums are neater. Could you explain your point further about enum being meaningless here? – sprinter Oct 30 '15 at 03:43
  • The problem is actually you are not using the enum as predefined set of value itself. You are just using it to hold the string values. Maybe take it this way: even you rename the enum values to something meaningless (E1, E2...) it will not make any difference to your program. What you are trying to achieve is simply a mapping from the string to the method to call. You can do so simply by making a Map. It is actually better to use a Map, as you are actually doing a sequential search every time you try to lookup the method to call, while using Map it can be much more efficient – Adrian Shum Oct 30 '15 at 05:09