java 将 List<String> 转换为 List<Integer>(或任何扩展 Number 的类)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4108970/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Converting a List<String> to a List<Integer> (or any class that extends Number)
提问by Eliseo Soto
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.)
我想创建一个非常通用的实用方法来获取任何 Collection 并将其转换为从 Number(Long、Double、Float、Integer 等)扩展的用户可选类的 Collection
I came up with this code that uses Google Collections to transform the Collection and to return an Immutable List.
我想出了这段代码,它使用 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);
}
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?
我的代码是否矫枉过正,或者您将如何简化它并同时保持足够的通用性?
采纳答案by ColinD
I think the most important aspect of this code is the Function
as opposed to the method itself. I also don't think it makes sense to switch over the subclasses you allow in the Function
body, as you already know what type of Number
you want to return at the time the Function
is created. It's also slightly problematic that your method fails if given, say, BigInteger.class
.
我认为这段代码最重要的方面是Function
方法本身。我也不认为切换您允许在Function
正文中使用的子类是没有意义的,因为您Number
在Function
创建时已经知道要返回的类型。如果给出,例如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 a Function
(which can be an enum
singleton) for parsing a String
as a specific type of Number
. That is:
鉴于此,我要做的是创建一个实用程序类(我们称之为Numbers
)并在其上提供方法,每个方法都返回 a Function
(可以是enum
单例),用于将String
a解析为特定类型的Number
. 那是:
public class Numbers {
public static Function<String, Integer> parseIntegerFunction() { ... }
public static Function<String, Long> parseLongFunction() { ... }
...
}
They could each be implemented something like this:
他们每个人都可以这样实现:
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";
}
}
This can then be used however users want:
然后可以根据用户的需要使用它:
List<String> strings = ...
List<Integer> integers = Lists.transform(strings, Numbers.parseIntegerFunction());
This approach has quite a few advantages over yours:
这种方法比你的方法有很多优点:
- Doesn't require any switching in the
Function
... we know what type of number we're creating and just do that. Faster. - Is more flexible, in that each
Function
can be used wherever... users aren't forced to use it the way your method does (copying the transformed values into anImmutableList
. - You only create the
Function
s you actually want to allow. If there's noBigInteger
parsing 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.
- 不需要任何切换
Function
......我们知道我们正在创建什么类型的数字,然后就可以了。快点。 - 更灵活,因为每个都
Function
可以在任何地方使用......用户不会被迫像您的方法那样使用它(将转换后的值复制到ImmutableList
. - 您只需创建
Function
您实际想要允许的s。如果没有BigInteger
解析函数,用户就不能调用它,而不是在编译时这样做是完全合法的,然后像你的例子那样在运行时失败。
As a side note, I'd recommend making the return type of any method that returns an ImmutableList
be ImmutableList
rather than List
... it provides information that is useful to clients of the method.
作为旁注,我建议为任何返回ImmutableList
be 的方法设置返回类型,ImmutableList
而不是List
... 它提供对方法的客户端有用的信息。
Edit:
编辑:
If you really needsomething more dynamic (i.e. you want classes that have an instance of some Class<T extends Number>
to be able to transform String
s to that Number
type) you could also add a lookup method like:
如果您真的需要更动态的东西(即您希望具有 some 实例的类Class<T extends Number>
能够将String
s 转换为该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
}
This has the same problems as your original method, though, if there's a Number
subclass that you don't provide a Function
for. It also doesn't seem like there would be many situations where this would be useful.
但是,如果Number
您没有提供Function
for的子类,则这与您的原始方法存在相同的问题。似乎也不会在很多情况下这是有用的。
回答by Eugene Kuleshov
Why don't you implement several transformer functions and pass them to Lists.transform() call?
为什么不实现几个转换器函数并将它们传递给 Lists.transform() 调用?
public class IntegerTransformer extends Function<String, Integer>() {
public Integer apply(String from) {
return Integer.valueOf(from);
}
}
So, you could write:
所以,你可以写:
Lists.transform(stringValues, new IntegerTransformer());
If you want to handle types automatically, you can add a transformer factory or a map:
如果你想自动处理类型,你可以添加一个transformer factory或者一个map:
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;
}
回答by Mark Peters
Looks good to me.
对我来说看上去很好。
Since you have the Class token, why not avoid the unchecked cast and thus suppress warnings?
既然你有 Class 标记,为什么不避免未经检查的强制转换,从而抑制警告?
retVal = clazz.cast(Double.valueOf(from));
回答by Stefan Kendall
You could use reflection, and do something like this:
你可以使用反射,并做这样的事情:
Method m = clazz.getDeclaredMethod("valueOf", String.class);
T str = (T) m.invoke(null, from);
return str;
Untested and possible slow.
未经测试,可能很慢。