[英]Converting a List<String> to a List<Integer> (or any class that extends Number)
我想創建一個非常通用的實用程序方法,以獲取任何Collection並將其轉換為用戶可選類的Collection,該類從Number擴展(Long,Double,Float,Integer等)
我想到了使用Google集合來轉換集合並返回不可變列表的代碼。
import java.util.List;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
/**
* Takes a {@code List<String>} and transforms it into a list of the
* specified {@code clazz}.
*
* @param <T>
* @param stringValues
* the list of Strings to be used to create the list of the
* specified type
* @param clazz
* must be a subclass of Number. Defines the type of the new List
* @return
*/
public static <T extends Number> List<T> toNumberList(List<String> stringValues, final Class<T> clazz) {
List<T> ids = Lists.transform(stringValues, new Function<String, T>() {
@SuppressWarnings("unchecked")
@Override
public T apply(String from) {
T retVal = null;
if (clazz.equals(Integer.class)) {
retVal = (T) Integer.valueOf(from);
} else if (clazz.equals(Long.class)) {
retVal = (T) Long.valueOf(from);
} else if (clazz.equals(Float.class)) {
retVal = (T) Float.valueOf(from);
} else if (clazz.equals(Double.class)) {
retVal = (T) Double.valueOf(from);
} else {
throw new RuntimeException(String.format("Type %s is not supported (yet)", clazz.getName()));
}
return retVal;
}
});
return ImmutableList.copyOf(ids);
}
可以這樣使用:
// Convert List<String> to List<Long>
List<Long> ids = MiscUtils.toNumberList(productIds, Long.class);
是我的代碼過度殺傷力,還是您將如何簡化它,同時又使其足夠通用?
我認為這段代碼最重要的方面是Function
,而不是方法本身。 我也認為切換在Function
主體中允許的子類沒有任何意義,因為您已經知道在創建Function
時要返回的Number
類型。 如果給定的方法(例如BigInteger.class
失敗,這也會有一點問題。
鑒於此,我會做的是創建一個實用工具類(姑且稱之為Numbers
),並提供它的方法,每個回報Function
(可以是一個enum
解析單身) String
作為一種特殊類型的Number
。 那是:
public class Numbers {
public static Function<String, Integer> parseIntegerFunction() { ... }
public static Function<String, Long> parseLongFunction() { ... }
...
}
它們每個都可以這樣實現:
public static Function<String, Integer> parseIntegerFunction() {
return ParseIntegerFunction.INSTANCE;
}
private enum ParseIntegerFunction implements Function<String, Integer> {
INSTANCE;
public Integer apply(String input) {
return Integer.valueOf(input);
}
@Override public String toString() {
return "ParseIntegerFunction";
}
}
然后可以使用此功能,但用戶需要:
List<String> strings = ...
List<Integer> integers = Lists.transform(strings, Numbers.parseIntegerFunction());
與您的方法相比,此方法有很多優點:
Function
進行任何切換...我們知道我們要創建哪種類型的數字,只需執行此操作即可。 快點。 Function
都可以在任何地方使用...用戶不必像您的方法那樣使用它(將轉換后的值復制到ImmutableList
。 Function
。 如果沒有BigInteger
解析函數,則用戶只能調用它,而不是像在您的示例中那樣在編譯時這樣做然后在運行時失敗是完全合法的。 附帶說明一下,我建議將任何返回ImmutableList
方法的返回類型設置為ImmutableList
而不是List
…它提供對方法的客戶端有用的信息。
編輯:
如果您確實需要更多動態的東西(即,您希望具有某些Class<T extends Number>
實例的Class<T extends Number>
能夠將String
轉換為該Number
類型),則還可以添加如下查找方法:
public static <T extends Number> Function<String, T> parseFunctionFor(Class<T> type) {
// lookup the function for the type in an ImmutableMap and return it
}
但是,如果存在一個Number
子類,而您沒有為其提供Function
,則它與原始方法有同樣的問題。 似乎在很多情況下這都沒有用。
為什么不實現幾個轉換器函數並將它們傳遞給Lists.transform()調用?
public class IntegerTransformer extends Function<String, Integer>() {
public Integer apply(String from) {
return Integer.valueOf(from);
}
}
因此,您可以編寫:
Lists.transform(stringValues, new IntegerTransformer());
如果要自動處理類型,則可以添加變壓器工廠或地圖:
static Map<Class,Function<String,?>> transformers = new HashMap<String,?>();
static {
transformers.put(Integer.class, new IntegerTransformer());
transformers.put(Integer.class, new LongTransformer());
...
}
public static Function<String,?> get(Class c) {
Function<String,?> transformer = transformers.get(c);
if(transformer==null) {
throw new RuntimeException(String.format("Type %s is not supported (yet)", clazz.getName()));
}
return transformer;
}
對我來說看上去很好。
既然您具有Class令牌,為什么不避免避免未經檢查的強制轉換,從而抑制警告?
retVal = clazz.cast(Double.valueOf(from));
您可以使用反射,並執行以下操作:
Method m = clazz.getDeclaredMethod("valueOf", String.class);
T str = (T) m.invoke(null, from);
return str;
未經測試,可能很慢。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.