19

When I was starting to programme in Java, the fact that switch statements didn't take strings frustrated me. Then on using Enums, I realised the benefits that you get with them rather than passing around raw values — type safety (which brings easier refactoring) & also clarity to other developers.

I'm struggling to think of a situation where with SE7 I'll now decide to use a switch with strings as inputs rather than Enums. If they are implemented via switching on whole strings (e.g. rather than partial or regex matches), it doesn't seem to offer less reason for the code to change.

And with IDE tools and the read-write ratio of coding, I'd be much happier auto-generating an extra Enum than passing around string values.

What benefit do they bring to us as programmers? Less boiler-plate?

It doesn't feel like the language was crying-out for this feature. Though maybe there's a use-case I'm overlooking.

anotherdave
  • 467
  • 3
  • 12
  • Strings are already used a lot in switch statements already, but because people could not use them directly they resorted to workarounds like giant if else trees or conversions to enums. Both workarounds make code less readable. Both ways are workarounds and why use a workaround if a natively implemented solution shows the programmers intentions better. – Pieter B Nov 18 '13 at 11:50
  • @PieterB Arguably though, an Enum is adding semantic value rather than being a workaround though, which brings type-safety (e.g. a typo will be caught at compile time rather than leading to a bug). It also allows us to refactor all instances of the string, *as used in that context*, without affecting other usages of that string (which may happen quite often with domain objects.) – anotherdave Nov 18 '13 at 14:06

8 Answers8

12

As far as I can tell, the question is why wrapping String constants into enum hasn't been considered sufficient to cover the needs of language users. This has been addressed in the official feature proposal announced at JDK 7 (project Coin) mailing list.

Per my reading of the proposal, alternative of using enums has been dismissed on the ground that it introduces types bloat. For your convenience, relevant part of the proposal is quoted below, with the statement addressing enums quoted in bold:

MAJOR ADVANTAGE: What makes the proposal a favorable change?

More regular coding patterns can be used for operations selected on the basis of a set of constant string values; the meaning of the new construct should be obvious to Java developers.

MAJOR BENEFIT: Why is the platform better if the proposal is adopted?

Potentially better performance for string-based dispatch code.

MAJOR DISADVANTAGE: There is always a cost.

Some increased implementation and testing complexity for the compiler.

ALTERNATIVES: Can the benefits and advantages be had some way without a language change?

No; chained if-then-else tests for string equality are potentially expensive and introducing an enum for its switchable constants, one per string value of interest, would add another type to a program without good cause...

gnat
  • 21,442
  • 29
  • 112
  • 288
  • the bold part is quite surprising – Simon Bergot Nov 18 '13 at 11:02
  • 1
    @Simon well to me personally it reads as indirect treat, "we'll loose competition to C# if we continue sticking with pre-Java5 ways of dealing with considerations like that". :) For an example of "pre-Java5 ways", refer to [JDK-1223179 : switch on strings](http://bugs.sun.com/view_bug.do?bug_id=1223179) - submitted in 1995 and quickly closed as _Won't Fix_: "Don't hold your breath. Nothing resembling this is in our plans." – gnat Nov 18 '13 at 11:14
  • Thanks, very interesting to see the reasons put forward in the proposal. It still feels wrong to say that we're introducing a type to a programme "without good cause" - we're OO programmers! :) – anotherdave Nov 18 '13 at 14:10
  • 5
    @anotherdave "object-oriented" justifies introducing types only when these serve meaningful purpose. Apparently, prevailing opinion at JCP turned out that using enums as brainless wrappers for String constants in switch doesn't qualify as meaningful – gnat Nov 18 '13 at 14:20
  • 1
    Wow, I'm surprised (in a good way) to see the official proposal actively countering type bloat. That's refreshing. Type bloat is a huge problem in Java. – Ben Lee Nov 20 '13 at 20:35
7

Apart from making the code more readable, there are potential performance gains relative to if/else if comparisons. Whether the change is worthwhile depends on how many comparisons you would be making. A string switch will be emitted as two separate switch instructions. The first operates on hash codes, so it tends to be a lookupswitch, ultimately yielding O(log n) complexity. The second is always a perfect O(1) tableswitch, so the combined complexity is still O(log n). A single, linear chain of if/else if statements would give slightly worse O(n) complexity.

If you're comparing more than, say, three strings, then a switch is probably more readable and compact. It will likely perform better, though you are unlikely to notice a difference unless you are doing a large number of comparisons on a hot code path.

Mike Strobel
  • 254
  • 1
  • 3
  • 1
    I was more asking though why I'd use a switch on a string rather than a switch on an enum. I'd consider a large `if/else` block bad practice, but at the moment, I wouldn't have much reason to use one. – anotherdave Nov 16 '13 at 19:52
  • But then a Map in combination with the command pattern would even yield more readability with the same complexity because you have the extra type of the command – SpaceTrucker Nov 18 '13 at 07:43
3

Switch for strings could be used when your enum values come from outside, i.e. stored in a database.

Another notable thing in JDK 7 switch is that it's much more perfomant than if-else constructs.

And a nice use case for speedy string switches could be JSON/XML stream parsing when you need to make a lot of switches on node and attribute types. I can't think of any better option for this.

  • 1
    "Switch for strings is irreplaceable when your enum values come from outside, i.e. stored in a database.": Can you elaborate on this? The strings in the switch statement are hard-coded: as soon as the strings in the database get changed, your code is out of date. – Giorgio Nov 18 '13 at 08:30
  • Well, you are correct - `enum`s can be used in this case because of static nature of Java. When I was writing this, I was thinking about a `Role` from a security library which is usually provided as a class and cannot be put into `enum`. Another case is a dynamically compiled Java/Groovy code - in this situation, which is however rare, string switches might be a better option. – Andrey Chaschev Nov 18 '13 at 08:39
2

Simplicity

String in Switch support are useful for processing data without conversion to enum or if-else logic. Sometimes is just easier to switch on String.

From feature proposal at JDK 7 (project Coin) mailing list (@gnat answer)

introducing an enum for its switchable constants, one per string value of interest, would add another type to a program without good cause...

If-Else version

This is short, but many if's are hard to read. And this is slow.

if (color.equals("red")) {
    System.out.println("Color is Red");
} else if (color.equals("green")) {
    System.out.println("Color is Green");
} else {
    System.out.println("Color not found");
}

Enum version

Enums need to be defined, this is good, but sometime not needed.

enum Color {RED, GREEN}

Processing as usual

try {
    switch (Color.valueOf(color)) {
        case RED:
            System.out.println("Color is Red");
            break;
        case GREEN:
            System.out.println("Color is Green");
            break;
    }
} catch (IllegalArgumentException e) {
    System.out.println("Color not found");
}

JDK 7 - Strings in switch Statements version

We can process without converting and defining additional types.

switch (color) {
    case "red":
        System.out.println("Color is Red");
        break;
    case "green":
        System.out.println("Color is Green");
        break;
    default:
        System.out.println("Color not found");
}
0

Most improvements in any language are to make the code easier to read. I favor readable code over fancy any day.

You may not believe this but try:

public enum JettStaff {
  ADRIAN("Adrian German") {
    public String toString() {
      return name + " (dgerman@indiana.edu)";
    }
  },
  ARJIT("Arjit Sengupta") {
    public String toString() {
      return name + " (asengupt@indiana.edu)";
    }
  },

  // and on for the rest...

  private String name;

  public JettStaff(String n) { this.name = n; }
}

JettStaff x = JettStaff.SUZANNE;
System.out.println(x);
  • I'm unclear on your code example vs your comments above. Do you mean the Enum as an example of something that's difficult to read? – anotherdave Nov 16 '13 at 18:59
  • @anotherdave See http://stackoverflow.com/a/338230/2860598 –  Nov 16 '13 at 19:01
  • 2
    This is *very* contrived; you're pretending that the enum wouldn't have an email field, or that this wouldn't be a class. – Dave Newton Nov 16 '13 at 19:04
  • @DaveNewton Sometimes examples are just that, examples. –  Nov 16 '13 at 19:07
  • 4
    @user2860598 If you're trying to make a point, use an example that's relevant. It also doesn't address fat-fingering a string constant. – Dave Newton Nov 16 '13 at 19:08
  • 1
    @user2860598 The answer you linked is saying that there have been introduced & that previously they could be "approximated" with an Enum. My point was that the Enum use seems to be preferable still, even with their introduction. – anotherdave Nov 16 '13 at 19:29
0

Enums are great and you should use those instead of Strings when you have an ability to do so. But there are some times when you just couldn't, for example when you need to work with some external object coming from outside of Java. Imagine that you have to parse something. Like server response, configuration, log file or something similar: you have a bunch of options that you're looking for and there is no way those could be enums. So in Java < 7 you'd be stuck with a bunch of

  if (something.equals("foo")) {
    // foo processing
  } else 
  if (something.equals("bar")) {
   // bar processing
  }

You can still use enums in this case by just trying to get those by names and/or by providing custom String->Enum routine but sometimes it's not possible or just not practical (i.e. when you'd have to create too many enums)

TLDR: you absolutely should use Enums when you are working purely with Java code but it's not always possible with external objects. I hope my explanation makes sense.

  • If you're dealing with outside data, and you already know enough to know what you need in your `if` statements, then you should be wrapping it up *anyway*, which means you could still use enums, or a command pattern, etc. – Dave Newton Nov 16 '13 at 19:10
  • @DaveNewton yes, you can still use enums but as I stated in my answer, sometimes it's not practical like in case where you'd end up creating a hungded of enums only to be used once in your code during parsing. –  Nov 16 '13 at 19:13
  • @dimoniy But if you had to create 100s of Enum values, wouldn't that mean with a switch alternative you'd have to have 100s of case statements? If there are that many variables, I'd definitely prefer the type-safety of enums. – anotherdave Nov 16 '13 at 19:33
0

I don't agree with the opinion that it's cleaner and readable code when you use Strings in switch statements and think that it's a bad programming practice. If you change the value that you use to store, you have to change it every switch or if-elseif occurance. This is not good since you're putting hardcoded values to every bir of your code. What are you going to do if one day you decide to change one of these hard coded values? Search and replace every copy of it?

If you have some hardcoded values that you do if-elseif statements, using constant primitive values for them is much better in prior to Java 1.5 just because it brings type safety.

OK, there will be situations you'll get String values (from HTTP Request, files etc.) and converting them to the primitive values is a lof of pain. But Enums do a good job at this point. Because when you want to change the value you store in Enum, just change it when you declare. There is no need to change anything else in your code. (You of course need to change the values stored somewhere else).

Of couse if you're just implementing a dirty and lazy code, it's perfect. You don't want to involve to code lots of Enums, but in a big scale complex software that'll kill you.

-1

If you know what information coming in and that it could only be of 5 states then use an Enum. However if the possible states could be over 9000 and you only need to find 42, then using a switch is better because you don't want to be typing all those states out.

An Enum tends to be the choice by most in most circumstances unless where the possible states are unknown or there are a lot and you only care about a few.

But why they introduced it now? It was just a change that allowed for cleaner code.

In 1.5 they also allowed you to create custom bodies for Enums as well.

  • But would you not just assign the other 8958 possible values to the one Enum state? – anotherdave Nov 16 '13 at 19:36
  • @anotherdave This is where the `default` in `switch` comes in to play. I don't know that you can have a default state with `Enum`, unless you make a default state but then this code just gets bloated whereas a `switch` is much cleaner to use. –  Nov 16 '13 at 19:47
  • 3
    It seems strange to say that a `UNKNOWN` state on an Enum is bloat, but a `default` case on a switch isn't. – anotherdave Nov 16 '13 at 19:50