将List 转换为List (或任何扩展Number的类)

我想创建一个非常通用的实用工具方法来获取任何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} and transforms it into a list of the * specified {@code clazz}. * * @param  * @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  List toNumberList(List stringValues, final Class clazz) { List ids = Lists.transform(stringValues, new Function() { @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 to List List ids = MiscUtils.toNumberList(productIds, Long.class); 

我的代码是否过度杀伤,或者您如何简化它并同时保持足够的通用性?

我认为这个代码最重要的方面是Function ,而不是方法本身。 我也不认为在Function体中切换允许的子类是有意义的,因为您已经知道在创建Function时要返回的Number类型。 如果给出BigInteger.class ,那么你的方法失败也有些问题。

鉴于此,我要做的是创建一个实用程序类(让我们称之为Numbers )并在其上提供方法,每个方法都返回一个Function (可以是一个enum单例),用于将String解析为特定类型的Number 。 那是:

 public class Numbers { public static Function parseIntegerFunction() { ... } public static Function parseLongFunction() { ... } ... } 

他们每个都可以这样实现:

 public static Function parseIntegerFunction() { return ParseIntegerFunction.INSTANCE; } private enum ParseIntegerFunction implements Function { INSTANCE; public Integer apply(String input) { return Integer.valueOf(input); } @Override public String toString() { return "ParseIntegerFunction"; } } 

然后可以使用它,但用户需要:

 List strings = ... List integers = Lists.transform(strings, Numbers.parseIntegerFunction()); 

这种方法比你的方法有很多优点:

  • 不需要在Function进行任何切换……我们知道我们正在创建的数字类型,并且就是这样做的。 快点。
  • 更灵活,因为每个Function都可以在任何地方使用…用户不必像你的方法那样使用它(将转换后的值复制到ImmutableList
  • 您只需创建您想要允许的function。 如果没有BigInteger解析函数,用户就不能调用它,而不是在编译时完全合法,然后在运行时失败,就像在你的例子中一样。

作为旁注,我建议将返回ImmutableList的任何方法的返回类型设置为ImmutableList而不是List …它提供对该方法的客户端有用的信息。

编辑:

如果你真的需要一些更动态的东西(即你希望类具有某个Class的实例能够将String转换为该Number类型),你还可以添加一个查找方法,如:

 public static  Function parseFunctionFor(Class type) { // lookup the function for the type in an ImmutableMap and return it } 

这与原始方法有相同的问题,但是,如果有一个Number子类,则不提供Function 。 它似乎也不会有很多情况会有用。

为什么不实现几个变换器函数并将它们传递给Lists.transform()调用?

  public class IntegerTransformer extends Function() { public Integer apply(String from) { return Integer.valueOf(from); } } 

所以,你可以写:

 Lists.transform(stringValues, new IntegerTransformer()); 

如果要自动处理类型,可以添加变换器工厂或地图:

 static Map> transformers = new HashMap(); static { transformers.put(Integer.class, new IntegerTransformer()); transformers.put(Integer.class, new LongTransformer()); ... } public static Function get(Class c) { Function transformer = transformers.get(c); if(transformer==null) { throw new RuntimeException(String.format("Type %s is not supported (yet)", clazz.getName())); } return transformer; } 

在我看来很好。

既然你有类令牌,为什么不避免未经检查的强制转换,从而抑制警告?

 retVal = clazz.cast(Double.valueOf(from)); 

你可以使用reflection,并做这样的事情:

  Method m = clazz.getDeclaredMethod("valueOf", String.class); T str = (T) m.invoke(null, from); return str; 

未经测试,可能很慢。