I want to create a very generic utility method to take any Collection and convert it into a Collection of a user selectable class that extends from Number (Long, Double, Float, Integer, etc.)
I came up with this code that uses Google Collections to transform the Collection and to return an Immutable List.
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);
}
It can be used like this:
// Convert List<String> to List<Long>
List<Long> ids = MiscUtils.toNumberList(productIds, Long.class);
Is my code overkill or how would you simplify it and at the same time keep it generic enough?
I think the most important aspect of this code is the
Functionas opposed to the method itself. I also don’t think it makes sense to switch over the subclasses you allow in theFunctionbody, as you already know what type ofNumberyou want to return at the time theFunctionis created. It’s also slightly problematic that your method fails if given, say,BigInteger.class.Given this, what I would do is create a utility class (let’s call it
Numbers) and provide methods on it that each return aFunction(which can be anenumsingleton) for parsing aStringas a specific type ofNumber. That is:They could each be implemented something like this:
This can then be used however users want:
This approach has quite a few advantages over yours:
Function… we know what type of number we’re creating and just do that. Faster.Functioncan be used wherever… users aren’t forced to use it the way your method does (copying the transformed values into anImmutableList.Functions you actually want to allow. If there’s noBigIntegerparsing function, users just can’t call that, as opposed to having it be completely legal to do that at compile time and then fail at runtime like in your example.As a side note, I’d recommend making the return type of any method that returns an
ImmutableListbeImmutableListrather thanList… it provides information that is useful to clients of the method.Edit:
If you really need something more dynamic (i.e. you want classes that have an instance of some
Class<T extends Number>to be able to transformStrings to thatNumbertype) you could also add a lookup method like:This has the same problems as your original method, though, if there’s a
Numbersubclass that you don’t provide aFunctionfor. It also doesn’t seem like there would be many situations where this would be useful.