我想创建一个非常通用的实用程序方法来获取任何Collection并将其转换为从Number(Long,Double,Float,Integer等)扩展的用户可选类的集合
我想出了这个代码,它使用Google Collections来转换Collection并返回一个不可变列表。
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);
我的代码是否过度,或者您如何简化它并同时保持足够通用?
答案 0 :(得分:7)
我认为此代码最重要的方面是Function
而不是方法本身。我也不认为切换Function
正文中允许的子类是有意义的,因为您已经知道Number
时要返回的Function
类型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>
...它提供的信息对于该方法的客户。
修改强>
如果确实需要更动态的内容(即您希望具有某些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
子类,则不提供{{1}}。它似乎也不会有很多情况会有用。
答案 1 :(得分:2)
为什么不实现多个变换器函数并将它们传递给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;
}
答案 2 :(得分:0)
对我来说很好看。
由于您拥有类令牌,为什么不避免未经检查的强制转换,从而抑制警告?
retVal = clazz.cast(Double.valueOf(from));
答案 3 :(得分:-1)
您可以使用反射,并执行以下操作:
Method m = clazz.getDeclaredMethod("valueOf", String.class);
T str = (T) m.invoke(null, from);
return str;
未经测试且可能很慢。