简体   繁体   English

如何将String转换为基本类型或标准java Wrapper类型

[英]How to convert from String to a primitive type or standard java Wrapper types

I have a java.lang.reflect.InvocationHandler and I need to implement the method invoke() 我有一个java.lang.reflect.InvocationHandler ,我需要实现方法invoke()

I have a value of type java.lang.String from my elaboration and I need to convert this value to the appropriate returnType expected by the method (it can be a primitive like int, boolean, double or wrapper classes like Boolean, Integer, Double, Float, etc). 我有一个java.lang.String类型的值,我需要将此值转换为该方法所需的相应returnType(它可以是一个原语,如int,boolean,double或包装类,如Boolean,Integer,Double ,浮动等)。

Example: 例:

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?
}

I am not expecting to simply implement an automatic conversion between complex objects, but I expect a simple way to convert from String to the standard java types. 我不希望简单地在复杂对象之间实现自动转换,但我期望从String转换为标准java类型的简单方法。

I've seen (too) many times stuff like this, but it doesn't seem appropriate to me: 我曾经多次看过这样的东西,但这对我来说似乎不合适:

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;
}

and the above is not even the worse one I saw, so far :) 以上甚至不是我看到的更糟糕的,到目前为止:)

Does anybody have a secret trick here? 有人在这里有秘密技巧吗?

As far as I'm aware, there is no real alternative to the version you presented. 据我所知,你提供的版本没有真正的替代品。 You can simplify it a bit (since the wrapper types are all final ), but you essentially need to use if or switch or hashing to switch on the class. 您可以稍微简化一下(因为包装器类型都是final ),但您基本上需要使用ifswitch或hasing来打开类。

My advice is to code it like the above. 我的建议是像上面那样对它进行编码。 Ugly code is only a problem per se if you have to look at it. 丑陋的代码本身只是一个问题如果你不得不看它。 So put it inside a utility method and don't look at it again. 所以把它放在一个实用工具方法中,不要再看它了。


FWIW - this is how I'd simplify the method: 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;
}

This is simpler and more efficient. 这更简单,更有效。 And it is equivalent to the original version because the classes are all final and because the specs state that equality for Class objects is object identity. 它等同于原始版本,因为类都是final ,因为规范声明Class对象的相等性是对象标识。

Arguably, we should be using the <wrapper>.valueOf(String) methods which return the wrapper objects directly. 可以说,我们应该使用<wrapper>.valueOf(String)方法直接返回包装器对象。

I make no claim that this is less ugly ... but "beauty" is not a useful measure of code quality, because it is subjective and because it doesn't tell you whether the code is easy to understand and / or maintain. 我没有声称这不那么丑陋...但“美”并不是衡量代码质量的有用方法,因为它是主观的,因为它不会告诉你代码是否易于理解和/或维护。

UPDATE UPDATE

To support primitive types as well, add the corresponding classes to the if conditions; 要同样支持基本类型,请将相应的类添加到if条件中; eg 例如

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

It may now be getting to the point where doing a String switch on the type's name is more efficient, though there are some slightly knotty issues of type identity that need to be thought through. 它现在可能已经达到了这样的程度,即对类型名称进行字符串切换更有效,尽管有一些类型标识的问题需要仔细考虑。 (In theory, you can have multiple types with the same full name that have been loaded by different classloaders. I think you'd need to "play fast and loose" in a classloader to do that with the primitive wrapper classes ... but I think it might still be possible.) (理论上,您可以使用由不同类加载器加载的具有相同全名的多个类型。我认为您需要在类加载器中“快速且松散地”使用原始包装类来执行此操作...但是我认为它仍有可能。)

I think I found something 我想我找到了些东西

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();
}

I think that those 3 lines of code are better than the multiple ifs, and I avoided to add external library dependencies, since java.beans package is inside the Java standard libraries (javadocs: PropertyEditorManager ). 我认为这三行代码比多个ifs更好,我避免添加外部库依赖,因为java.beans包在Java标准库(javadocs: PropertyEditorManager )中。

I find it quite acceptable; 我发现它完全可以接受; my only perplexity is that PropertyEditor is contained in java.beans package and I would have preferred something available in java.util or java.lang.reflect package, since this code has nothing to do with java.beans actually. 我唯一的困惑是PropertyEditor包含在java.beans包中,我更喜欢java.utiljava.lang.reflect包中可用的东西,因为这段代码实际上与java.beans无关。

The code above has also the advantage that you can register additional PropertyEditor instances to translate complex objects, btw. 上面的代码还有一个优点,你可以注册其他PropertyEditor实例来翻译复杂的对象,顺便说一句。 That's not a bad thing to have though. 尽管如此,这并不是一件坏事。

I think it's better than a list of ifs, in beauty, but also in quality. 我认为它比ifs,美容,质量更好。

Probably org.apache.commons.beanutils.ConvertUtils can help? 可能org.apache.commons.beanutils.ConvertUtils可以帮忙吗?

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

There is a lightweight library that parses strings to java types which does what you want. 有一个轻量级的库可以将字符串解析为java类型,它可以满足您的需求。 It's called type-parser and you can find it on github here . 这就是所谓的类型解析器和你可以找到它在github 这里

Your above code could then look something like this: 您的上述代码可能看起来像这样:

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());
}

in jdk8, you could now do something like so O(1) lookup time with no if statements... 在jdk8中,你现在可以做O(1)查找时间,没有if语句...

A better version now that handles nulls correct is here 现在处理空值正确的更好的版本就在这里

https://github.com/deanhiller/webpieces/blob/master/webserver/http-router/src/main/java/org/webpieces/router/impl/params/ObjectTranslator.java 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);
}

such that you can then call 这样你就可以打电话了

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

I propose this: 我建议这个:

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
    }
}

I'll leave it to you whether this looks cleaner or uglier. 无论这看起来更清洁还是更丑陋,我都会留给你。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM