2

In my front end html, when no country is selected, country 0 is saved.

In my back end,in my java code I want to have a 0 to for no countries selected.

I get a syntax error on 0 ("");

So when i get a country code of 0 ,the enum code will not fail on System.out.println(Country.valueOf("0").getCountry());

Do advise, thanks.

public static void main (String []args) {
    System.out.println(Country.valueOf("SG").getCountry());
}

public static enum Country {
    MY ("Malaysia"),   
    SG ("Singapore"),   
    ID ("Indonesia"),
    0 (""); //for null blank

    private final String country;

    private Country(String levelCode) {
        this.country = levelCode;
    }   

    public String getCountry() {
        return this.country;
    }
}
8
  • 2
    You can write NO_COUNTRY("0"). Commented Jul 20, 2019 at 5:38
  • If i add tthe above, 'System.out.println(Country.valueOf("0").getCountry());' will fail Commented Jul 20, 2019 at 5:41
  • 1
    Have the enumeration at ordinal 0 just be labeled as no country. Then you can lookup by ordinal instead of the much slower string lookup. Commented Jul 20, 2019 at 5:46
  • You can also add your own lookup function, then use a switch for the string tests so that you can get constant lookup time. Commented Jul 20, 2019 at 5:47
  • 3
    @vandench relying upon the ordinal of an enum value is brittle (there is an item in Effective Java about this): what if somebody unknowingly reorders the values, say alphabetically, and you start accidentally assigning everybody to a particular country. It is far better to be explicit about one element being "unknown", even if (in the current code) that happens to be the first element. Commented Jul 20, 2019 at 6:28

5 Answers 5

2

While the other answers contain helpful suggestions, I’d like to explain the reason for your error and the limitations of Java enums.

The reason for your syntax error is that in Java (and most other programming languages) an enum constant is an identifier and an identifier has to start with a letter (or underscore, certainly not recommended). 0 is not a letter.

This in turn also means that Country.valueOf("0") is never going to work no matter what you do (one might have imagined overriding the method in your enum, but that is not possible).

Two suggestions:

  1. Use another name, one that starts with a letter.

       NULL_BLANK (""); //for null blank
    
  2. Use a null to represent no country.

For a different name I’m thinking COUNTRY_0, BLANK or ZERO. No matter if you use item 1. or 2. above you will have to write your own lookup method as in Joakim Danielson’s answer, for example.

Edit: A possibly nicer solution may be an enum where the constructor accpets both key and country name as arguments:

public static enum Country {
    MALAYSIA ("MY", "Malaysia"),   
    SINGAPORE ("SG", "Singapore"),   
    INDONESIA ("ID", "Indonesia"),
    NULL_BLANK ("0", ""); //for null blank

    private static final Map<String, Country> BY_KEY
            = Arrays.stream(values()).collect(Collectors.toMap(c -> c.key, c -> c));

    public static Country of(String key) {
        return BY_KEY.get(key);
    }

    private final String key;
    private final String country;

    private Country(String key, String name) {
        this.key = key;
        this.country = name;
    }   

    public String getCountry() {
        return this.country;
    }
}

One advantage is it allows for nicer enum constant names, MALAYSIA instead of MY, etc. I have provided the of method for lookup. Use like for example:

        System.out.println("MY -> \"" + Country.of("MY").getCountry() + "\"");
        System.out.println("0  -> \"" + Country.of("0").getCountry() + "\"");

Output:

MY -> "Malaysia"
0  -> ""
Sign up to request clarification or add additional context in comments.

Comments

1

You can create your own valueOf method and use that instead in your code, since Enum.valueOf is static we can't override it directly so we need another name for our method

public static Country getValue(String code) {
    if (code == null || code.isEmpty() || code.equals("0")) {
        return NO_COUNTRY;
    }
    return valueOf(code);
} 

I added a NO_COUNTRY to the enum defined like this

NO_COUNTRY("")

Example

public static void main(String[] args) throws Exception {
  System.out.printf("[%s]\n", Country.getValue("SG").getCountry());
  System.out.printf("[%s]\n", Country.getValue("0").getCountry());
}

yields

[Singapore]
[]

Comments

0

As per your requirement, instead of writing 0 (""); //for null blank, you can write like this.

ZERO ("NO-COUNTRY");

or

NO_COUNTRY("ZERO");

2 Comments

If I do ` System.out.println(Country.valueOf("0").getCountry());` it will fail then
You have to use like this System.out.println(Country.valueOf("ZERO").getCountry());
0

Enum.valueOf throws an exception when a passed string is not mapped to any enum value of the given enum. Furthermore valueOf is O(n) - it has to iterate all elements of an enum to find the matching enum. Try using an internal Map<String,Country> instead:

import java.util.Arrays;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

class ScratchStackOverflowQuestion57122100 {
    public static enum Country {
        MY ("Malaysia"),
        SG ("Singapore"),
        ID ("Indonesia"),
        FALLBACK(null);

        private static final Map<String, Country> stringMapping =
                Arrays.stream(Country.values())
                .collect(Collectors.toMap(Country::getCountry, Function.identity()));

        private final String country;

        Country(String levelCode) {
            this.country = levelCode;
        }

        public String getCountry() {
            return this.country;
        }

        //caller has to handle non-presence
        public static Optional<Country> tryFromString(String input) {
            return Optional.ofNullable(stringMapping.get(input));
        }

        //handle the error internal
        public static Country fromString(String input) {
            return tryFromString(input).orElse(FALLBACK);
        }
    }
}

This has the following benefits: if you only add tryFromString you could let the caller handle the error, you don't have to specify a fallback then - this may fix your 0 issue. The lookup is really fast now and doesn't throw an undesirable exception in the future as unmapped values are always mapped to FALLBACK in fromString.

Comments

0

Why don't you use HasMap (Recommended)?

public final static Map countries = new HashMap<String, String>();
static {
    countries.put("MY", "Malaysia");
    countries.put("SG", "Singapore");
    countries.put("ID", "Indonesia");
    countries.put("0", "");
}

1 Comment

No, I mistake with Kotlin @OleV.V.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.