web-dev-qa-db-ja.com

文字列からプリミティブ型または標準型に変換する方法Javaラッパー型

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

複雑なオブジェクト間の自動変換を単純に実装することは期待していませんが、文字列から標準の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;
}

そして上記は私が今まで見たものより悪いものではありません:)

ここに誰かが秘密のトリックを持っていますか?

21

私の知る限り、あなたが提示したバージョンに代わるものはありません。少し単純化できます(ラッパータイプはすべてfinalであるため)。ただし、基本的にはifまたはswitchまたはハッシュを使用してクラスをオンにする必要があります。

上記のようにコーディングすることをお勧めします。醜いコードは、それ自体を見なければならない場合にのみ問題自体です。したがって、それをユーティリティメソッド内に配置し、再度見ないでください。


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オブジェクトの同等性はオブジェクトIDであると規定されているため、元のバージョンと同等です。

おそらく、ラッパーオブジェクトを直接返す<wrapper>.valueOf(String)メソッドを使用する必要があります。

これは見苦しくないという主張はしませんが、「美しさ」は主観的なものであり、コードの理解や保守が容易かどうかを通知しないため、コード品質の有用な尺度ではありません。

[〜#〜]更新[〜#〜]

プリミティブ型もサポートするには、対応するクラスをif条件に追加します。例えば.

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

考えなければならないタイプIDの若干のこだわりの問題がありますが、タイプの名前で文字列スイッチを実行する方が効率的になるようになりました。 (理論的には、異なるクラスローダーによってロードされた同じフルネームを持つ複数のタイプを持つことができます。プリミティブラッパークラスでこれを行うには、クラスローダーで「高速かつ緩やかに再生」する必要があると思いますが、まだ可能かもしれないと思います。)

27
Stephen C

私は何か見つけたと思う

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

Java.beansパッケージがJava標準ライブラリ(javadocs: PropertyEditorManager )。

私はそれがかなり受け入れられると思います。私の唯一の困惑は、PropertyEditorJava.beansパッケージに含まれていることです。このコードは実際にはJava.utilとは関係がないため、Java.lang.reflectまたはJava.beansパッケージで利用可能なものを優先しました。

上記のコードには、追加のPropertyEditorインスタンスを登録して複雑なオブジェクトを変換できるという利点もあります。しかし、それは悪いことではありません。

Ifsのリストよりも、美しさだけでなく、品質も良いと思います。

22

おそらく org.Apache.commons.beanutils.ConvertUtils が役立つでしょうか?

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

jdk8では、次のようにすることができますO(1) ifステートメントなしのルックアップ時間...

Nullを正しく処理するより良いバージョンがここにあります

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);
4
Dean Hiller

文字列をJava=必要なタイプに解析する軽量ライブラリがあります。type-parserと呼ばれ、github here で見つけることができます。

上記のコードは次のようになります。

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

私はこれを提案します:

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

見た目がきれいか醜いかはあなたにお任せします。

3
luiscubal