I'm new to using Java Enums and I've read that replace IF logic that compares String literals should be replaced with an Enum. I don't quite understand how to replace my below code with an Enum, any ideas? Based on the col value being passed into applyEQ, I need to do a base the next method call on it's value. I do know the possible values of col ahead of time and I'm using a constants file for now. Should I create an Enum and place it in my Interface of Constants 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";
}
First create an enum
:
public enum EConstants {
CEWNAME,
CEWROLE,
CEWKEYWORDS;
}
Then convert col
String to this 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 EConstants.valueOf()
can throw IllegalArgumentException
if col.toUpperCase()
does not match any of constant values.
BTW I hate local variables initialized in multiple places (and break
keyword), try extracting 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);
}
}
You can rewrite your EConstants as enum:
public enum EConstants {
NAME, KEYWORDS, ROLE
}
And evaluate condition using 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;
}
col
is a String. Prior to Java 7 you cannot switch
over String. But this won't work even in Java 7 -> case
statements reference enum
values - Tomasz Nurkiewicz 2012-04-05 15:52
The great thing about Java Enums is that they provide language level support for the type safe enum pattern, because among other things it allows you to define methods and even override them. So you could 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 replaced the switch statement with polymorphism!
it is best to create a Enum.
public Enum AvailableCols{
COL_1,
COL_2;
}
and convert the procedure as
public void applyEQ(AvailableCols col, String val) throws Exception {
switch(col){
case COL1:
...
If you still want the string to be preserved you can see the following post
Basically create an enum and change the type of col
and use equals()
or ==
to compare the value of col
against the enum values. Alternatively you could use a switch
statement but I doubt that would 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:
...
}
}
http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html
If your raw data is a string, you will still need to do a string comparison to assign the enum. This might be faster if you do a lot of comparisons on the result data, but if not, it simply adds complication to your code.
You can iterate over the values of the enum like a collection, which gives you an advantage when you need to add constants. That's not bad.
Here is 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 that way and now when you are trying to figure out logic you can use a switch on the enum type value.
Here is 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);
}
EConstants
into an Enum class then you can useswitch/case
instead of String comparisons - anubhava 2012-04-05 15:43