Switch String with Enum variables - java

I have got an Enum with different values and want to switch a string variable. Now I hit a wall trying to convert the Enum values to Strings, that I can use as case constant.
My best try was to convert the Enum to a String array, but the switch doesn't seem to accept array values as a case constant. (IntelliJ says: "constant expression required")
Enum myEnum = {FOO, BAR}
String input = "foo"
final String[] constant = Arrays.stream(myEnum.values()).map(Enum::name).toArray(String[]::new);
//converts Enum to String[]; made it final, so it is "constant"
switch (input) {
case constant[0]:
System.out.println("foo");
break;
case constant[1]:
System.out.println("bar");
break;
}
Is there an elegant way to make this switch depend on the Enum?

You shouldn't convert it because it isn't needed. Also, your code won't even compile because case is a reserved keyword in Java.
You should take a look at the valueOf method of an Enum.
Your code can look like that:
public enum MyEnum {FOO, BAR}
//method
String input = "foo";
MyEnum niceFound = MyEnum.valueOf(input.toUpperCase());
That will return FOO but can throw an IllegalArgumentException when the given value isn't present as type.

You can do this :
public enum MyEnum {
FOO("foo"),
BAR("bar");
private String value;
public String getValue() {
return value;
}
public static MyEnum getState(String value) {
switch (value) {
case "foo":
return FOO;
case "bar":
return BAR;
}
return null;
}
private MyEnum(String value) {
this.value = value;
}
}
Now, in your class, you can :
MyEnum myEnum = getState("foo"); // returns MyEnum.FOO
Also make sure you handle the case when getState() returns null

A solution with Java 8+ streams would be to create a method inside your enum :
public static Optional<MyEnum> getByValue(final String value) {
return Arrays.stream(MyEnum.values())
.filter(myEnum -> myEnum.value.equals(value))
.findFirst();
}
This returns optional in case there is no enum value for your String parameter. But you can change it according to your needs.

Use MyEnum.valueOf(value.toUpperCase())
public enum MyEnum {
FOO, BAR;
}
public static void process(String value) {
try {
switch (MyEnum.valueOf(value.toUpperCase())) {
case FOO :
System.out.println("FOO");
break;
case BAR :
System.out.println("BAR");
break;
default :
break;
}
}
catch (IllegalArgumentException e) {
// TODO: handle exception
}
public static void main(String[] a){
process("foo");
}

Related

Constant Map for case selection in switch statement?

Is there a way to define a constant Map for the use in a switch statement? All my trials with static Maps from here, here and others were not successful. Why isn't the Map constant?
For the line case (kws.get(KEYWORD_NAME)): I always get constant string expression required error.
public class Demo {
public static final String KEYWORD_NAME = "Name";
public static final String KEYWORD_TYPE = "Type";
private static final Map<String, String> kws = Collections.unmodifiableMap(
new HashMap<String, String>() {{
put(KEYWORD_NAME, KEYWORD_NAME.toLowerCase());
put(KEYWORD_TYPE, KEYWORD_TYPE.toLowerCase());
}});
public static void parse(String kw){
switch(kw){
case (kws.get(KEYWORD_NAME)):
System.out.println("Test");
break;
default:
System.out.println("Unknown");
}
}
}
No, because the case labels in a switch statement must be either constant expressions or enumerators.
The reference to your Map is final, and your map is unmodifiable. But the latter is enforced at run time. The compiler does not treat the object as a constant.
From the Java Language Specification, 14.11: The switch statement:
SwitchLabel:
case ConstantExpression :
case EnumConstantName :
default :
Constant expressions can be composed only of primitive and String literals, certain operators without side-effects, constant variables, and a few other components that can be computed at compile-time. (A constant variable is a final variable of primitive or String type that's been initialized to a constant expression.) More detail is at 15.28: Constant expressions.
I do not know your use case, but instead of using unmodifiable map you can use parametrized enum:
>> when:
public enum Demo {
NAME("Name"),
TYPE("Type"),
NOT_SUPPORTED("");
private String code;
private static final Map<String, Demo> CODE_VALUE_MAP = new LinkedHashMap<>();
// -- static
static {
for (Demo demo : Demo.values()) {
CODE_VALUE_MAP.put(demo.getCode(), demo );
}
}
public static Demo forCode(#NotNull String code) {
if (code!= null) {
return CODE_VALUE_MAP.getOrDefault(code.toUpperCase(), NOT_SUPPORTED);
}
return NOT_SUPPORTED;
}
}
// -- constructor
Demo(String code) {
this.code= code;
}
// -- public methods
public String getCode() {
return code;
}
}
>>Then:
...
public static void parse(String kw){
Demo demo = Demo.forCode(kw);
switch(demo){
case NAME:
System.out.println("Test");
break;
default:
System.out.println("Unknown");
}
...

Can't access enum values inside Switch Case / Java

I can't access my enum variables in my switch-case statement:
public enum Country {
FRANCE(0, "France"), SPAIN(1, "Spain");
private final int code;
private final String name;
Country(int code, String name) {
// TODO Auto-generated constructor stub
this.code = code;
this.name = name;
}
public int getCode() {
return code;
}
public String getName() {
return name;
}
}
In another class there is this code :
public Drawable getFlag(){
Drawable d = null;
switch(country_id){
case Country.FRANCE.getCode():
break;
}
return d;
}
But the problem is that when i type Country, there is only class or this.
The expressions in the case statements must be constant values.
One (commonly used) way to approach your problem is by creating a function that gets the enum from the numeric code:
public enum Country {
...
public static Country getCountry(int countryCode) {
for(Country country : Country.values()) {
if(country.code == countryCode) {
return country;
}
}
throw new IllegalArgumentException();
}
Then you'll be able to do the switch on the enum:
switch(Country.getCountry(country_id)){
case Country.FRANCE:
break;
...
}
case labels in a switch statement need be constants
The case expressions must be compile time constant expressions. Your enum instance's variables are constants, but not compile time constants.
We call a variable, of primitive type or type String, that is final
and initialized with a compile-time constant expression (§15.28) a
constant variable. Whether a variable is a constant variable or not
may have implications with respect to class initialization (§12.4.1),
binary compatibility (§13.1, §13.4.9) and definite assignment (§16).

Using Enum as a int value

Am trying to use Enum as Constants for readability as below .
Public enum x { test1 , test2 , test3 }
I want to pass this enum into a method and use it as a int value as shown
private void (int type)
{
switch(int)
{
case enum.X:
// do somthing
break;
}
} ;
Can we use enum here as its more clearer than using a int value .( like switch 1 etc) . Is it possible to use this way.?
Yes, you should be able to use an enum in a switch statement in Java:
public enum SomeEnum { FOO, BAR, BAZ };
// in a class...
private void something(SomeEnum s) {
switch (s) {
case FOO:
// do something
break;
case BAR:
// do something else
break;
}
}
Not sure I understand how int values tie into this, but you can have fields/methods on an enum like in a normal Java class, and can use these to hold int (or any other type) values as on any other POJO.
Here's an example in which we declare a constructor for an enum class, so that you can pass in values for internal variables at the time each instance of the enum is constructed. To help you follow what's going on: First we declare the items in the enum - each declaration invokes the constructor, so we can pass in instance variables here. Then the code for the enum class follows, as with a normal Java class.
public enum AnotherEnum {
ONE(1, "un"), TWO(2, "deux"), THREE(3, "trois"), FIFTY_SEVEN(57, "cinquante-sept");
private final int someInt;
private final String french;
private AnotherEnum(int i, String s) {
this.someInt = i;
this.french = s;
}
public int getSomeInt() {
return this.someInt;
}
public String getFrench() {
return this.french;
}
}
So for example, System.out.println(AnotherEnum.TWO.getSomeInt()) would print 2, and System.out.println(AnotherEnum.FIFTY_SEVEN.getFrench()) would print cinquante-sept.
No, you cannot say:
case Enumerator.ordinal():
But you could say:
switch(EnumObject.values()[intVar]) {
case Enumerator1:
...
}
Another way you can do this by doing a little more work with you enum class.
public enum Foo {
X (1),
Y (2);
private int value;
Foo (int value)
{
this.value = value;
}
}
Now all you need to do is:
switch (int)
{
case Foo.X: doSomething ();break;
case Foo.Y: doSomething ();break;
}

Design Issue | Enum to represent combo box options

I need to use an Enum with a combobox (values shown below).
YES (shown as YES on UI, stored in DB as Y)
NO (shown as NO on UI, stored in DB as N)
DEFAULT (shown as "" on UI, stored in DB as null)
The Enum has methods to perform the following -
toString() - to provide the custom String for UI. (showing the combo options)
OptionToDB (static) - Convert a selected option to db value (on save / update)
DBToOption (static)- Convert a DB value to selcted option (while loading the screen)
static enum EnumOption{
YES,NO,DEFAULT;
....
public static EnumOption DBToOption(String val){
if("Y".equals(val)){
return YES;
} else if("N".equals(val)){
return NO;
}else {
return DEFAULT;
}
}
....
}
It works pretty well, but the issue with above methods is that it uses if/else comparison to deduce which option / db value to be returned.
I thought of storing the dbValue as a field in enum but I was not able to reduce the if/else from DBToOption.
Can this if/else be avoided in any way using a better design??
If you store the dbValue as a field in the enum, you can remove the if/else and replace it with a for-loop, although I don't see anything wrong with those if/elses for this particular case:
static enum EnumOption {
YES("Y"),
NO("N"),
DEFAULT("");
private final String value;
private EnumOption(String value) {
this.value = value;
}
public static EnumOption DBToOption(String val) {
for (EnumOption opt : EnumOption.values()) {
if (opt.value.equals(val)) {
return opt;
}
}
return DEFAULT;
}
}
public enum EnumOption {
YES("Y"), NO("N"), DEFAULT("");
private final String value;
private final static Map<String, EnumOption> options;
static {
options = new HashMap<String, EnumOption>();
for (EnumOption opt : EnumOption.values()) {
options.put(opt.value, opt);
}
}
private EnumOption(String value) {
this.value = value;
}
public static EnumOption DBToOption(String val) {
return options.get(val) != null ? options.get(val) : DEFAULT;
}
}
And here is the test that proves it works.
public void testDBToOption() {
assertEquals(EnumOption.NO, EnumOption.DBToOption("N"));
assertEquals(EnumOption.YES, EnumOption.DBToOption("Y"));
assertEquals(EnumOption.DEFAULT, EnumOption.DBToOption(""));
assertEquals(EnumOption.DEFAULT, EnumOption.DBToOption(null));
assertEquals(EnumOption.DEFAULT, EnumOption.DBToOption("R"));
}
So you want to get rid of the remaining if/else ...Are you doing Object Calisthenics?
You could do the following, if you do not have compatibility issues:
public enum EnumOption {
Y("Y", "YES"),
N("N", "NO"),
D("D", "");
private final String dbValue;
private final String uiValue;
private EnumOption(String dbValue, String uiValue) {
this.dbValue = dbValue;
this.uiValue = uiValue;
}
public String getDbValue() {
return this.dbValue;
}
public String uiValue() {
return this.uiValue;
}
public static EnumOption getFromDb(String dbValue) {
return EnumOption.valueOf(dbValue);
}
}
Since each enum value can only occur once, this has at least the same performance as all the other implementations.
For details about the automatically generated valueOf(String) method in enum types, and James DW's solution, you can read up in Josh Bloch's Effective Java Item 30 (Use enums instead of int constants), page 154.

Implementing toString on Java enums

It seems to be possible in Java to write something like this:
private enum TrafficLight {
RED,
GREEN;
public String toString() {
return //what should I return here if I want to return
//"abc" when red and "def" when green?
}
}
Now, I'd like to know if it possible to returnin the toString method "abc" when the enum's value is red and "def" when it's green. Also, is it possible to do like in C#, where you can do this?:
private enum TrafficLight {
RED = 0,
GREEN = 15
...
}
I've tried this but it but I'm getting compiler errors with it.
Thanks
You can do it as follows:
private enum TrafficLight {
// using the constructor defined below
RED("abc"),
GREEN("def");
// Member to hold the name
private String string;
// constructor to set the string
TrafficLight(String name){string = name;}
// the toString just returns the given name
#Override
public String toString() {
return string;
}
}
You can add as many methods and members as you like. I believe you can even add multiple constructors. All constructors must be private.
An enum in Java is basically a class that has a set number of instances.
Ans 1:
enum TrafficLight {
RED,
GREEN;
#Override
public String toString() {
switch(this) {
case RED: return "abc";
case GREEN: return "def";
default: throw new IllegalArgumentException();
}
}
}
Ans 2:
enum TrafficLight {
RED(0),
GREEN(15);
int value;
TrafficLight(int value) { this.value = value; }
}
Also if You need to get lowercase string value of enum ("red", "green") You can do it as follows:
private enum TrafficLight {
RED,
GREEN;
#Override
public String toString() {
return super.toString().toLowerCase();
}
}
I liked this approach for selective alternate toString() if it's useful for anyone out there :
private enum TrafficLight {
RED,
GREEN {
#Override
public String toString() {
return "GREEN-ISH";
}
}
}

Categories

Resources