Home > OS >  Why isn't it possible to switch over class objects?
Why isn't it possible to switch over class objects?

Time:07-27

What would be the best way to switch over class-literals? Every class-instance exists only once and is an immutable constant but still, this seems to be not supported:

static void switchOnClass(Class<?> cls) {
    switch (cls) {
    case String.class -> System.out.println("String class");
    case Integer.class -> System.out.println("Integer class");
    default -> System.out.println("Unknown");
    }
}

CodePudding user response:

To answer my own question: The use case seems to be not common enough, that this feature is supported. Currently (as of Java 18) a switch-case-statement supports switching over literals:

  • primitive types
  • their wrapper classes
  • enum constants
  • String literals

It can utilize (exhaustive) pattern-matching like the instanceof operator, and as of Java 19 it will support record-pattern-matching which will maybe get extended by the following:

Future Work

There are many directions in which the record patterns described here could be extended:

  • Array patterns, whose subpatterns match individual array elements;
  • Varargs patterns, when the record is a varargs record;
  • Inference for type arguments in generic record patterns, possibly using a diamond form (<>);
  • Do-not-care patterns, which can appear as an element in a record component pattern list but do not declare a pattern variable; and
  • Patterns based upon arbitrary classes rather than only record classes.

But currently it seems the best way to switch over classes would be, like @Davide pointed out, to use a uniquely identifieable, human-readable attribute, like their name/path. Which in itself would be restricted by anonymous, hidden, and local classes.

CodePudding user response:

It is not possible because is not part of the language.

As explained here on the oracle documentation:

A switch works with the byte, short, char, and int primitive data types. It also works with enumerated types (discussed in Enum Types), the String class, and a few special classes that wrap certain primitive types: Character, Byte, Short, and Integer (discussed in Numbers and Strings).

Java is evolving through the years. The old versionsthe of switch doesn't allow to use the String as parameter of the switch. May be thatin a newer version of java this functionality will be added, but for what I know at the moment it is not planned.


If you plan to use classes as business object of the switch you can use their full names and use the switch over strings

 switch (myObject.getClass().getCanonicalName()) {
     case "myFullClassName": ...
     case "myOtherFullClassName": ...

 }

CodePudding user response:

There are two answers:

  1. Because nobody on the Java team has been sufficiently motivated to propose switch for a broader range of types. (Use-cases are uncommon ...)

  2. Because there is a significant technical issue ...

The thing is that a switch statement needs the values in the cases to be compile time constant expressions. This is necessary because the compiler has to be able to check that the values in different cases are distinct. We can't have something like this:

int A = 1;
int B = 1;
switch (foo) {
    case A:  doSomething(); break;
    case B:  doSomethingElse(); break;
}

The compile time checks work for integer and String values (that are results of constant expressions) and enum names because these types have models of equality1 that will give the same answer at compile time and runtime.

Unfortunately, this doesn't generalize to other reference types:

  • On the one hand, == would most likely be too difficult to use in practice.

  • On the other hand, it would not be possible for the compiler to perform a compile time check that the case values are pair-wise not equals to each other.

Even class literals (e.g. Foo.class) are problematic2. It turns out that if the same class is loaded by two different class loaders, you can get two distinct Class objects. And they are NOT equal according to either == or equals. They could probably come up with a semantic that was amenable to a compile time check. But the runtime semantics would have a nasty gotcha in the above scenario.


1 - Note that the equality model for switch statements /expressions using String is equals, not ==.
2 - I don't know if the Java language designers actually considered supporting switch for Class values, but I can understand why they haven't done it yet.

  • Related