我有一个问题,使用开关情况的instanceof对象:
例如:我的问题可以在Java中重现:
if(this instanceof A)
doA();
else if(this instanceof B)
doB();
else if(this instanceof C)
doC():
如何使用switch…case实现它?
我有一个问题,使用开关情况的instanceof对象:
例如:我的问题可以在Java中重现:
if(this instanceof A)
doA();
else if(this instanceof B)
doB();
else if(this instanceof C)
doC():
如何使用switch…case实现它?
当前回答
创建一个Map,其中键为Class<?>,值为表达式(lambda或类似)。考虑:
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();
如果你需要检查异常,那就实现一个抛出异常的FunctionalInterface,而不是使用Runnable。
下面是一个真实的单词前后对比,展示了这种方法如何简化代码。
重构映射之前的代码:
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;
}
重构为映射后的代码:
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() );
}
这避免了重复,消除了几乎所有的分支语句,并简化了维护。
其他回答
我个人比较喜欢下面的Java 1.8代码:
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");
});
将输出:
YYyy
示例代码使用字符串,但您可以使用任何对象类型,包括Class。例如:. mycase (this.getClass(), (o) ->…
需要以下片段:
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);
}
如果您可以操作公共接口,您可以在枚举中添加,并让每个类返回唯一的值。您不需要instanceof或visitor模式。
对我来说,逻辑需要写在switch语句中,而不是对象本身。这就是我的解决方案:
ClassA、ClassB和ClassC实现了CommonClass
接口:
public interface CommonClass {
MyEnum getEnumType();
}
枚举:
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;
}
...
如果你使用的是java 7,你可以为枚举设置字符串值,并且switch case块仍然可以工作。
Java现在允许你以op的方式切换。他们称之为模式匹配切换。它在Java 17发布。JEP中给出的例子是
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();
}
或者使用他们的lambda语法并返回一个值
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();
};
不管怎样,他们一直在用开关做很酷的东西。
不,这是不可能的。然而,您可能想要做的是将多态性作为处理这类问题的一种方法。
如果需要通过“this”对象的类类型“切换”,这个答案是最好的https://stackoverflow.com/a/5579385/2078368
但如果你需要将“switch”应用于任何其他变量。我建议另一种解决办法。定义以下接口:
public interface ClassTypeInterface {
public String getType();
}
在你想要“切换”的每个类中实现这个接口。例子:
public class A extends Something implements ClassTypeInterface {
public final static String TYPE = "A";
@Override
public String getType() {
return TYPE;
}
}
之后,你可以用以下方式使用它:
switch (var.getType()) {
case A.TYPE: {
break;
}
case B.TYPE: {
break;
}
...
}
你唯一需要关心的是——在实现ClassTypeInterface的所有类中保持“类型”的唯一性。这不是一个大问题,因为在任何交集的情况下,您都会收到“switch-case”语句的编译时错误。