Java refactoring interlinked switch/if statement with polymorphism - java

I am aware of how to replace a switch statement through polymorphism, like it is explained for instance here.
In my case however I have two Enum:
public enum EleType {
INTEGER,
CHARACTER
}
and
public enum SorterType {
BUBBLE,
INSERTION
}
and the switch/if I would like to refactor has the structure:
if ( eleType == EleType.INTEGER ) {
switch ( sorterType ) {
case BUBBLE:
composition = new SorterComposition<Integer>(new BubbleSort<Integer>(), randomList);
break;
case INSERTION:
composition = new SorterComposition<Integer>(new InsertionSort<Integer>(), randomList);
break;
}
} else if ( eleType == EleType.CHARACTER ) {
switch ( sorterType ) {
case BUBBLE:
composition = new SorterComposition<Character>(new BubbleSort<Character>(), randomList);
break;
case INSERTION:
composition = new SorterComposition<Character>(new InsertionSort<Character>(), randomList);
break;
}
}
Because both enum appear together and both affect the SorterComposition part, I am unsure how to refactor this structure. Also I am unsure how to get the "Integer"/"Character" generic types from EleType.INTEGER or EleType.CHARACTER respectively without using conditional statements.

Do you mean that you implement the code like this?
public static <T> SorterComposition<T> createComposition(SorterType type, <Type of randomList>) {
switch (type) {
case BUBBLE:
return new SorterComposition<T>(new BubbleSort<T>(), randomList);
case INSERTION:
return new SorterComposition<T>(new InsertionSort<T>(), randomList);
default:
throw <Exception>
}
}
Or, you can change the EleType class a little bit.
public enum EleType {
INTEGER(Integer.class), CHARACTER(Character.class);
private EleType(Class cl) { this.classType = cl; }
public Class getClassType() { return classType; }
private final Class classType;
}
and use this code instead of the createComposition above.
public static <T> SorterComposition<T> createComposition(Class<T> eleType, SorterType type, <Type of randomList>) {
switch (type) {
case BUBBLE:
return new SorterComposition<T>(new BubbleSort<T>(), randomList);
case INSERTION:
return new SorterComposition<T>(new InsertionSort<T>(), randomList);
default:
throw <Exception>
}
}
and when you use it, use composition = createComposition(eleType.getClassType(), sorterType, randomList);
To avoid switch of SorterType in a gentle way, maybe you can use in add a Supplier field into SorterType.
public enum SorterType {
BUBBLE(() -> new BubbleSort()),
INSERTION(() -> new InsertionSort());
private SorterType(Supplier<Sort> supplier) {
this.supplier = supplier;
}
public Sort getSort() {
return supplier.get();
}
private final Supplier<Sort> supplier;
}

You could use double dispatch. I have provided a skeleton implementation below.
However some consider double dispatch a code smell. In this instance your EleType seems suspect to me. All you are doing with it in this example is use it for your generic type declaration.
public enum EleType {
INTEGER {
SorterComposition getSorter(SorterType s) {
return s.getIntegerSorter();
}
},
CHARACTER{
SorterComposition getSorter(SorterType s) {
return s.getChracterSorter();
}
};
abstract SorterComposition getSorter(SorterType s);
};
public enum SorterType {
BUBBLE {
SorterComposition getIntegerSorter() {return new BubbleSort<Integer>();}
SorterComposition getChracterSorter() {return new BubbleSort<Character>();}
},
INSERTION{
SorterComposition getIntegerSorter() {return new InsertionSort<Integer>();}
SorterComposition getChracterSorter() {return new InsertionSort<Character>();}
};
abstract SorterComposition getIntegerSorter();
abstract SorterComposition getChracterSorter();
};

Related

How do I dynamically create a common proxy class of two unrelated classes?

I have two unrelated java classes (only *.class, no *.java) like this:
public class Trick {
public String getName() { return "Jack"; }
public String trick() { ... }
}
and
public class Treat {
public String getName() { return "John"; }
public String treat() { ... }
}
and I would like to generate a sort of Proxy class at runtime that represents the union of both classes and forwards them to the respective instance, and maybe throw if that's not possible. I assume that can be done with cglib but I don't know where to start.
This is what I would like to do (pseudocode):
// prepare: generate a common interface
TrickOrTreat trickOrTreat = magic.createUnionInterface(Trick.class, Treat.class);
// use with concrete interface A:
Trick trick = new Trick();
TrickOrTreat proxyA = magic.createProxy(trickOrTreat.class, trick);
System.out.println("trick name: " + proxyA.getName());
// use with concrete interface B:
Treat treat = new Treat();
TrickOrTreat proxyB = magic.createProxy(trickOrTreat.class, treat);
System.out.println("treat name: " + proxyB.getName());
Or something to that effect. I would like to do it completely dynamically, probably cglib-based? If thats not possible I would do it with a code generation step in between?
If you are willing to trade in cglib, you can do this with Byte Buddy. I typically refuse to call it magic but here you go:
class Magic {
Class<?> createUnionInterface(Class<?> a, Class<?> b) {
DynamicType.Builder<?> builder = new ByteBuddy().makeInterface();
Set<MethodDescription.SignatureToken> tokens = new HashSet<>();
for (MethodDescription m : new TypeDescription.ForLoadedType(a)
.getDeclaredMethods()
.filter(ElementMatchers.isVirtual())) {
tokens.add(m.asSignatureToken());
builder = builder.defineMethod(m.getName(),
m.getReturnType(),
m.getModifiers()).withoutCode();
}
for (MethodDescription m : new TypeDescription.ForLoadedType(b)
.getDeclaredMethods()
.filter(ElementMatchers.isVirtual())) {
if (!tokens.contains(m.asSignatureToken())) {
builder = builder.defineMethod(m.getName(),
m.getReturnType(),
m.getModifiers()).withoutCode();
}
}
return builder.make()
.load(Magic.class.getClassLoader())
.getLoaded();
}
Object createProxy(Class<?> m, final Object delegate) throws Exception {
return new ByteBuddy()
.subclass(m)
.method(new ElementMatcher<MethodDescription>() {
#Override
public boolean matches(MethodDescription target) {
for (Method method : delegate.getClass()
.getDeclaredMethods()) {
if (new MethodDescription.ForLoadedMethod(method)
.asSignatureToken()
.equals(target.asSignatureToken())) {
return true;
}
}
return false;
}
}).intercept(MethodDelegation.to(delegate))
.make()
.load(Magic.class.getClassLoader())
.getLoaded()
.newInstance();
}
}
Note that you cannot reference a runtime-generated type at compile-time. This is however a given constraint with runtime code generation.
Magic magic = new Magic();
Class<?> trickOrTreat = magic.createUnionInterface(Trick.class, Treat.class);
Trick trick = new Trick();
Object proxyA = magic.createProxy(trickOrTreat, trick);
System.out.println("trick name: " + trickOrTreat.getDeclaredMethod("getName").invoke(proxyA));
Treat treat = new Treat();
Object proxyB = magic.createProxy(trickOrTreat, treat);
System.out.println("trick name: " + trickOrTreat.getDeclaredMethod("getName").invoke(proxyB));
You can overcome this by generating your TrickOrTreat class prior to runtime such that you can reference the type at runtime.
As for the suggested union-type approach, this would require you to have at least one class to be an interface type as Java does not support multiple inheritance.
If you need functionality of both classes/interfaces you can use
public <TT extends Trick & Treat> void process(TT thing){
//...
}
edit:
Implement new Interface MyProxyHandler
public interface MyProxyHandler {}
Extend it with interfaces of classes say TreatInterface and TrickInterface
Create class ProxyManager that implements java.lang.reflect.InvocationHandler
public abstract class ProxyManager<T extends MyProxyHandler> implements InvocationHandler {
protected static String LOCK_OBJECT = new String("LOCK");
protected T proxyHandler;
protected List<T> handlers = new ArrayList<>();
#SuppressWarnings("unchecked")
public ProxyManager(Class<T> _clazz) {
proxyHandler = (T) Proxy.newProxyInstance(_clazz.getClassLoader(), new Class[]{_clazz}, this);
}
public T getProxy() {
return proxyHandler;
}
public List<T> getHandlers() {
return handlers;
}
public void setHandlers(List<T> handlers) {
this.handlers = handlers;
}
public boolean registerHandler(T handler) {
synchronized (LOCK_OBJECT) {
boolean add = true;
for (T item : this.handlers) {
if (item.getClass().equals(handler.getClass())) {
add = false;
}
}
if (add)
this.handlers.add(handler);
return add;
}
}
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String result = "";
for (MyProxyHandler handler : getHandlers()) {
try {
//I recommend that methods returns some enum like HANDLED/NOTHANDLED
result = (String) method.invoke(handler, args);
if (result.equals("Some flag"))
break;
} catch (InvocationTargetException e) {
throw e.getCause();
}
}
return result;
}
}
Extend that class with your concrete class
public class TreatTrickProxyManager<T extends TreatInterface & TreatInterface> extends ProxyManager<T> {
public TreatTrickProxyManager(Class<T> _clazz) {
super(_clazz);
}
}
In your bussines logic class get an instance of TreatTrickProxyManager
In your method
public void retrieveSomeData(){
((TreatTrickProxyManager)getTreatTrickProxyManager().getProxy()).someMethodInvocation()
}

Set enum values

I have a enum class that has values A,B. Here is the class:
#XmlType(name = "MemberType")
#XmlEnum
public enum MemberType {
A,
B;
public String value() {
return name();
}
public static MemberType fromValue(String v) {
return valueOf(v);
}
}
I have another enum class similar to this one that has the same values A, and B. This class is generated from my WSDL, and I have no control over its code. What I basically want to do is, equate the two enum values.
Basically say MemberType.A = WSDLClass.A, something like that. What can I try next?
While you cannot assign one enum type to a different type (and you can't have enum extend some abstract superclass), you can declare a static method (either in MemberType or in some utility class), mapping from WSDLClass to MemberType:
public static MemberType fromWsdl(WSDLClass w) {
if (w==null) {
return null;
} else {
switch (w) {
case WSDLClass.A: return MemberType.A;
case WSDLClass.B: return MemberType.B;
default: return null;
}
}
}
Then you would use that function as follow:
import static xyz.MemberType.fromWsdl;
...
MemberType m = ...;
WSDLClass w = ...;
if (m.equals(fromWsdl(w))) ...
If the names are strictly the same, I suppose you can :
private MemberType convertEnum(WSDLClass type) {
return Enum.valueOf(MemberType.class, type.name());
}
If the names are not strictly the same or could differ in the future you are going to have to do :
private MemberType convertEnum(WSDLClass type) {
MemberType memberType;
switch (type) {
case A:
memberType = MemberType.A;
break;
case B:
memberType = MemberType.B;
break;
default:
memberType = null;
break;
}
return memberType;
}
If you want to use the first solution but the fact that it throw NullPointerException if type is null bother you can use EnumUtils from Apache Commons Lang.

Switch in elegant way in java 1.6 for string

I'm using java 1.6 and i know that from java 1.7 there is option to switch on string
but here i use the if/elseif to route type name,my question if there is a elegant way
that i can change it to switch Yet
public static SwitchType<?> switchT(final String typeName,
final String memberName) {
if (typeName.equals("java.lang.String")) {
return new SwitchInputType<String>(new String(memberName + " "));
} else if (typeName.equals("char")) {
return new SwitchInputType<Character>(new Character('a'));
} else if (typeName.equals("decimal") ||
typeName.equals("java.math.BigDecimal")) {
return new SwitchInputType<BigDecimal>(new BigDecimal("34.58"));
} else if (typeName.equals("boolean")) {
}
You could use a Map<String, SwitchTypeFactory>:
public interface SwitchTypeFactory {
SwitchType<?> create(String memberName);
}
...
private static Map<String, SwitchTypeFactory> factories = new HashMap<String, SwitchTypeFactory>();
static {
factories.put("java.lang.String", new SwitchTypeFactory() {
#Override
public SwitchType<?> create(String memberName) {
return new SwitchInputType<String>(memberName + " ");
}
});
factories.put("char", new SwitchTypeFactory() {
#Override
public SwitchType<?> create(String memberName) {
return new SwitchInputType<Character>(Character.valueOf('a'))
}
});
...
}
public static SwitchType<?> switchT(final String typeName, final String memberName) {
return factories.get(typeName).create(memberName);
}
Many patterns are available, from the use of an enumeration to the use of a Map<String,Implementation> but none of them will be more concise nor faster that what you have in this precise case. They would only make sense if more code was dependent of this typeName.
Although it might be a little counter intuitive using enum has proven quite powerful in that regard.
Every enum has a valueOf(String) method that returns an Element for that name. Then you may use the retrieved Element in a switch statement. The only ugly part is that valueOf(String) throws an IllegalArgumentException. So catching that is equivalent to a default case.
enum Type{
JAVA_LANG_STRING;
CHAR;
DECIMAL;
BOOLEAN;
JAVA_LANG_BIGDECIMAL;
}
public static SwitchType<?> switchT(final String typeName,
final String memberName) {
try{
Type t = Type.valueOf(typeName.toUppercase().replace(".","_"));
switch(t){
case Type.JAVA_LANG_STRING: return new SwitchInputType<String>(new String(memberName + " "));
case Type.CHAR: return new SwitchInputType<Character>(new Character('a'));
case Type.DECIMAL:
case Type.JAVA_MATH_BIGDECIMAL: return new SwitchInputType<BigDecimal>(new BigDecimal("34.58"));
}catch(IllegalArgumentException e){
//default case
}
}
Also enums may implement interfaces. Either by providing one implementation for each element or one global one.
interface SwitchInputTypeFacotry {
SwitchInputType get(String arg);
}
enum TypeName implements SwitchInputTypeFacotry{
CHAR{
SwitchInputType get(String arg){
return new SwitchInputType<Character>(new Character('a'));
}
}
[...]
}
public static SwitchType<?> switchT(final String typeName,
final String memberName) {
try{
SwitchInputTypeFacotry t = Type.valueOf(typeName.toUppercase().replace(".","_"));
return t.get(memberName);
}catch(IllegalArgumentException e){
//default case
}
}
The second way makes it very easy to extend functionality (as long as it stays in one module, subclassing is not possible with enums).

Is it possible to use the instanceof operator in a switch statement?

I have a question of using switch case for instanceof object:
For example: my problem can be reproduced in Java:
if(this instanceof A)
doA();
else if(this instanceof B)
doB();
else if(this instanceof C)
doC():
How would it be implemented using switch...case?
This is a typical scenario where subtype polymorphism helps. Do the following
interface I {
void do();
}
class A implements I { void do() { doA() } ... }
class B implements I { void do() { doB() } ... }
class C implements I { void do() { doC() } ... }
Then you can simply call do() on this.
If you are not free to change A, B, and C, you could apply the visitor pattern to achieve the same.
if you absolutely cannot code to an interface, then you could use an enum as an intermediary:
public A() {
CLAZZ z = CLAZZ.valueOf(this.getClass().getSimpleName());
switch (z) {
case A:
doA();
break;
case B:
doB();
break;
case C:
doC();
break;
}
}
enum CLAZZ {
A,B,C;
}
Create a Map where the key is Class<?> and the value is an expression (lambda or similar). Consider:
Map<Class,Runnable> doByClass = new HashMap<>();
doByClass.put(Foo.class, () -> doAClosure(this));
doByClass.put(Bar.class, this::doBMethod);
doByClass.put(Baz.class, new MyCRunnable());
// of course, refactor this to only initialize once
doByClass.get(getClass()).run();
If you need checked exceptions than implement a FunctionalInterface that throws the Exception and use that instead of Runnable.
Here's a real-word before-and-after showing how this approach can simplify code.
The code before refactoring to a map:
private Object unmarshall(
final Property<?> property, final Object configValue ) {
final Object result;
final String value = configValue.toString();
if( property instanceof SimpleDoubleProperty ) {
result = Double.parseDouble( value );
}
else if( property instanceof SimpleFloatProperty ) {
result = Float.parseFloat( value );
}
else if( property instanceof SimpleBooleanProperty ) {
result = Boolean.parseBoolean( value );
}
else if( property instanceof SimpleFileProperty ) {
result = new File( value );
}
else {
result = value;
}
return result;
}
The code after refactoring to a map:
private final Map<Class<?>, Function<String, Object>> UNMARSHALL =
Map.of(
SimpleBooleanProperty.class, Boolean::parseBoolean,
SimpleDoubleProperty.class, Double::parseDouble,
SimpleFloatProperty.class, Float::parseFloat,
SimpleFileProperty.class, File::new
);
private Object unmarshall(
final Property<?> property, final Object configValue ) {
return UNMARSHALL
.getOrDefault( property.getClass(), ( v ) -> v )
.apply( configValue.toString() );
}
This avoids repetition, eliminates nearly all branching statements, and simplifies maintenance.
Java now allows you to switch in the manner of the OP. They call it Pattern Matching for switch. It was released as a preview feature of Java 17. The example given in the JEP is
String formatted;
switch (obj) {
case Integer i : formatted = String.format ( "int %d", i); break;
case Byte b : formatted = String.format ( "byte %d", b); break;
case Long l : formatted = String.format ( "long %d", l); break;
case Double d : formatted = String.format ( "double %f", d); break;
case String s : formatted = String.format ( "String %s", s); break
default: formatted = obj.toString();
}
or using their lambda syntax and returning a value
String formatted = switch (obj) {
case Integer i -> String.format ( "int %d", i )
case Byte b -> String.format ( "byte %d", b );
case Long l -> String.format ( "long %d", l );
case Double d -> String.format ( "double %f", d );
case String s -> String.format ( "String %s", s );
default -> obj.toString();
};
either way they've been doing cool stuff with switches.
Just in case if someone will read it:
The BEST solution in java is :
public enum Action {
a{
void doAction(...){
// some code
}
},
b{
void doAction(...){
// some code
}
},
c{
void doAction(...){
// some code
}
};
abstract void doAction (...);
}
The GREAT benefits of such pattern are:
You just do it like (NO switches at all):
void someFunction ( Action action ) {
action.doAction(...);
}
In case if you add new Action called "d" you MUST imlement doAction(...) method
NOTE: This pattern is described in Joshua's Bloch "Effective Java (2nd Edition)"
You can't. The switch statement can only contain case statements which are compile time constants and which evaluate to an integer (Up to Java 6 and a string in Java 7).
What you are looking for is called "pattern matching" in functional programming.
See also Avoiding instanceof in Java
As discussed in the top answers, the traditional OOP approach is to use polymorphism instead of switch. There is even a well documented refactoring pattern for this trick: Replace Conditional with Polymorphism. Whenever I reach for this approach, I like to also implement a Null object to provide the default behaviour.
Starting with Java 8, we can use lambdas and generics to give us something functional programmers are very familiar with: pattern matching. It's not a core language feature but the VAVR Library - formerly Javaslang library provides one implementation. Example from the docs:
Match.ofType(Number.class)
.caze((Integer i) -> i)
.caze((String s) -> new BigDecimal(s))
.orElse(() -> -1)
.apply(1.0d); // result: -1
It's not the most natural paradigm in the Java world so use it with caution. While the generic methods will save you from having to typecast the matched value, we're missing a standard way to decompose the matched object as with Scala's case classes for example.
Unfortunately, it is not possible out of the box since the switch-case statement expects a constant expression. To overcome this, one way would be to use enum values with the class names e.g.
public enum MyEnum {
A(A.class.getName()),
B(B.class.getName()),
C(C.class.getName());
private String refClassname;
private static final Map<String, MyEnum> ENUM_MAP;
MyEnum (String refClassname) {
this.refClassname = refClassname;
}
static {
Map<String, MyEnum> map = new ConcurrentHashMap<String, MyEnum>();
for (MyEnum instance : MyEnum.values()) {
map.put(instance.refClassname, instance);
}
ENUM_MAP = Collections.unmodifiableMap(map);
}
public static MyEnum get(String name) {
return ENUM_MAP.get(name);
}
}
With that is is possible to use the switch statement like this
MyEnum type = MyEnum.get(clazz.getName());
switch (type) {
case A:
... // it's A class
case B:
... // it's B class
case C:
... // it's C class
}
I know this is very late but for future readers ...
Beware of the approaches above that are based only on the name of the class of A, B, C ... :
Unless you can guarantee that A, B, C ... (all subclasses or implementers of Base) are final then subclasses of A, B, C ... will not be dealt with.
Even though the if, elseif, elseif .. approach is slower for large number of subclasses/implementers, it is more accurate.
java 7+
public <T> T process(Object model) {
switch (model.getClass().getSimpleName()) {
case "Trade":
return processTrade((Trade) model);
case "InsuranceTransaction":
return processInsuranceTransaction((InsuranceTransaction) model);
case "CashTransaction":
return processCashTransaction((CashTransaction) model);
case "CardTransaction":
return processCardTransaction((CardTransaction) model);
case "TransferTransaction":
return processTransferTransaction((TransferTransaction) model);
case "ClientAccount":
return processAccount((ClientAccount) model);
...
default:
throw new IllegalArgumentException(model.getClass().getSimpleName());
}
}
You can be even faster by for omitting string manipulation inside getSimpleName by for introducing constants and using full class name:
public static final TRADE = Trade.class.getName();
...
switch (model.getClass().getName()) {
case TRADE:
Nope, there is no way to do this. What you might want to do is however to consider Polymorphism as a way to handle these kind of problems.
Using switch statements like this is not the object oriented way. You should instead use the power of polymorphism. Simply write
this.do()
Having previously set up a base class:
abstract class Base {
abstract void do();
...
}
which is the base class for A, B and C:
class A extends Base {
void do() { this.doA() }
}
class B extends Base {
void do() { this.doB() }
}
class C extends Base {
void do() { this.doC() }
}
You can't a switch only works with the byte, short, char, int, String and enumerated types (and the object versions of the primitives, it also depends on your java version, Strings can be switched on in java 7)
I personally like the following Java 1.8 code:
mySwitch("YY")
.myCase("AA", (o) -> {
System.out.println(o+"aa");
})
.myCase("BB", (o) -> {
System.out.println(o+"bb");
})
.myCase("YY", (o) -> {
System.out.println(o+"yy");
})
.myCase("ZZ", (o) -> {
System.out.println(o+"zz");
});
Will output:
YYyy
The sample code uses Strings but you can use any object type, including Class. e.g. .myCase(this.getClass(), (o) -> ...
Needs the following snippet:
public Case mySwitch(Object reference) {
return new Case(reference);
}
public class Case {
private Object reference;
public Case(Object reference) {
this.reference = reference;
}
public Case myCase(Object b, OnMatchDo task) {
if (reference.equals(b)) {
task.task(reference);
}
return this;
}
}
public interface OnMatchDo {
public void task(Object o);
}
If you can manipulate the common interface, you could do add in an enum and have each class return a unique value. You won't need instanceof or a visitor pattern.
For me, the logic needed to be in the written in the switch statement, not the object itself. This was my solution:
ClassA, ClassB, and ClassC implement CommonClass
Interface:
public interface CommonClass {
MyEnum getEnumType();
}
Enum:
public enum MyEnum {
ClassA(0), ClassB(1), ClassC(2);
private int value;
private MyEnum(final int value) {
this.value = value;
}
public int getValue() {
return value;
}
Impl:
...
switch(obj.getEnumType())
{
case MyEnum.ClassA:
ClassA classA = (ClassA) obj;
break;
case MyEnum.ClassB:
ClassB classB = (ClassB) obj;
break;
case MyEnum.ClassC:
ClassC classC = (ClassC) obj;
break;
}
...
If you are on java 7, you can put string values for the enum and the switch case block will still work.
How about this ?
switch (this.name)
{
case "A":
doA();
break;
case "B":
doB();
break;
case "C":
doC();
break;
default:
console.log('Undefined instance');
}
I think there are reasons to use a switch statement. If you are using xText generated Code perhaps. Or another kind of EMF generated classes.
instance.getClass().getName();
returns a String of the Class Implementation Name. i.e:
org.eclipse.emf.ecore.util.EcoreUtil
instance.getClass().getSimpleName();
returns the simple represenation i.e:
EcoreUtil
If you need to "switch" thru the class type of "this" object, this answer is the best https://stackoverflow.com/a/5579385/2078368
But if you need to apply "switch" to any other variable. I would suggest another solution. Define following interface:
public interface ClassTypeInterface {
public String getType();
}
Implement this interface in every class you want to "switch". Example:
public class A extends Something implements ClassTypeInterface {
public final static String TYPE = "A";
#Override
public String getType() {
return TYPE;
}
}
After that you can use it in following way:
switch (var.getType()) {
case A.TYPE: {
break;
}
case B.TYPE: {
break;
}
...
}
The only thing you should care about - keep the "types" unique across all the classes implementing the ClassTypeInterface. It's not a big problem, because in case of any intersection you receive a compile-time error for the "switch-case" statement.
Create an Enum with Class names.
public enum ClassNameEnum {
A, B, C
}
Find the Class name of the object.
Write a switch case over the enum.
private void switchByClassType(Object obj) {
ClassNameEnum className = ClassNameEnum.valueOf(obj.getClass().getSimpleName());
switch (className) {
case A:
doA();
break;
case B:
doB();
break;
case C:
doC();
break;
}
}
}
Hope this helps.
Here's a functional way of accomplishing it in Java 8 using http://www.vavr.io/
import static io.vavr.API.*;
import static io.vavr.Predicates.instanceOf;
public Throwable liftRootCause(final Throwable throwable) {
return Match(throwable).of(
Case($(instanceOf(CompletionException.class)), Throwable::getCause),
Case($(instanceOf(ExecutionException.class)), Throwable::getCause),
Case($(), th -> th)
);
}
While it is not possible to write a switch statement, it is possible to branch out to specific processing for each given type. One way of doing this is to use standard double dispatch mechanism. An example where we want to "switch" based on type is Jersey Exception mapper where we need to map multitude of exceptions to error responses. While for this specific case there is probably a better way (i.e. using a polymorphic method that translates each exception to an error response), using double dispatch mechanism is still useful and practical.
interface Processable {
<R> R process(final Processor<R> processor);
}
interface Processor<R> {
R process(final A a);
R process(final B b);
R process(final C c);
// for each type of Processable
...
}
class A implements Processable {
// other class logic here
<R> R process(final Processor<R> processor){
return processor.process(this);
}
}
class B implements Processable {
// other class logic here
<R> R process(final Processor<R> processor){
return processor.process(this);
}
}
class C implements Processable {
// other class logic here
<R> R process(final Processor<R> processor){
return processor.process(this);
}
}
Then where ever the "switch" is needed, you can do it as follows:
public class LogProcessor implements Processor<String> {
private static final Logger log = Logger.for(LogProcessor.class);
public void logIt(final Processable base) {
log.info("Logging for type {}", process(base));
}
// Processor methods, these are basically the effective "case" statements
String process(final A a) {
return "Stringifying A";
}
String process(final B b) {
return "Stringifying B";
}
String process(final C c) {
return "Stringifying C";
}
}
Starting from Java 17 you can use pattern matching for switch expressions (preview feature) JEP-406.
public void doAction(Object o) {
return switch (o) {
case A a -> doA(a);
case B b -> doB(b);
case C c -> doC(c);
default -> log.warn("Unrecognized type of {}", o);
};
}
Guard pattern is also available:
public void doAction(Object o) {
return switch (o) {
case String s && !s.isBlank() -> handle(s);
};
}
You need to enable preview features to use it: java --enable-preview
In Java 19 recent release this has been very easy and useful :
Create interface and have method called makesomenoise() which accepts animal parameter.
void makeSomeNoise (Animal animal) {
switch (animal) {
case Dog dog → dog.bark();
case Cat catcat.meow();
default throw new RuntimeException ("WTH is it???");
}
}
there is an even simpler way of emulating a switch structure that uses instanceof, you do this by creating a code block in your method and naming it with a label. Then you use if structures to emulate the case statements. If a case is true then you use the break LABEL_NAME to get out of your makeshift switch structure.
DEFINE_TYPE:
{
if (a instanceof x){
//do something
break DEFINE_TYPE;
}
if (a instanceof y){
//do something
break DEFINE_TYPE;
}
if (a instanceof z){
// do something
break DEFINE_TYPE;
}
}
The Eclipse Modelling Framework has an interesting idea that also considers inheritance. The basic concept is defined in the Switch interface: switching is done by invoking the doSwitch method.
What is really interesting is the implementation. For each type of interest, a
public T caseXXXX(XXXX object);
method must be implemented (with a default implementation returning null). The doSwitch implementation will attempt to call al the caseXXX methods on the object for all its type hierarchy. Something in the lines of:
BaseType baseType = (BaseType)object;
T result = caseBaseType(eAttribute);
if (result == null) result = caseSuperType1(baseType);
if (result == null) result = caseSuperType2(baseType);
if (result == null) result = caseSuperType3(baseType);
if (result == null) result = caseSuperType4(baseType);
if (result == null) result = defaultCase(object);
return result;
The actual framework uses an integer id for each class, so the logic is actually a pure switch:
public T doSwitch(Object object) {
return doSwitch(object.class(), eObject);
}
protected T doSwitch(Class clazz, Object object) {
return doSwitch(getClassifierID(clazz), object);
}
protected T doSwitch(int classifierID, Object theObject) {
switch (classifierID) {
case MyClasses.BASETYPE:
{
BaseType baseType = (BaseType)object;
...
return result;
}
case MyClasses.TYPE1:
{
...
}
...
You can look at a complete implementation of the ECoreSwitch to get a better idea.
If you want to avoid the verbosity of if(){} else if{}, you may consider switching this single file to kotlin and use the switch-like when expression in combination with is operator.
In any case Kotlin and java files can co-exist in a project and result in a jar that can run in JVM.
when (this) { //switch-like statement in kotlin supporting class-pattern-matching and smart casts via `is` operator.
is A -> doA()
is B -> doB()
is C -> doC()
}

Enums,use in switch case

I have an Enum defined which contains method return type like "String",Float,List,Double etc.
I will be using it in switch case statements.
For example my enum is
public enum MethodType {
DOUBLE,LIST,STRING,ARRAYLIST,FLOAT,LONG;
}
In a property file, I've key value pairs as follows.
Test1=String
Test2=Double
In my code I'm getting the value for the key. I need to use the VALUE in Switch Case to Determine the Type and based on that I've to implement some logic.
For example something like this
switch(MethodType.DOUBLE){
case DOUBLE:
//Dobule logic
}
Can someone please help me to implement this?
I guess this is what you are looking for:
public class C_EnumTest {
public enum MethodType {
DOUBLE,LIST,STRING,ARRAYLIST,FLOAT,LONG;
}
public static void main( String[] args ) {
String value = "DOUBLE";
switch( MethodType.valueOf( value ) ) {
case DOUBLE:
System.out.println( "It's a double" );
break;
case LIST:
System.out.println( "It's a list" );
break;
}
}
}
For not being case sensitive you could do a MethodType.valueOf( value.toUpperCase() ).
This may be a little closer to what you need. You can make the propertyName property anything you need it to be in this case:
public enum MethodType {
STRING("String"),
LONG("Long"),
DOUBLE("Double"),
THING("Thing");
private String propertyName;
MethodType(String propName) {
this.propertyName = propName;
}
public String getPropertyName() {
return propertyName;
}
static MethodType fromPropertyName(String x) throws Exception {
for (MethodType currentType : MethodType.values()) {
if (x.equals(currentType.getPropertyName())) {
return currentType;
}
}
throw new Exception("Unmatched Type: " + x);
}
}
You've defined the enum, but you need to define a variable that is that type. Like this:
public enum MethodType { ... }
public MethodType myMethod;
switch (myMethod)
{
case MethodType.DOUBLE:
//...
break;
case MethodType.LIST:
//...
break;
//...
}
Edit:
Previously, this snippet used var as the variable name, but that's a reserved keyword. Changed to myMethod.
You don't need a switch at all (this is in java btw so might not work for you): Obviously you'll want to add some null checks, better exception handling, etc.
public enum MethodType {
String,LONG,DOUBLE,THING;
static MethodType fromString(String x) throws Exception {
for (MethodType currentType: MethodType.values()){
if (x.equals(currentType.toString())){
return currentType;
}
}
throw new Exception("Unmatched Type");
}
}

Categories