tipos programacion primitivos ejemplos ejemplo definicion datos java string object reflection type-conversion

java - ejemplos - tipos de datos primitivos en programacion



Cómo convertir de String a un tipo primitivo o tipos de envoltor java estándar (6)

Tengo un java.lang.reflect.InvocationHandler y necesito implementar el método invoke ()

Tengo un valor de tipo java.lang.String desde mi elaboración y necesito convertir este valor al tipo de retorno apropiado que espera el método (puede ser una clase primitiva como int, boolean, double o wrapper como boolean, Integer, Double , Flotador, etc).

Ejemplo:

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

No espero simplemente implementar una conversión automática entre objetos complejos, pero espero una forma sencilla de convertir de String a los tipos de Java estándar.

He visto (también) muchas veces cosas como esta, pero no me parece apropiado:

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

y lo de arriba ni siquiera es el peor que he visto hasta ahora :)

¿Alguien tiene un truco secreto aquí?


Creo que encontré algo

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

Creo que esas 3 líneas de código son mejores que los múltiples ifs, y evité agregar dependencias de bibliotecas externas, ya que el paquete java.beans está dentro de las bibliotecas estándar de Java (javadocs: PropertyEditorManager ).

Me parece bastante aceptable; mi única perplejidad es que PropertyEditor está contenido en el paquete java.beans y hubiera preferido algo disponible en el paquete java.util o java.lang.reflect , ya que este código no tiene nada que ver con java.beans realidad.

El código anterior también tiene la ventaja de que puede registrar instancias adicionales de PropertyEditor para traducir objetos complejos, por cierto. Aunque eso no es algo malo.

Creo que es mejor que una lista de ifs, en belleza, pero también en calidad.


Hay una biblioteca liviana que analiza cadenas a tipos java que hacen lo que usted quiere. Se llama analizador de tipos y puede encontrarlo en github here .

Su código de arriba podría verse así:

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



Propongo esto:

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

Te lo dejaré ya sea que se vea más limpio o más feo.


Que yo sepa, no hay una alternativa real a la versión que presentó. Puede simplificarlo un poco (ya que los tipos de envoltura son todos final ), pero esencialmente necesita usar if o switch o hashing para activar la clase.

Mi consejo es codificarlo como el anterior. El código feo es solo un problema per se si tienes que verlo. Así que ponlo dentro de un método de utilidad y no lo mires otra vez.

FWIW - Así es como simplificaría el método:

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

Esto es más simple y más eficiente. Y es equivalente a la versión original porque las clases son todas final y porque las especificaciones establecen que la igualdad para Class objetos de Class es la identidad del objeto.

Podría decirse que deberíamos utilizar los métodos de <wrapper>.valueOf(String) que devuelven los objetos de contenedor directamente.

No digo que esto sea menos feo ... pero "belleza" no es una medida útil de la calidad del código, porque es subjetiva y porque no le dice si el código es fácil de entender y / o mantener.

ACTUALIZAR

Para admitir tipos primitivos también, agregue las clases correspondientes a las condiciones if ; p.ej

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

Puede que ahora esté llegando al punto en el que hacer un cambio de String en el nombre del tipo sea más eficiente, aunque hay algunos problemas ligeramente marcados de la identidad de tipo que deben analizarse. (En teoría, puedes tener varios tipos con el mismo nombre completo que han sido cargados por diferentes cargadores de clases. Creo que deberías "jugar rápido y suelto" en un cargador de clases para hacer eso con las clases primitivas de envoltorio ... pero Creo que todavía podría ser posible.


en jdk8, ahora podría hacer algo así como O (1) tiempo de búsqueda sin sentencias if ...

Una mejor versión ahora que maneja los nulos correctos está aquí.

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

de tal manera que puedas llamar

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