Before I start, I know there are a bunch of answers to this question that suggest alternate approaches. I\'m looking for assistance to this particular approach as to whethe
Here's an example of this which uses a simple object for each case.
package mcve.util;
import java.util.*;
import java.util.function.*;
/**
* Allows switch-like statements with classes and consumers.
*/
public final class ClassSwitch implements Consumer
A usage example would be something like this, assuming imports of e.g. import static mcve.util.ClassSwitch.*;:
cswitch(anObject,
ccase(Byte.class, b -> System.out.println("Byte")),
ccase(Short.class, s -> System.out.println("Short")),
ccase(Integer.class, i -> System.out.println("Integer")),
ccase(Long.class, l -> System.out.println("Long")),
ccase(Float.class, f -> System.out.println("Float")),
ccase(Double.class, d -> System.out.println("Double"))
);
You could also create a reusable object:
ClassSwitch ts =
new ClassSwitch(ccase(String.class, System.out::println),
ccase(Double.class, System.out::println));
ts.accept(anObject);
Notes:
If you want a default case, you can use Object.class as the last case.
There's no way to make a case which handles null, but it could be modified a little bit for that. You could e.g. make a class NullCase whose test method returns obj == null.
What you could also do is actually generate overloads instead of using varargs. This lets you associate classes with consumers using just generic method declarations. The following is a fairly simple example of this:
package mcve.util;
import java.util.*;
import java.util.function.*;
/**
* Allows switch-like statements with classes and consumers.
*/
public final class GeneratedClassSwitch {
private GeneratedClassSwitch() {}
/**
* Generates overloads for a class switch to System.out.
*
* For example, if max=4, then 5 methods are generated:
* with 0, 1, 2, 3, and 4 cases.
*
* @param max
* the number of cases in the largest overload generated
* @param indents
* the number of indents to indent each generated method
* @throws IllegalArgumentException
* if max is negative or greater than 26, or if indents
* is negative
*/
public static void generateFixedOverloads(int max, int indents) {
if (max < 0 || max > 26) {
throw new IllegalArgumentException("max=" + max);
}
String indent = String.join("", Collections.nCopies(indents, " "));
for (int i = 0; i <= max; ++i) {
System.out.print(indent);
System.out.print("public static ");
if (i > 0) {
System.out.print("<");
for (char ch = 'A'; ch < 'A' + i; ++ch) {
if (ch != 'A') {
System.out.print(", ");
}
System.out.print(ch);
}
System.out.print("> ");
}
System.out.print("void cswitch");
if (i > 0) {
System.out.println();
System.out.print(indent + " (Object o, ");
for (char ch = 'A'; ch < 'A' + i; ++ch) {
if (ch != 'A') {
System.out.println(",");
System.out.print(indent + " ");
}
System.out.print("Class<" + ch + "> class" + ch);
System.out.print(", Consumer super " + ch + "> action" + ch);
}
} else {
System.out.print("(Object o");
}
System.out.println(") {");
for (char ch = 'A'; ch < 'A' + i; ++ch) {
if (ch == 'A') {
System.out.print(indent + " ");
} else {
System.out.print(" else ");
}
System.out.println("if (class" + ch + ".isInstance(o)) {");
System.out.print(indent + " ");
System.out.println("action" + ch + ".accept(class" + ch + ".cast(o));");
System.out.print(indent + " ");
System.out.print("}");
if (ch == ('A' + i - 1)) {
System.out.println();
}
}
System.out.print(indent);
System.out.println("}");
}
}
// Generated code pasted below.
public static void cswitch(Object o) {
}
public static void cswitch
(Object o, Class classA, Consumer super A> actionA) {
if (classA.isInstance(o)) {
actionA.accept(classA.cast(o));
}
}
public static void cswitch
(Object o, Class classA, Consumer super A> actionA,
Class classB, Consumer super B> actionB) {
if (classA.isInstance(o)) {
actionA.accept(classA.cast(o));
} else if (classB.isInstance(o)) {
actionB.accept(classB.cast(o));
}
}
public static void cswitch
(Object o, Class classA, Consumer super A> actionA,
Class classB, Consumer super B> actionB,
Class classC, Consumer super C> actionC) {
if (classA.isInstance(o)) {
actionA.accept(classA.cast(o));
} else if (classB.isInstance(o)) {
actionB.accept(classB.cast(o));
} else if (classC.isInstance(o)) {
actionC.accept(classC.cast(o));
}
}
public static void cswitch
(Object o, Class classA, Consumer super A> actionA,
Class classB, Consumer super B> actionB,
Class classC, Consumer super C> actionC,
Class classD, Consumer super D> actionD) {
if (classA.isInstance(o)) {
actionA.accept(classA.cast(o));
} else if (classB.isInstance(o)) {
actionB.accept(classB.cast(o));
} else if (classC.isInstance(o)) {
actionC.accept(classC.cast(o));
} else if (classD.isInstance(o)) {
actionD.accept(classD.cast(o));
}
}
public static void cswitch
(Object o, Class classA, Consumer super A> actionA,
Class classB, Consumer super B> actionB,
Class classC, Consumer super C> actionC,
Class classD, Consumer super D> actionD,
Class classE, Consumer super E> actionE) {
if (classA.isInstance(o)) {
actionA.accept(classA.cast(o));
} else if (classB.isInstance(o)) {
actionB.accept(classB.cast(o));
} else if (classC.isInstance(o)) {
actionC.accept(classC.cast(o));
} else if (classD.isInstance(o)) {
actionD.accept(classD.cast(o));
} else if (classE.isInstance(o)) {
actionE.accept(classE.cast(o));
}
}
public static void cswitch
(Object o, Class classA, Consumer super A> actionA,
Class classB, Consumer super B> actionB,
Class classC, Consumer super C> actionC,
Class classD, Consumer super D> actionD,
Class classE, Consumer super E> actionE,
Class classF, Consumer super F> actionF) {
if (classA.isInstance(o)) {
actionA.accept(classA.cast(o));
} else if (classB.isInstance(o)) {
actionB.accept(classB.cast(o));
} else if (classC.isInstance(o)) {
actionC.accept(classC.cast(o));
} else if (classD.isInstance(o)) {
actionD.accept(classD.cast(o));
} else if (classE.isInstance(o)) {
actionE.accept(classE.cast(o));
} else if (classF.isInstance(o)) {
actionF.accept(classF.cast(o));
}
}
public static void cswitch
(Object o, Class classA, Consumer super A> actionA,
Class classB, Consumer super B> actionB,
Class classC, Consumer super C> actionC,
Class classD, Consumer super D> actionD,
Class classE, Consumer super E> actionE,
Class classF, Consumer super F> actionF,
Class classG, Consumer super G> actionG) {
if (classA.isInstance(o)) {
actionA.accept(classA.cast(o));
} else if (classB.isInstance(o)) {
actionB.accept(classB.cast(o));
} else if (classC.isInstance(o)) {
actionC.accept(classC.cast(o));
} else if (classD.isInstance(o)) {
actionD.accept(classD.cast(o));
} else if (classE.isInstance(o)) {
actionE.accept(classE.cast(o));
} else if (classF.isInstance(o)) {
actionF.accept(classF.cast(o));
} else if (classG.isInstance(o)) {
actionG.accept(classG.cast(o));
}
}
public static void cswitch
(Object o, Class classA, Consumer super A> actionA,
Class classB, Consumer super B> actionB,
Class classC, Consumer super C> actionC,
Class classD, Consumer super D> actionD,
Class classE, Consumer super E> actionE,
Class classF, Consumer super F> actionF,
Class classG, Consumer super G> actionG,
Class classH, Consumer super H> actionH) {
if (classA.isInstance(o)) {
actionA.accept(classA.cast(o));
} else if (classB.isInstance(o)) {
actionB.accept(classB.cast(o));
} else if (classC.isInstance(o)) {
actionC.accept(classC.cast(o));
} else if (classD.isInstance(o)) {
actionD.accept(classD.cast(o));
} else if (classE.isInstance(o)) {
actionE.accept(classE.cast(o));
} else if (classF.isInstance(o)) {
actionF.accept(classF.cast(o));
} else if (classG.isInstance(o)) {
actionG.accept(classG.cast(o));
} else if (classH.isInstance(o)) {
actionH.accept(classH.cast(o));
}
}
}
If you want to generate overloads, for example to have more than 8 cases, you can say something like the following:
GeneratedClassSwitch.generateFixedOverloads(16, 1);
That will generate methods to System.out that follow the general form of:
public static void cswitch
(Object o, Class classA, Consumer super A> actionA,
Class classB, Consumer super B> actionB,
Class classC, Consumer super C> actionC) {
if (classA.isInstance(o)) {
actionA.accept(classA.cast(o));
} else if (classB.isInstance(o)) {
actionB.accept(classB.cast(o));
} else if (classC.isInstance(o)) {
actionC.accept(classC.cast(o));
}
}
Notice that we're able to map each class type to its associated consumer type, i.e.
Class<A> with Consumer super A>, Class<B> with Consumer super B>, and so on. This is actually impossible with varargs (as of the current version of Java, anyway, which is 10).
Our usage example is now like this, again assuming imports of e.g. import static mcve.util.GeneratedClassSwitch.*;:
cswitch(anObject,
Byte.class, b -> System.out.println("Byte"),
Short.class, s -> System.out.println("Short"),
Integer.class, i -> System.out.println("Integer"),
Long.class, l -> System.out.println("Long"),
Float.class, f -> System.out.println("Float"),
Double.class, d -> System.out.println("Double")
);
(Notes about default cases and null are the same as the first example.)