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

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

我有一个java.lang.String类型的值,我需要将此值转换为方法所期望的相应returnType(它可以是像int,boolean,double或包装类一样的原语,如Boolean,Integer,Double ,浮动等)。

例:

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

我不希望简单地在复杂对象之间实现自动转换,但我希望有一种简单的方法可以将String转换为标准的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; } 

以上甚至不是我看到的更糟糕的,到目前为止:)

有人在这里有秘密技巧吗?

据我所知,你提供的版本没有真正的替代品。 您可以稍微简化它(因为包装器类型都是final ),但您基本上需要使用ifswitch或hasing来打开类。

我的建议是像上面那样对它进行编码。 如果你不得不看一下,丑陋的代码本身只是一个问题。 所以把它放在一个实用工具方法中,不要再看了。


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对象的相等性是对象标识。

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

我没有声称这不那么丑陋…但“美”并不是衡量代码质量的有用方法,因为它是主观的,因为它不会告诉你代码是否易于理解和/或维护。

UPDATE

要同样支持基本类型,请将相应的类添加到if条件中; 例如

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

现在可能已经到了这样的程度,即对类型名称进行字符串切换更有效,尽管有一些类型标识的问题需要仔细考虑。 (理论上,您可以使用由不同类加载器加载的具有相同全名的多个类型。我认为您需要在类加载器中“快速且松散地”使用原始包装类来执行此操作…但是我认为它仍有可能。)

我想我找到了些东西

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

我认为这三行代码比多个ifs更好,并且我避免添加外部库依赖项,因为java.beans包在Java标准库(javadocs: PropertyEditorManager )中。

我发现它完全可以接受; 我唯一的困惑是PropertyEditor包含在java.beans包中,我更喜欢java.utiljava.lang.reflect包中可用的东西,因为这段代码实际上与java.beans无关。

上面的代码还有一个优点,你可以注册其他PropertyEditor实例来翻译复杂的对象,顺便说一句。 尽管如此,这并不是件坏事。

我认为它比ifs,美丽,质量更好。

或许org.apache.commons.beanutils.ConvertUtils可以帮忙吗?

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

有一个轻量级的库可以将字符串解析为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()); } 

在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, Function> classToUnmarshaller = new HashMap<>(); private Map, Function> 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 getUnmarshaller(Class paramTypeToCreate) { return classToUnmarshaller.get(paramTypeToCreate); } public Function getMarshaller(Class type) { return classToMarshaller.get(type); } 

这样你就可以打电话了

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

我建议这个:

 List> clsList = new ArrayList>(); 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 } } 

无论这看起来更清洁还是更丑陋,我都会留给你。