我正在研究一个消息解析库,其中消息体在每种情况下都以字符串形式返回。我想创建一个能自动将结果转换为正确类型的函数,但我不确定它是否可行。
我的结构是这样的: 我有一个名为ReturnType的枚举。这包含了它包含返回类型的类变量。
我有一个功能映射,它将用户尝试调用的函数映射到消息响应的返回类型。
我认为我有一点工作,但问题是我必须将我想要的类包含在getTypedValue()方法调用中,我认为这是多余的,因为我已经知道基于ReturnType变量的返回类型在功能图中。这是一些代码:
public enum ReturnType {
NA(String.class),
INTEGER(Integer.class),
JSON(JsonElement.class),
STRING(String.class),
FLOAT(Float.class),
DOUBLE(Double.class),
IP_ADDRESS(InetAddress.class),
UNKNOWN(String.class),
BOOLEAN(Boolean.class);
private Class<?> c;
<T> ReturnType(Class<T> clazz) {
this.c = clazz;
}
public Class<?> getClazz() {
return this.c;
}
}
这是我的getTypedValue()方法:
public <T> T getTypedValue(String functionName, String value, Class<T> clazz) {
ReturnType type = this.getReturnType(functionName);
//TODO: Finish this
if(type.getClazz().equals(clazz)) {
switch(type) {
case DOUBLE:
break;
case FLOAT:
break;
case INTEGER:
return clazz.cast(Integer.parseInt(value));
case IP_ADDRESS:
break;
case JSON:
break;
case STRING:
return clazz.cast(value);
case UNKNOWN:
return clazz.cast(value);
default:
return clazz.cast(value);
}
return null;
}else {
throw new UnsupportedOperationException(functionName +" does not support that class("+clazz.getSimpleName()+")");
}
}
以下是用户如何调用get typed值。为了简化,我输入了一个静态值(15),但这实际上是一个从消息响应中获取结果的方法调用:
Integer volume = fm.getTypedValue("VOLUME", "15", Integer.class);
有没有办法让它在不提供课程的情况下返回正确的类型?即
Integer volume = fm.getTypedValue("VOLUME", "15");
Double minutes = fm.getTypedValue("MINUTES", "15.25");
Boolean isRunning = fm.getTypedValue("IS_RUNNING","true");
我不确定它是否可能,即使它是,我认为我现在的代码可能有点难看并且难以理解。
答案 0 :(得分:0)
Object
以外的任何其他内容不安全
或者,您可以返回Object
并进行多次instanceof
检查,但我认为情况更糟。
另一种方法是使用提供的通用调用该方法。不幸的是,我不确定这是否会导致其他编译错误。尝试像
这样的东西Double minutes = fm.<Double>getTypedValue("MINUTES", "15.25");
向泛型方法提供Class
实例没有任何问题,我在许多不同的库中都看到过它。
答案 1 :(得分:0)
你可以实现这一点,但你将失去编译器给你的优势,在编译时检查类型是否正确。
使用类似于{/ p>的getTypedValue
实现
@SuppressWarnings({ "unchecked" })
public <T> T getTypedValue(String functionName, String value) {
ReturnType type = this.getReturnType(functionName);
switch(type) {
case DOUBLE:
case FLOAT:
case JSON:
case IP_ADDRESS:
break;
case INTEGER:
return (T) Integer.valueOf(value);
case STRING:
case UNKNOWN:
default:
return (T) value;
}
return null;
}
您可以毫无问题地使用它:
int volume = fm.getTypedValue("VOLUME", "15");
但是,另一方面你也可以使用它(并且编译器不会显示任何错误)
String volume = fm.getTypedValue("VOLUME", "15");
您将收到类型为ClassCastException
的运行时异常,例如:
java.lang.Integer无法强制转换为java.lang.String
如果你想要某些可能不易出错(在编译时显示错误而不是运行时),你可以定义你在类中处理/知道/提供的所有函数(枚举确实不处理泛型)。
public final class Function<T> {
private final Class<T> type;
private Function(Class<T> type) {
this.type = type;
}
public Class<T> getType() {
return type;
}
public static final Function<Integer> VOLUME = new Function<>(Integer.class);
public static final Function<Boolean> IS_RUNNING = new Function<>(Boolean.class);
public static final Function<String> NAME = new Function<>(String.class);
}
(您可以根据需要进行重构,也可以添加ReturnType
。您可以在Function
中添加一些自定义逻辑。也可以在构造函数参数中传递函数的名称,如果您需要稍后的名称)
然后稍微更改getTypedValue
方法:
public <T> T getTypedValue(Function<T> function, String value) {
ReturnType returnType = ReturnType.getReturnTypeByClass(function.getType());
// ... same as before
}
您可以创建方法getReturnTypeByClass()
以获取returnType
,具体取决于收到的课程。
这将有效:
int volume = test2.getTypedValue(Function.VOLUME, "123");
这将显示编译时错误,非常容易检测和修复:
String volume = test2.getTypedValue(Function.VOLUME, "123");
最后,您可以将Function
类的定义与其他类名称中的函数声明分开,例如Functions
。
答案 2 :(得分:0)
修改您的枚举,如下所示。
public enum ReturnType {
NA(String.class) {
@Override
public String getValue(String param) {
return param;
}
},
INTEGER(Integer.class) {
@Override
public Integer getValue(String param) {
return Integer.valueOf(param);
}
},
JSON(JsonElement.class) {
@Override
public <T> T getValue(String param) {
return null;
}
},
STRING(String.class) {
@Override
public String getValue(String param) {
return param;
}
},
FLOAT(Float.class),
DOUBLE(Double.class),
IP_ADDRESS(InetAddress.class),
UNKNOWN(String.class),
BOOLEAN(Boolean.class);
private Class<?> c;
<T> ReturnType(Class<T> clazz) {
this.c = clazz;
}
public Class<?> getClazz() {
return this.c;
}
public abstract <T> T getValue(String param);
}
您必须在每个ReturnType中实现以从String返回生成的T值。
然后你可以使用如下的ReturnType枚举。
public <T> T getTypedValue(String functionName, String value, Class<T> clazz) {
ReturnType type = this.getReturnType(functionName);
if(type.getClazz().equals(clazz)) {
return type.getValue(value);
}
return null;
}
请善意忽略编译器错误,请修复它。我想给你一个实现其他方式的想法。