-3

I want to create a switch/case statement in Java and ensure that all the Strings are in the statement.

However, it is easy to create a enum in Java with simple Strings i.e. NORTH, SOUTH, EAST, WEST.

How would it be done for strings with dots and spaces? i.e. "This is the description", "com.stackoverflow.ClassName"

jordiburgos
  • 5,964
  • 4
  • 46
  • 80
  • 4
    I'm afraid your question is not clear. What do you mean by "ensure that all the Strings are in the statement". What are those strings? – M A Mar 14 '19 at 12:23
  • by adding them in your case list – Stultuske Mar 14 '19 at 12:23
  • 1
    The Java compiler doesn't know that "NORTH" is part of a set of cardinal directions. How would it? – Michael Mar 14 '19 at 12:30
  • By using enums. They're what is doing what you're asking for. – kumesana Mar 14 '19 at 12:32
  • @kumesana that makes no sense.it is perfectly possible to have a switch on enums without having all enums in a case. – Stultuske Mar 14 '19 at 12:34
  • @Stultuske Java allows this but most professional environments treat it as an error if you don't set a *default* case. And all compilers I've known treats it at least as a warning, as encouraged by Java's specifications. This is enough of a useful feature to request it. – kumesana Mar 14 '19 at 12:39
  • The question is unclear. So maybe reword the question or add a code sample of what you try to do, but which doesn't work for you. – George Derpi Mar 14 '19 at 12:46
  • 1
    @kumesana warnings, yes, and no doubt libraries like sonar will pick up on it as well. unfortunately, this will not guarantee all cases are handled, It'll just inform you that some are not. As for the default: personally, I try to avoid it when switching on an enum. After all: if I would want them to be treated the same, I don't need different values. The danger herein is that everything is indeed handled. But if you somewhere missed a switch(myEnum) to adapt, it'll give wrong results if the default handling differs from the one you need. – Stultuske Mar 14 '19 at 14:32

2 Answers2

4

I think the main Problem of this question is, that your IDE is telling you that you are missing enum values within a switch statement. And asks you whether you would like to add them and not your compiler. This of course does not ensure a user of your enum class to have to use every value.

There is an approach mentioned by Joshua Bloch in his Effective Java book (Chapter Emulated extensible enum using an interface which can be changed to work with a switch shown here: Java Enum Switch. But I think the switch solution doesn't provide full security that all enums are used.

But since you wanted to know whether there is a solution using strings, we can also try using a functional approach as shown here: Enum Switch Functional Approach and make it work with string fields instead of enums.

This could look as follows:

public class Direction {
    private static final String NORTH = "north";
    private static final String SOUTH = "south";
    private static final String EAST = "east";
    private static final String WEST = "west";

    public interface SwitchResult {
        void NORTH();
        void SOUTH();
        void EAST();
        void WEST();
    }

    public static void switchValue(String direction, SwitchResult result){
        switch (direction){
            case NORTH:
                result.NORTH();
                break;
            case SOUTH:
                result.SOUTH();
                break;
            case EAST:
                result.EAST();
                break;
            case WEST:
                result.WEST();
                break;
        }
    }

    public static void main(String[] args) {
        String direction = "west";
        Direction.switchValue(direction, new SwitchResult() {
            @Override public void NORTH() {
                System.out.println("this time north");
            }

            @Override public void SOUTH() {
                System.out.println("this time south");
            }

            @Override public void EAST() {
                System.out.println("this time east");
            }

            @Override public void WEST() {
                System.out.println("this time west");
            }
        });
    }
}

As you can see in the main method, if you want to call the switchValue function you have to pass your string and an implementation of your interface, which ensures you to override every possibility. In exchange for this the code is very redundant. This approach could be used if you only have read access to a class which offers a bunch of String values and you want to build a switch statement around it. Anywhere else you should really stick to an approach using enums.

If you want to use third party tools to really ensure without having to write any redundant boilerplate code have a look at:

  1. FindBugs SF_SWITCH_NO_DEFAULT: But this only covers default branch of switch statement.
  2. @EnumMapper: Annotation processor which checks at compile-time that all enum constants are handled
FlorianDe
  • 1,202
  • 7
  • 20
2

If you are asking whether you can create an enum where the constants have spaces, then the answer is 'no'.

Enum constants are normal Java identifiers, like class or variable names so they can not have spaces or special characters in them.


However is it impossible to link an enum with a String? No.
If for some reason you want your switch case to use an enum for readability/brevity, but your inputs are Strings that can have spaces, dots, special characters..., then there is a way.

You need to extend your enum to have an extra field (let's call it label) to hold this String.
In your method with the switch case that uses the enum, you can call a findByLabel method
that returns the enum that corresponds to the provided String.

Here is a little example class that uses your enum values NORTH, EAST, SOUTH, WEST,
linked to Strings of different (invalid enum naming) structures.

public class EnumExample {

    enum SwitchEnum {
        NORTH   ("North star"),
        EAST    ("Eastpack rulez!"),
        SOUTH   ("https://www.southafrica.net/"),
        WEST    ("java.awt.BorderLayout.WEST");

        private final String label;
        SwitchEnum(final String label) {
            this.label = label;
        }

        @Override
        public String toString() {
            return this.label;
        }

        private static final Map<String,SwitchEnum> map;
        static {
            map = new HashMap<String,SwitchEnum>();
            for (SwitchEnum v : SwitchEnum.values()) {
                map.put(v.label, v);
            }
        }
        public static SwitchEnum findByLabel(String label) {
            return map.get(label);
        }
    }

    public static String doEnumSwitch(String enumString) {
        SwitchEnum enm = SwitchEnum.findByLabel(enumString);
        if (enm != null) {
            String enumReturn = enm.name() +" : "+ enm;
            switch (enm) {
                case NORTH:
                    return enumReturn +" - Up there.";
                case EAST:
                    return enumReturn +" - Now for sale.";
                case SOUTH:
                    return enumReturn +" - Now with 50% more elephants.";
                default:
                    return "UNHANDLED ENUM : "+ enm.name() +" - "+ enm;
            }
        } else {
            return "UNKNOWN ENUM : "+ enumString;
        }
    }

    public static void main(String[] args) {
        System.out.println(doEnumSwitch("North star"));
        System.out.println(doEnumSwitch("Eastpack rulez!"));
        System.out.println(doEnumSwitch("https://www.southafrica.net/"));
        System.out.println(doEnumSwitch("java.awt.BorderLayout.WEST"));
        System.out.println(doEnumSwitch("I only want to get out of here."));
    }
}

This outputs the following

NORTH : North star - Up there.
EAST : Eastpack rulez! - Now for sale.
SOUTH : https://www.southafrica.net/ - Now with 50% more elephants.
UNHANDLED ENUM : WEST - java.awt.BorderLayout.WEST
UNKNOWN ENUM : I only want to get out of here.

George Derpi
  • 668
  • 4
  • 10