Replace string literals If / elseIf block with Enum

I am new to using Java Enums and I read that replacing IF logic that compares string literals should be replaced with Enum. I am not quite clear how to replace my below Enum code, any ideas? Based on the col value passed to applyEQ, I need to make the base the next method call on that value. I know the possible col values ​​beforehand and now I am using the constants file. Should I create an Enum and put it in the Constants interface file?

public class FilterHelper implements IFilterHelper {

   private final EQuery eQuery;

   public FilterHelper(EQuery query) {
      eQuery = query;
   }

    @Override
    public void applyEQ(String col, String val) throws Exception {
        int return = 0;
        if (col.equalsIgnoreCase(EConstants.NAME)) {
            ret = Sample.addName(eQuery, val);
        } else if (col.equalsIgnoreCase(EConstants.KEYWORDS)) {
            ret = Sample.addKey(eQuery, val);
        } else if (col.equalsIgnoreCase(EConstants.ROLE)) {
            ret = Sample.addRole(eQuery, val);
        }  

        if (return != 0) {
            throw new Exception("failed");
        }
    }
}

      

EConstants.java

public final class EConstants {    
    public static final String NAME = "cewName";
    public static final String KEYWORDS = "cewKeywords";
    public static final String ROLE = "cewRole";
}

      

+3


source to share


7 replies


First create enum

:

public enum EConstants {
    CEWNAME,
    CEWROLE,
    CEWKEYWORDS;
}

      

Then convert col

String to this one enum

and use switch

:

public void applyEQ(String col, String val) throws Exception {
    int ret = 0;
    final EConstants constant = EConstants.valueOf(col.toUpperCase());
    switch(constant) {
        case CEWNAME:
            ret = Sample.addName(eQuery, val);
            break;
        case CEWROLE:
            ret = Sample.addRole(eQuery, val);
            break;
        case CEWKEYWORDS:
            ret = Sample.addKey(eQuery, val);
            break;
        default:
            throw new Exception("Unhandled enum constant: " + constant);
    }
}

      

Note that it EConstants.valueOf()

can throw IllegalArgumentException

if it col.toUpperCase()

doesn't match any of the constant values.



BTW I hate local variables initialized in multiple places (and keyword break

), try the extract method:

final EConstants constant = EConstants.valueOf(col.toUpperCase());
final int ret = processSample(val, constant);

      

And the method itself:

private int processSample(String val, EConstants constant) throws Exception {
    switch(constant) {
        case CEWNAME:
            return Sample.addName(eQuery, val);
        case CEWROLE:
            return Sample.addRole(eQuery, val);
        case CEWKEYWORDS:
            return Sample.addKey(eQuery, val);
        default:
            throw new Exception("Unhandled enum constant: " + constant);
    }
}

      

+2


source


You can rewrite your EConstants as an enumeration:

public enum EConstants {
  NAME, KEYWORDS, ROLE
}

      



And evaluate the condition with a switch statement:

// col has type of EConstants
switch (col) {
  case NAME:
    // do something
    break;
  case KEYWORDS:
    // do something
    break;
  case ROLE:
    // do something
    break;
  default:
    // what to do otherwise
    break;
}

      

+2


source


The great thing about Java Enums is that they provide language-level support for the type-safe enum, since, among other things, it allows you to define methods and even override them. So you can do this:

public enum CewColumn {

NAME("cewName") {

    @Override
    public int add(EQuery eQuery, String val) {
        return Sample.addName(eQuery, val);
    }
}, 
KEYWORDS("cewKeywords") {

    @Override
    public int add(EQuery eQuery, String val) {
        return Sample.addKey(eQuery, val);
    }
}, 
ROLE("cewRole") {

    @Override
    public int add(EQuery eQuery, String val) {
        return Sample.addRole(eQuery, val);
    }
};

private final String colName;

private MyColumn(String colName) {
    this.colName = colName;
}

private static final Map<String, CewColumn> COLUMNS = new HashMap<>(values().length);
static{
    for (CewColumn cewColumn : values()){
        COLUMNS.put(cewColumn.colName, cewColumn);
    }
}

public abstract int add(EQuery eQuery, String val);

public static CewColumn getCewColumn(String colName){
    return COLUMNS.get(colName);
}
}

      

Then you can use it like this:

CewColumn cewColumn = CewColumn.getCewColumn(colName);
if (cewColumn != null){
    int ret = cewColumn.add(eQuery, val);
}

      

-> You have replaced the switch statement with polymorphism!

+2


source


it's better to create an Enum.

    public Enum AvailableCols{
       COL_1,
       COL_2;
    }

      

and transform the procedure as

    public void applyEQ(AvailableCols col, String val) throws Exception { 
         switch(col){
             case COL1:
             ...

      

If you still want to keep the line, you can see the following message

+1


source


Basically create an enum and change the type col

and use equals()

or ==

to compare the value col

with the values ​​of the enum. Alternatively you can use an operator switch

, but I doubt it will make your code more readable for only 3 constants.

Example:

enum EConstants {
   NAME,
   KEYWORDS,
   ROLE;
}

public void applyEQ(EConstants col, String val) throws Exception {
   if( col == EConstants.NAME ) {
    ...
   }
   ....
}

//or

public void applyEQ(EConstants col, String val) throws Exception {
   if( EConstants.NAME.equals(col) ) { //col might be null
    ...
   }
   ....
}

//or

public void applyEQ(EConstants col, String val) throws Exception {
   switch( col ) {
     case NAME: 
       ...
       break;
     case ROLE: 
       ...

   }

}

      

0


source


http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html

If your source data is a string, you still need to do a string comparison for the enum destination. It may be faster if you are doing a lot of comparisons to the result data, but if not, it just adds complexity to your code.

You can iterate over enum values ​​as collections, which gives you the edge when you need to add constants. It's not bad.

Here's how to do it:

public enum EConstants {
    NAME, KEYWORDS, ROLE
}
...
public EConstants setConstant(String from) {
    if (from.equalsIgnoreCase("cewName")) {
        return NAME;
    } else if (col.equalsIgnoreCase("cewKeywords")) {
        return KEYWORDS;
    } else if (col.equalsIgnoreCase("cewRole")) {
        return ROLE;
    }      
}

      

You preprocess your data this way, and now when you are trying to find the logic, you can use a switch for an enum type value.

0


source


Here's a trick for you. No switch/case

(just come up with a better name for EConstants

).

public enum EConstants {
  NAME,
  KEYWORDS,
  ROLE;

  private interface Applier {
    void apply(EQuery query, String val);
  }

  public void apply(EQuery query, String val) {
    map.get(this).apply(query, val);
  }

  private static Map<EConstants, Applier> map = new HashMap<EConstants, EConstants.Applier>();
  static {
      map.put(NAME, new Applier() {

        @Override
        public void apply(EQuery query, String val) {
          Sample.addName(query, val);
        }

      });

      map.put(KEYWORDS, new Applier() {

        @Override
        public void apply(EQuery query, String val) {
          Sample.addKey(query, val);
        }

      });

      map.put(ROLE, new Applier() {

        @Override
        public void apply(EQuery query, String val) {
          Sample.addRole(query, val);
        }

      });
  }
}

      

Now you just write:

@Override
public void applyEQ(EConstants econs, String val) {
    econs.apply(equery, val);
}

      

0


source







All Articles