我有一个整数列表,List<Integer>
我想将所有整数对象转换为字符串,从而完成一个新的List<String>
.
自然地,我可以创建一个新的List<String>
并循环调用String.valueOf()
每个整数的列表,但我想知道是否有更好的(阅读:更自动的)方法来做到这一点?
我有一个整数列表,List<Integer>
我想将所有整数对象转换为字符串,从而完成一个新的List<String>
.
自然地,我可以创建一个新的List<String>
并循环调用String.valueOf()
每个整数的列表,但我想知道是否有更好的(阅读:更自动的)方法来做到这一点?
使用来自 Guava-Project 的 Google Collections,您可以使用Lists类transform
中的方法
import com.google.common.collect.Lists;
import com.google.common.base.Functions
List<Integer> integers = Arrays.asList(1, 2, 3, 4);
List<String> strings = Lists.transform(integers, Functions.toStringFunction());
List
返回的是transform
支持列表上的视图- 转换将应用于对转换列表的每次访问。
请注意,当应用于 null 时Functions.toStringFunction()
会抛出 a NullPointerException
,因此只有在您确定列表不包含 null 时才使用它。
Java 8 的解决方案。比 Guava 长一点,但至少您不必安装库。
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
//...
List<Integer> integers = Arrays.asList(1, 2, 3, 4);
List<String> strings = integers.stream().map(Object::toString)
.collect(Collectors.toList());
对于 Java 11,
List<String> strings = integers.stream().map(Object::toString)
.collect(Collectors.toUnmodifiableList());
仍然没有map
方便的方法,真的吗?
据我所知,迭代和实例化是做到这一点的唯一方法。类似的东西(对于其他人的潜在帮助,因为我相信你知道如何做到这一点):
List<Integer> oldList = ...
/* Specify the size of the list up front to prevent resizing. */
List<String> newList = new ArrayList<>(oldList.size());
for (Integer myInt : oldList) {
newList.add(String.valueOf(myInt));
}
你所做的很好,但如果你觉得需要“Java-it-up”,你可以使用Transformer和Apache Commons的collect 方法,例如:
public class IntegerToStringTransformer implements Transformer<Integer, String> {
public String transform(final Integer i) {
return (i == null ? null : i.toString());
}
}
..进而..
CollectionUtils.collect(
collectionOfIntegers,
new IntegerToStringTransformer(),
newCollectionOfStrings);
而不是使用 String.valueOf 我会使用 .toString(); 它避免了@johnathan.holland 描述的一些自动装箱
javadoc 说 valueOf 返回与 Integer.toString() 相同的东西。
List<Integer> oldList = ...
List<String> newList = new ArrayList<String>(oldList.size());
for (Integer myInt : oldList) {
newList.add(myInt.toString());
}
String.valueOf 的来源显示了这一点:
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
这并不重要,但我会使用 toString。
这是一个单线解决方案,无需使用非 JDK 库作弊。
List<String> strings = Arrays.asList(list.toString().replaceAll("\\[(.*)\\]", "$1").split(", "));
另一个使用 Guava 和 Java 8 的解决方案
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<String> strings = Lists.transform(numbers, number -> String.valueOf(number));
不是核心 Java,也不是泛型化的,但流行的 Jakarta commons 集合库对这类任务有一些有用的抽象。具体来说,看看收集方法
如果您已经在项目中使用公共集合,则需要考虑一些事情。
对于在jsight的回答中关注“拳击”的人:没有。String.valueOf(Object)
在这里使用,并且int
从未执行过拆箱。
是使用Integer.toString()
还是String.valueOf(Object)
取决于您希望如何处理可能的空值。您想抛出异常(可能),还是列表中有“空”字符串(可能)。如果是前者,你想抛出一个NullPointerException
还是其他类型?
此外,jsight 的响应中的一个小缺陷:List
是一个接口,您不能在其上使用 new 运算符。在这种情况下,我可能会使用 a java.util.ArrayList
,特别是因为我们预先知道列表可能有多长。
List<String> stringList = integerList.stream().map((Object s)->String.valueOf(s)).collect(Collectors.toList())
使用原始列表中的 forEach 方法的稍微更简洁的解决方案:
List<Integer> oldList = Arrays.asList(1, 2, 3, 4, 5);
List<String> newList = new ArrayList<>(oldList.size());
oldList.forEach(e -> newList.add(String.valueOf(e)));
@Jonathan:我可能弄错了,但我相信 String.valueOf() 在这种情况下会调用 String.valueOf(Object) 函数,而不是装箱到 String.valueOf(int)。如果 String.valueOf(Object) 为 null,则返回“null”;如果为非 null,则调用 Object.toString(),这不应该涉及装箱(尽管显然涉及实例化新的字符串对象)。
我认为将 Object.toString() 用于除调试以外的任何目的可能是一个非常糟糕的主意,即使在这种情况下两者在功能上是等效的(假设列表没有空值)。开发人员可以在没有任何警告的情况下自由更改任何 toString() 方法的行为,包括标准库中任何类的 toString() 方法。
甚至不用担心装箱/拆箱过程带来的性能问题。如果性能很关键,只需使用数组。如果它真的很重要,请不要使用 Java。试图超越 JVM 只会导致心痛。
仅供专家解答:
List<Integer> ints = ...;
String all = new ArrayList<Integer>(ints).toString();
String[] split = all.substring(1, all.length()-1).split(", ");
List<String> strs = Arrays.asList(split);
Lambdaj允许以非常简单易读的方式做到这一点。例如,假设您有一个 Integer 列表,并且您想将它们转换为相应的 String 表示形式,您可以编写类似的内容;
List<Integer> ints = asList(1, 2, 3, 4);
Iterator<String> stringIterator = convertIterator(ints, new Converter<Integer, String> {
public String convert(Integer i) { return Integer.toString(i); }
}
Lambdaj 仅在您对结果进行迭代时应用转换函数。
你无法避免“拳击开销”;Java 的仿通用容器只能存储对象,因此您的 int 必须装箱成 Integer。原则上它可以避免从 Object 到 Integer 的向下转换(因为它没有意义,因为 Object 对于 String.valueOf 和 Object.toString 都足够好),但我不知道编译器是否足够聪明来做到这一点。从 String 到 Object 的转换应该或多或少是无操作的,所以我不愿意担心那个。
只是为了好玩,一个使用 jsr166y fork-join 框架的解决方案,应该在 JDK7 中。
import java.util.concurrent.forkjoin.*;
private final ForkJoinExecutor executor = new ForkJoinPool();
...
List<Integer> ints = ...;
List<String> strs =
ParallelArray.create(ints.size(), Integer.class, executor)
.withMapping(new Ops.Op<Integer,String>() { public String op(Integer i) {
return String.valueOf(i);
}})
.all()
.asList();
(免责声明:未编译。规范未最终确定。等等)
在 JDK7 中不太可能是一些类型推断和语法糖,以使 withMapping 调用不那么冗长:
.withMapping(#(Integer i) String.valueOf(i))
这是一件非常基本的事情,我不会使用外部库(它会导致您的项目中出现您可能不需要的依赖项)。
我们有一类专门用于完成此类工作的静态方法。因为这方面的代码非常简单,所以我们让 Hotspot 为我们做优化。这似乎是我最近代码中的一个主题:编写非常简单(直接)的代码,让 Hotspot 发挥它的魔力。我们很少遇到像这样的代码的性能问题——当一个新的 VM 版本出现时,您可以获得所有额外的速度优势等。
尽管我很喜欢 Jakarta 系列,但它们不支持泛型并且使用 1.4 作为 LCD。我对 Google Collections 很警惕,因为它们被列为 Alpha 支持级别!
我没有看到任何遵循空间复杂性原则的解决方案。如果整数列表有大量元素,那么这是个大问题。
It will be really good to remove the integer from the List<Integer> and free
the space, once it's added to List<String>.
我们可以使用迭代器来实现相同的目的。
List<Integer> oldList = new ArrayList<>();
oldList.add(12);
oldList.add(14);
.......
.......
List<String> newList = new ArrayList<String>(oldList.size());
Iterator<Integer> itr = oldList.iterator();
while(itr.hasNext()){
newList.add(itr.next().toString());
itr.remove();
}
我只是想用一个面向对象的解决方案来解决这个问题。
如果您为域对象建模,那么解决方案就在域对象中。这里的域是我们想要字符串值的整数列表。
最简单的方法是根本不转换列表。
话虽这么说,为了在不转换的情况下进行转换,请将原始整数列表更改为值列表,其中值看起来像这样......
class Value {
Integer value;
public Integer getInt()
{
return value;
}
public String getString()
{
return String.valueOf(value);
}
}
这将比复制列表更快并且占用更少的内存。
祝你好运!