i have an enum like below:
public enum TripType {
TRIP1,
TRIP2,
TRIP3,
TRIP4
}
Then i have a method which receives a string parameter setupTravel(String tripType) and i need to check the value of tripType with a TripType. I wish to use a switch-case as below:
setupTravel(String tripType){
switch (tripType){
case TripType.TRIP1.toString():
setup1();
break;
case TripType.TRIP2.toString():
setup2();
break;
}
}
But, in the line TripType.TRIP1.toString() it complains with:
Constant expression required
How can i fix it?
setupTravel(String tripType) {
try {
switch (TripType.valueOf(tripType)) {
case TRIP1:
setup1();
break;
case TRIP2:
setup2();
break;
}
} catch (IllegalArgumentException ex) {
// Handle invalid trip type here
}
}
Since your method seems to switch on the Enum string, why not just use the Enum? You may want to include a default unless you have all Enums in the switch block.
setupTravel(TripType type){
switch (type){
case TRIP1:
setup1();
break;
case TRIP2:
setup2();
break;
}
}
You would call it as
setupTravel(TripType.TRIP1)
If it will be useful for you, You can use an enum constructor instead of using a switch case.
Something like this:
public enum TripType {
TRIP1("setup1"), TRIP2("setup2");
String setup;
private TripType(String setup) {
this.setup = setup;
}
public String getSetup() {
return setup;
}
public static TripType getTripTypeByName(String name) {
return Arrays.stream(TripType.values()).filter(t -> t.name().equalsIgnoreCase(name)).findAny().orElse(null);
}
}
And getting enum based on the name, you can use like this:
TripType tripType = TripType.getTripTypeByName("trip1");
System.out.println(tripType != null ? tripType.getSetup() : null);
Related
So currently, I have some code, that is extremely messy and does the opposite of following dry rules. This is killing me internally, and I would love to fix it, if I knew how.
I have a class called Commands, this have two enums in it. Subs, and Options. What I would like to do, is make a method, such as this one here:
public void makeTab(String args, List<String> command, Commands type) {
if (args.equals("")) {
for (Commands.type commd : Commands.type.values()) {
command.add(commd.name().toLowerCase());
}
} else {
for (Commands.type commd : Commands.type.values()) {
if (commd.name().toLowerCase().startsWith(args)) {
command.add(commd.name().toLowerCase());
}
}
}
}
Then, if that method actually worked like I wanted it to, I could then do this.
List<String> command = new ArrayList<>();
switch (args.length) {
case 1:
makeTab(args[0], command, Subs);
break;
case 2:
makeTab(args[1], command, Options);
break;
}
Very sadly though, as you should be able to tell, this doesn't work, specifically because of the "Commands type" bit in the method. The problem is, I don't know what to put there to work, I've tried "Class type", "enum type", "Enum type". So, because of this catastrophe, my code is currently looking like this.
List<String> comd = new ArrayList<>();
switch (args.length) {
case 1:
if (args[0].equals("")) {
for (Commands.Subs commd : Commands.Subs.values()) {
comd.add(commd.name().toLowerCase());
}
} else {
for (Commands.Subs commd : Commands.Subs.values()) {
if (commd.name().toLowerCase().startsWith(args[0])) {
comd.add(commd.name().toLowerCase());
}
}
}
break;
case 2:
if (args[1].equals("")) {
for (Commands.Options commd : Commands.Options.values()) {
comd.add(commd.name().toLowerCase());
}
} else {
for (Commands.Options commd : Commands.Options.values()) {
if (commd.name().toLowerCase().startsWith(args[1])) {
comd.add(commd.name().toLowerCase());
}
}
}
break;
}
tl;dr I'm trying to make the last code block cleaner by making a method for the if, else.
Rather than taking values yourself, have the caller pass values() to you:
public void makeTab(String args, List<String> command, Enum[] values) {
for (Enum commd : values) {
String lowerName = commd.name().toLowerCase()
if (lowerName.startsWith(args)) {
command.add(lowerName);
}
}
}
The caller would invoke your method as follows:
makeTab(args, command, Options.values());
makeTab(args, command, Subs.values());
Note that there is no need to check args to be an empty string, because when args is empty, startsWith(args) returns true for any String value.
Inside public class we want switchcase based on package name in every case we are calling one public URL.. i tried this way it is not working switch case
public class AllChanges {
Context context;
Switch(getPackageName()) {
case "com.agilerise.package1":
public static String gurl = "http://google.com/index.php";
break;
case "com.agilerise.package2":
public static String gurl = "http://bing.com/index.php";
case "com.agilerise.package2":
public static String gurl = "http://stackoverlfow.com/index.php";
break;
}
}
public class AllChanges {
public static String gurl ="";
public void seturl()
{
Switch(getPackageName()) {
case "com.agilerise.package1":
gurl = "http://google.com/index.php";
break;
case "com.agilerise.package2":
gurl = "http://bing.com/index.php";
break;
case "com.agilerise.package2":
gurl = "http://stackoverlfow.com/index.php";
break;
}
}
}
call like this
AllChanges allchanges=new AllChanges();
allchanges.seturl();
The better way is to use polymorphism here:
Instead of examining the classes package (which may vary and result in duplicated entries for subclasses) you should define an interface:
interface SearchEngineSelector{
URL getSearchEngineUrl();
}
Then You have specialized sub interfaces with default methods:
interface GoogleSearchEngineSelector extends SearchEngineSelector{
URL THE_URL = new URL("http://google.com/index.php");
default public URL getSearchEngineUrl(){
return THE_URL;
}
Your classes then can implement one of the specialized sub interfaces :
class SomeClass implements GoogleSearchEngineSelector {
// ...
}
and your code code change to: Nothing
because there is nothing to do for a subclass...
Java doesn't work that way. You can write statements only inside functions in Java. And declarations of variables can come in class outside of functions.
I would suggest you to read about scope.
https://docs.oracle.com/javase/specs/jls/se8/html/jls-6.html#jls-6.3
You need to declare your variables in the class scope. And your switch case has to be within a function. Your example has a duplicated case, you should probably fix that. com.agilerise.package1, com.agilerise.package2, com.agilerise.package3
public class AllChanges {
public static String gurl = "";
Context context;
private void myFunction(){
switch(getPackageName()) {
case "com.agilerise.package1":
gurl = "http://google.com/index.php";
break;
case "com.agilerise.package2":
gurl = "http://bing.com/index.php";
break;
case "com.agilerise.package3":
gurl = "http://stackoverlfow.com/index.php";
break;
}
}
}
This is a more elegant solution. You should try to avoid static variables. You could then call this function by String url = getUrl(myFunction());
private String getUrl(String s){
switch(s) {
case "com.agilerise.package1":
return "http://google.com/index.php";
case "com.agilerise.package2":
return "http://bing.com/index.php";
case "com.agilerise.package3":
return "http://stackoverlfow.com/index.php";
default:
return "SomeDefaultUrl";
}
}
If I´m using an enum to determine the type of a task.
public enum TaskType {
TYPE_ONE("Type1"),TYPE_TWO("Type2"),TYPE_THREE("Type3");
private final String type;
private StageType(String type) {
this.type = type;
}
#Override
public String toString() {
return type;
}
}
how can I assure at one point in my Application
if(taskType == TaskType.TYPE_ONE) {
typeOneProcessing();
} else if(taskType == TaskType.TYPE_TWO) {
typeTwoProcessing();
} else if(taskType == TaskType.TYPE_THREE) {
typeThreeProcessing();
}
that every enum value is used?
I mean if I need to add a new TYPE_FOUR someday, I´d need to find every place in my code where I used the enum, so I ask myself if there is a better way so that I either avoid the enum and use some other concept or that I can ensure that every value of the enum is used in that piece of code.
There are findbugs type tools for doing that but you could consider removing the if-then-else completely and put the processing inside the enum. Here, adding a new TYPE_FOUR will force you to write it's doProcessing() method.
public interface DoesProcessing {
public void doProcessing();
}
public enum TaskType implements DoesProcessing {
TYPE_ONE("Type1") {
#Override
public void doProcessing() {
}
},
TYPE_TWO("Type2") {
#Override
public void doProcessing() {
}
},
TYPE_THREE("Type3") {
#Override
public void doProcessing() {
}
},
TYPE_FOUR("Type4") {
// error: <anonymous com.oldcurmudgeon.test.Test$TaskType$4> is not abstract and does not override abstract method doProcessing() in DoesProcessing
};
private final String type;
private TaskType(String type) {
this.type = type;
}
#Override
public String toString() {
return type;
}
}
public void test() {
DoesProcessing type = TaskType.TYPE_TWO;
type.doProcessing();
}
If you would prefer an abstract method then this works:
public enum TaskType {
TYPE_ONE("Type1") {
#Override
public void doProcessing() {
}
},
TYPE_TWO("Type2") {
#Override
public void doProcessing() {
}
},
TYPE_THREE("Type3") {
#Override
public void doProcessing() {
}
};
private final String type;
private TaskType(String type) {
this.type = type;
}
// Force them all to implement doProcessing.
public abstract void doProcessing();
#Override
public String toString() {
return type;
}
}
You could put the process method as an abstract method in TaskType, and then override it in every task in the enum. What would probably be a better idea is if you create an interface, something like:
public interface Task {
void process();
}
Then you either let your enum implement this interface. Or, probably better, you create concrete classes implementing this interface. One class for each of your task types.
I think you are saying that you are wanting the compiler to tell you that all of the enum's values are considered.
Unfortunately, Java doesn't support that.
You might think that you could write something like this:
public int method(TaskType t) {
switch (t) {
case TYPE_ONE: return 1;
case TYPE_TWO: return 2;
case TYPE_THREE: return 3;
}
// not reachable ... no return required
}
... and rely on the compiler to tell you if you left out one of the enum values in the switch cases.
Unfortunately, it doesn't work!! The above is a compilation error anyway. According to the JLS reachability rules, the switch statement needs a default: arm for that method to be valid. (Or you can add a return at the end ...)
There is a good reason for this oddity. The JLS binary compatibility rules say that adding a new value to an enum is a binary compatible change. That means that any code with switch statement that switches on an enum needs to still remain valid (executable) code after the addition of enum values. If method was valid to start with, it can't become invalid (because there is a return path with no return statement) after the binary compatible change.
In fact, this is how I would write the code above:
public int method(TaskType t) {
switch (t) {
case TYPE_ONE: return 1;
case TYPE_TWO: return 2;
case TYPE_THREE: return 3;
default:
throw new AssertionError("TaskType " + t + " not implemented");
}
// not reachable ... no return required
}
This doesn't pretend to be compile-time safe, but it is fail-fast, and it doesn't involve bad OO design.
AFAIK you can't do it "automatically".
To minimize the risk of forgetting to add an if/case for new value you could have one "service" class for each enum value and a factory which provides a specific service for enum value.
E.g. instead of:
void methodA(TaskType type) {
doSth();
switch(type) {
case TYPE_ONE:
foo1();
break;
case TYPE_TWO:
foo2();
break;
...
}
}
void methodB(TaskType type) {
doSthElse();
switch(type) {
case TYPE_ONE:
bar1();
break;
case TYPE_TWO:
bar2();
break;
...
}
}
do:
interface Service {
foo();
bar();
}
class ServiceFactory {
Service getInstance(TaskType type) {
switch(type) {
case TYPE_ONE:
return new TypeOneService();
case TYPE_TWO:
return new TypeTwoService();
default:
throw new IllegalArgumentException("Unsupported TaskType: " + type);
}
}
}
And then the methods above can be rewritten as follows:
void methodX(TaskType type) {
doSth();
ServiceFactory.getInstance(type).foo();
}
This way you have only one point where you have to add handling of new enum value.
HashMap<String, Integer> hm=new HashMap<String, Integer>();
...
if(taskType == TaskType.TYPE_ONE) {
typeOneProcessing();
hm.put(TaskType.TYPE_ONE, 1)
} else if(taskType == TaskType.TYPE_TWO) {
typeTwoProcessing();
hm.put(TaskType.TYPE_TWO, 1)
} else if(taskType == TaskType.TYPE_THREE) {
typeThreeProcessing();
hm.put(TaskType.TYPE_THREE, 1)
}
...
for (TaskType t : TaskType.values()) {
if(hm.get(t)!=1)
// Trigger the alarm
}
You can even count the times the element was count if you need it
You can do swich case on the enum, and fail if the default is hit:
switch(taskType ){
case TYPE_ONE: ... break;
case TYPE_TWO: ... break;
case TYPE_THREE: ... break;
default:
throw new IllegalStateException("Unsupported task type:"+taskType);
}
When I try to use enum to store: "=", ">", "<", etc, I have:
public static enum DataValueModifier {
EQUAL("="),
GREATER_THAN(">"),
GREATER_EUQAL(">="),
LESS_THAN("<"),
LESS_EQUAL("<="),
APPRROXIMATE("~"),
NOT_DETERMINED("ND");
private String value;
private DataValueModifier(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
How do I use it when I try to compare a string to see if it contains a "=" sign, should I do:
if (dataValue.contains(DataValueModifier.EQUAL.getValue())) {
...
}
I understand using enum is the better practice here, but this just looks silly...
Thanks,
David
If you defined a method boolean containedIn(String str) in your enum and imported your enum values of interest (in this case EQUAL), usage would look like:
if (EQUAL.containedIn(dataValue)) {
...
}
First of all, I'd move the "contains" method (or the equivalent of it) to the enum itself by defining an isModifier method.
public static enum DataValueModifier {
...
public boolean isModifier( String modifierString )
{
return modifierString != null && value.equals(modifierString);
}
}
Then, your code looks like this instead:
if (DataValueModifier.EQUAL.isModifier(dataValue))
{
//...
}
But, more importantly, why are you using dataValue instead of the enum in the first place? If you are getting command line input or something or parsing a string equation and then need to figure out the expression I guess I understand. But if you have control of the code then you should just start with the enum and you'll be able to say
if ( dataValueEnum == DataValueModifier.EQUAL ) {
{
//...
}
I'd also consider adding a static method to the enum that converts a given string to the correct enum value. It's not quite as efficient, perhaps, but unless you really care about efficiency it will make your code much cleaner. So add this method to your enum:
public static DataValueModifier toDataValueModifier( String dataValue ) {
if( EQUAL.isModifier( dataValue ) {
return EQUAL;
} else if( GREATER_THAN.isModifier( dataValue ) {
return GREATER_THAN;
} else if...
// Do this for all possible values
} else {
return UNKNOWN;
// Also, add an UNKNOWN to your list of enum values.
}
}
The isModifier and the toDataValueModifier methods might add a bit of ugly code to your DataValueModifier enum, but all your other code will look great. You can now do something like this:
DataValueModifier dataValueEnum = DataValueModifier.toDataValueModifier(dataValue);
if (dataValueEnum == DataValueModifier.EQUAL) {
...
}
or even
switch( DataValueModifier.toDataValueModifier(dataValue) ) {
case EQUAL:
// ...
break;
case GREATER_THAN:
// ...
break;
case GREATER_EQUAL:
// ...
break;
// ... define all the cases you want
case UNKNOWN:
default:
// ...
}
I like to use a static import in these cases.
package mypackage;
public enum DataValueModifier
{
//your enum code
}
then...
import static mypackage.DataValueModifier.*;
public MyClass
{
// code blah blah blah
public void doIt()
{
// more code blah blah
if (dataValue.contains(EQUAL.getValue()))
{
//...
}
}
}
It's a little nicer.
I'm trying to use a switch statement in Android aplication,where I have to check if an integer is equal to some of the Enum's value.The code goes like this :
public enum RPCServerResponseCode{
E_INCORRECT_LOGIN(4001),
E_ACCOUNT_DISABLED(4002),
E_ACCOUNT_NOT_ACTIVE(4003);
private int value;
private RPCServerResponseCode(int i) {
this.value=i;
}
public static RPCServerResponseCode getByValue(int i) {
for(RPCServerResponseCode dt : RPCServerResponseCode.values()) {
if(dt.value == i) {
return dt;
}
}
throw new IllegalArgumentException("No datatype with " + i + " exists");
}
}
}
And my switch statement looks like this :
int errorCode;
switch(errorCode){
case RPCServerResponseCode.E_INCORRECT_LOGIN :
{
if (user.isAuthenticated)
{
// logout before login
}
break;
}
case RPCServerResponseCode.E_ACCOUNT_NOT_ACTIVE:
{
if (user.isAuthenticated)
{
//logout
}
break;
}
}
}
But I get error saying this : "Type mismatch: cannot convert from RPCCommucatorDefines.RPCServerResponseCode to int".
Any suggestions how to solce that issue? Thanks in advance!!!
errorcode is int. Should be of type RPCServerResponseCode, so you could use something like:
switch (RCPServerResponseCode.getByValue(errorcode))
{
...
}
You're trying to compare your INT error code to a RPCServerResponseCode instance - This isn't possible. You need to use the method getByValue in your RPCServerResponseCode class to do the conversion for you. After that, you can use the result (Which will be a RPCServerResponseCode instance) in your switch statement:
int errorCode;
RPCServerResponseCode responseCode = RPCServerResponseCode.getByValue(errorCode);
switch(responseCode){
case RPCServerResponseCode.E_INCORRECT_LOGIN :
{
if (user.isAuthenticated)
{
// logout before login
}
break;
}
case RPCServerResponseCode.E_ACCOUNT_NOT_ACTIVE:
{
if (user.isAuthenticated)
{
//logout
}
break;
}
}
}
Java enums are fully-fledged objects and cannot be implicitly cast to integers.
This should work:
switch(RPCServerResponseCode.getByValue(errorCode)){
you can say
int errorCode=4001;
RPCServerResponseCode code = RPCServerResponseCode.getByValue(errorCode);
switch(code){
...
}