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";
}
source to share
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);
}
}
source to share
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;
}
source to share
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!
source to share
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:
...
}
}
source to share
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.
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);
}
source to share