2017-01-03 35 views
0

我建立了一個簡單的文檔存儲,有實體具有不同類型的字段,我有一個Float,Int和String類型。該實體包含值的數組列表,如果有人更新實體的模式,我希望能夠嘗試將值轉換爲新類型。使用類的泛型如何將一個類型的值轉換爲另一個類型?

public interface FieldType<T> { 
    ArrayList<T> values; 
} 

public class FloatField implements FieldType<Float> { 

} 

public class StringField implements FieldType<String> { 

} 

我曾經想過用一個有方法的抽象類,如下

public abstract class Field<T> implements FieldType<T> { 
    abstract public <T> castFromString(String value); 
    abstract public <T> castFromFloat(Float value); 
    abstract public <T> castFromInt(Int value); 
} 

public class FloatField extends Field<Float> { 
    @override 
    public <Float> castFromString(String value){ 
    Float castValue = null; 
    try { 
     castValue = Float.parseFloat(value); 
    } catch(Exception e){ 

    } 

    return castValue; 
    } 
} 

我真的不喜歡這個解決方案,我將不得不給每個我增加了一個額外的類型時添加一個新的抽象方法到系統。

任何想法我可以如何實現這一點更好?

回答

1

也許你可以使用Function<T, R> interface

public abstract class Field<T> implements FieldType<T> { 

    ... 

    public <F> T convert(F value, Function<F, T> converter) { 
     try { 
      return converter.apply(value); 
     } catch(Exception e) { 
      return null; 
     } 
    } 

    ... 

} 

,然後指定使用lambda expressionmethod reference轉換器:

field.convert("1234", BigDecimal::new); //with a method reference 
field.convert("1234", s -> new BigDecimal(s)) //with a lambda 

因爲返回類型是從傳遞Function推斷這將通過更換所有的convertXXX方法。


編輯: 如果你想自動轉換,你當然會不得不硬編碼這些,因爲你不希望寫所有4240類的Java API中的轉換方法。雖然這會變得混亂。也許像這樣在靜態幫助類或FieldType本身?

public class WhereverYouWantThis { 

    private static HashMap<Class<?>, HashMap<Class<?>, Function<?, ?>>> converters = new HashMap<>(); 

    static { 
     putConverter(String.class, Float.class, Float::parseFloat); 
    } 

    private static <T, R> void putConverter(Class<T> t, Class<R> r, Function<T, R> func) { 
     HashMap<Class<?>, Function<?, ?>> map = converters.get(t); 
     if(map == null) converters.put(t, map = new HashMap<>()); 
     map.put(r, func); 
    } 

    public static <T, R> Function<T, R> getConverter(Class<T> t, Class<R> r) { 
     HashMap<Class<?>, Function<?, ?>> map = converters.get(t); 
     if(map == null) return null; 
     @SuppressWarnings("unchecked") 
     Function<T, R> func = (Function<T, R>) map.get(r); 
     return func; 
    } 

    public static <T, R> R convert(T o, Class<R> to) { 
     @SuppressWarnings("unchecked") 
     Function<T, R> func = (Function<T, R>) getConverter(o.getClass(), to); 
     return func == null ? null : func.apply(o); 
    } 

} 
+0

這看起來不錯,如果它不能轉換爲正確的類型,我是否必須將try語句包裝在try catch中? –

+0

如果你的意思是格式無效,是(例如'convert(「a」,Float :: parseFloat)')。修正了 – Moira

+0

有沒有辦法讓FloatField返回轉換器,或者有一個方法可以調用convert,所以我不需要計算出要傳遞什麼函數? –

0

我不認爲你需要這種泛型。相反,只是試圖從輸入String創建Float並返回null如果有一個問題:

public Float castFromString(String value) { 
    Float castValue = null; 
    try { 
     castValue = Float.parseFloat(value); 
    } catch(Exception e){ 
     // log here 
    } 

    return castValue; 
} 

我不認爲需要仿製藥的原因是,參與轉換的類型被命名爲/已知在你的幫手方法中。

相關問題