如何从字符串转换为基本类型或标准的Java包装类型(How to convert from Stri

2019-07-05 19:25发布

我有一个java.lang.reflect.InvocationHandler ,我需要实现的方法调用()

我有类型的值java.lang.String从我的阐述,我需要这个值转换成用该方法有望适当的返回类型(也可以是一个原始的,比如说int,布尔人,双人或包装类,如布尔,整型,双浮法等)。

例:

public Object invoke(Object proxy, Method method, Object[] args) 
        throws Throwable {
    String computedValue = compute(...);
    return convert(method.getReturnType(), computedValue);
}

private Object convert(Class<?> returnType, String stringValue) {
    return ...; // what's the simplest way?
}

我不希望简单地实现复杂的对象之间的自动转换,但我期待有一个简单的方法来从字符串转换为标准的Java类型。

我已经看到了(太)很多次这样的东西,但它似乎不适合我:

public static Object toObject( Class clazz, String value ) {
    if( Boolean.class.isAssignableFrom( clazz ) ) return Boolean.parseBoolean( value );
    if( Byte.class.isAssignableFrom( clazz ) ) return Byte.parseByte( value );
    if( Short.class.isAssignableFrom( clazz ) ) return Short.parseShort( value );
    if( Integer.class.isAssignableFrom( clazz ) ) return Integer.parseInteger( value );
    if( Long.class.isAssignableFrom( clazz ) ) return Long.parseLong( value );
    if( Float.class.isAssignableFrom( clazz ) ) return Float.parseFloat( value );
    if( Double.class.isAssignableFrom( clazz ) ) return Double.parseDouble( value );
    return value;
}

和上面甚至不是一个糟糕的我看到了,到目前为止:)

没有任何人有一个秘招吗?

Answer 1:

据我所知,有对你提出的版本没有真正的替代品。 你可以把它简化一点(因为包装类型都是final ),但你基本上需要使用ifswitch或散列对班级进行切换。

我的建议是像上面的代码。 丑陋的代码只是一个本身的问题,如果你有看它。 所以把它放在一个工具方法内,它再也不看。


FWIW - 这就是我想简化方法:

public static Object toObject( Class clazz, String value ) {
    if( Boolean.class == clazz ) return Boolean.parseBoolean( value );
    if( Byte.class == clazz ) return Byte.parseByte( value );
    if( Short.class == clazz ) return Short.parseShort( value );
    if( Integer.class == clazz ) return Integer.parseInt( value );
    if( Long.class == clazz ) return Long.parseLong( value );
    if( Float.class == clazz ) return Float.parseFloat( value );
    if( Double.class == clazz ) return Double.parseDouble( value );
    return value;
}

这是更简单,更高效。 而且,因为类都是它相当于原来的版本, final又因为规格说明的平等Class对象为对象的身份。

可以说,我们应该使用<wrapper>.valueOf(String) ,其直接返回包装器对象的方法。

我并没有说这是不太难看......但“美”不是代码质量的有效手段,因为它是主观的,因为它不会告诉你的代码是否是容易理解和/或维护。

UPDATE

为了支持原始类型为好,添加相应的类到if条件; 例如

    if (Boolean.class == clazz || Boolean.TYPE == clazz) {
        return Boolean.parseBoolean(value);
    }

目前可以得到的地方做的类型名称的字符串开关是更有效的,但也有需要通过被认为是身份类型微微有些棘手的问题上。 (理论上,你可以有多种类型的具有相同全名已加载由不同类加载器,我认为你需要在一个类加载器做与原始的包装类“朝三暮四” ......但我觉得它可能仍然是可能的。)



Answer 2:

我想我找到了些东西

import java.beans.PropertyEditor;
import java.beans.PropertyEditorManager;

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    String returnValue = ...
    return convert(method.getReturnType(), returnValue); 
}

private Object convert(Class<?> targetType, String text) {
    PropertyEditor editor = PropertyEditorManager.findEditor(targetType);
    editor.setAsText(text);
    return editor.getValue();
}

我认为,这些代码3线比多IFS更好,我避免添加外部库的依赖,因为java.beans包是Java标准库(的javadoc:内PropertyEditorManager )。

我觉得完全可以接受的; 我唯一的困惑就是PropertyEditor中包含java.beans包,我本来希望获得的东西java.utiljava.lang.reflect包,因为这个代码有无关java.beans实际。

上面的代码也有您可以注册其他优势PropertyEditor实例,以复杂的对象翻译,顺便说一句。 这不是一件坏事,有虽然。

我认为这是比IFS的列表,在美更好,而且在质量。



Answer 3:

也许org.apache.commons.beanutils.ConvertUtils能帮忙吗?

import org.apache.commons.beanutils.ConvertUtils;
// ...
final Object v = ConvertUtils.convert("42", Integer.class);


Answer 4:

还有就是解析字符串Java类型,而且你想要做什么一个轻量级库。 这就是所谓的类型解析器和你可以找到它在github 这里 。

然后你上面的代码可能是这个样子:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    TypeParser parser = TypeParser.newBuilder().build();
    String computedValue = compute(...);
    return parser.parseType(computedValue,  method.getGenericReturnType());
}


Answer 5:

在jdk8,你现在可以做一些像这样O(1)查找时间没有if语句...

一个更好的版本,现在处理空值正确的是这里

https://github.com/deanhiller/webpieces/blob/master/webserver/http-router/src/main/java/org/webpieces/router/impl/params/ObjectTranslator.java

private Map<Class<?>, Function<String, Object>> classToUnmarshaller = new HashMap<>();
private Map<Class<?>, Function<Object, String>> classToMarshaller = new HashMap<>();

public ObjectTranslator() {
    classToUnmarshaller.put(Boolean.class, s -> s == null ? null : Boolean.parseBoolean(s));
    classToUnmarshaller.put(Boolean.TYPE, s -> Boolean.parseBoolean(s));
    classToUnmarshaller.put(Byte.class, s -> s == null ? null : Byte.parseByte(s));
    classToUnmarshaller.put(Byte.TYPE, s -> Byte.parseByte(s));
    classToUnmarshaller.put(Short.class, s -> s == null ? null : Short.parseShort(s));
    classToUnmarshaller.put(Short.TYPE, s -> Short.parseShort(s));
    classToUnmarshaller.put(Integer.class, s -> s == null ? null : Integer.parseInt(s));
    classToUnmarshaller.put(Integer.TYPE, s -> Integer.parseInt(s));
    classToUnmarshaller.put(Long.class, s -> s == null ? null : Long.parseLong(s));
    classToUnmarshaller.put(Long.TYPE, s -> Long.parseLong(s));
    classToUnmarshaller.put(Float.class, s -> s == null ? null : Float.parseFloat(s));
    classToUnmarshaller.put(Float.TYPE, s -> Float.parseFloat(s));
    classToUnmarshaller.put(Double.class, s -> s == null ? null : Double.parseDouble(s));
    classToUnmarshaller.put(Double.TYPE, s -> Double.parseDouble(s));
    classToUnmarshaller.put(String.class, s -> s);

    classToMarshaller.put(Boolean.class, s -> s == null ? null : s.toString());
    classToMarshaller.put(Boolean.TYPE, s -> s.toString());
    classToMarshaller.put(Byte.class, s -> s == null ? null : s.toString());
    classToMarshaller.put(Byte.TYPE, s -> s.toString());
    classToMarshaller.put(Short.class, s -> s == null ? null : s.toString());
    classToMarshaller.put(Short.TYPE, s -> s.toString());
    classToMarshaller.put(Integer.class, s -> s == null ? null : s.toString());
    classToMarshaller.put(Integer.TYPE, s -> s.toString());
    classToMarshaller.put(Long.class, s -> s == null ? null : s.toString());
    classToMarshaller.put(Long.TYPE, s -> s.toString());
    classToMarshaller.put(Float.class, s -> s == null ? null : s.toString());
    classToMarshaller.put(Float.TYPE, s -> s.toString());
    classToMarshaller.put(Double.class, s -> s == null ? null : s.toString());
    classToMarshaller.put(Double.TYPE, s -> s.toString());
    classToMarshaller.put(String.class, s -> s == null ? null : s.toString());
}

public Function<String, Object> getUnmarshaller(Class<?> paramTypeToCreate) {
    return classToUnmarshaller.get(paramTypeToCreate);
}

public Function<Object, String> getMarshaller(Class<?> type) {
    return classToMarshaller.get(type);
}

这样你就可以调用

primitiveTranslator.getConverter(Integer.TYPE).apply(stringToConvert);


Answer 6:

我建议这样的:

List<Class<?>> clsList = new ArrayList<Class<?>>();
clsList.add(Boolean.class);
clsList.add(Integer.class);
//etc.

for (Class<?> cls : clsList) {
    if (cls.isAssignableFrom(clazz)) {
        return cls.getMethod("valueOf", new Class[] { String.class }).invoke(null, new Object[] { value });
        //Missing in this example: Handle a few exceptions
    }
}

我要把它留给你,这是否看起来清洁剂或丑陋。



文章来源: How to convert from String to a primitive type or standard java Wrapper types