将List <Integer>转换为List <String>


105

我有一个整数列表,List<Integer>我想将所有整数对象都转换为String,从而以new结束List<String>

自然地,我可以创建一个新的List<String>并遍历列表以调用String.valueOf()每个整数,但是我想知道是否有更好的方法(阅读:更自动化)?

Answers:


77

据我所知,迭代和实例化是实现此目的的唯一方法。诸如此类的东西(对于其他潜在的帮助,因为我确定您知道该怎么做):

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)); 
}

简单的时候,这就是美。
易北河2012年

1
原始海报似乎表明他已经想到了这一点,但认为此解决方案过于复杂或乏味。但是我很难想象会更容易些。是的,有时您必须编写3或4行代码才能完成工作。
杰伊

但这将您绑定到ArrayList。可以使用与原始列表相同的实现方式来完成此操作吗?
alianos-

@Andreas oldList.getClass()。newInstance()将起作用
Lluis Martinez

96

使用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是一个视图背衬列表上-变换将在每个访问变换表来施加。

请注意,Functions.toStringFunction()将其NullPointerException应用于null时将抛出a ,因此仅在确定列表不包含null时才使用它。


1
如果在Functions.toStringFunction()之外还有更多现成的函数,那将是很好的选择
ThiamTeck 2010年

1
干净,但可能没有那么快。.每个值1个额外的函数调用?
h3xStream 2010年

3
HotSpot可以内联函数调用-因此,如果调用足够多,则不应有所作为。
Ben Lings 2010年

3
我不会对此表示反对,因为这确实是一个解决方案。但是,鼓励人们增加库依赖来解决这种简单的任务对我来说是不行的。
estani 2014年

1
如果您已经在我们的解决方案中使用了番石榴,则是一个不错的解决方案。
dudinha-dedalus

86

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());

1
尽管此toString示例的时间更长,但是对于Guava的Functions库不支持的转换,它最终会更短。自定义函数仍然很容易,但是比Java 8流要多得多的代码
lightswitch05

40

你在做什么是好的,但如果你觉得有必要的Java-它一起“你可以使用一个变压器收集方法,从Apache的共享,例如:

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);

1
CollectionUtils.collect(collectionOfIntegers,新的org.apache.commons.collections.functors.StringValueTransformer()); 但是,StringValueTransformer使用String.valueOf ...
Kannan Ekanath 2010年

5
除非在apache集合上完成了新工作,否则它们不会做泛型。
KitsuneYMG 2010年

1
这确实使Java崩溃了。这不是惯用的Java,更像是函数式编程。也许当我们在Java 8中获得闭包时,可以将其称为惯用Java。
ChristofferHammarström2012年

你一定要使用Collections4为(不老3.x的集合),用于支持仿制药:commons.apache.org/proper/commons-collections/apidocs/org/...
JRA_TLL

定义一个新类只是为了“更多面向对象或惯用语” ...我不认为这比简单的for-each循环更好。它需要更多代码并将功能移开(匿名类可以缓解,但仍然可以)。仅当存在适当的语法(即Java 8之后的lambda表达式)时,这种功能样式才开始变得有用,就像功能语言已经提供了数十年一样。
TheOperator '16

9

String.valueOf的源显示如下:

public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();
}

并不是很重要,但是我会使用toString。


9

而不是使用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()); 
}

正如汤姆·哈顿(Tom Hawtin)在“获奖”答案中指出的那样,不能实例List <String>,因为它只是一个接口。
Stu Thompson

嘿,我知道。我只是在不尝试的情况下编写了代码。我会在我的答案中修复它。
ScArcher2

9

这是一种单行解决方案,无需与非JDK库作弊。

List<String> strings = Arrays.asList(list.toString().replaceAll("\\[(.*)\\]", "$1").split(", "));

7

使用Guava和Java 8的另一种解决方案

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<String> strings = Lists.transform(numbers, number -> String.valueOf(number));

3

它不是Java的核心,也不是通用的,但是流行的Jakarta Commons Collections库为此类任务提供了一些有用的抽象。具体来说,看看下面的collect方法

实用工具

如果您已经在项目中使用了commons集合,请考虑一下。


4
切勿使用Apache Collections。它们是旧的,过时的,不是类型安全的并且编写得不好。
KitsuneYMG 2010年

3

对于那些关心“拳击”的人们,jsight的回答是:没有。String.valueOf(Object)在这里使用,并且int从未执行过拆箱操作。

使用Integer.toString()还是String.valueOf(Object)取决于要如何处理可能的null。您是否要抛出异常(可能),或者列表中包含“空”字符串(也许)。如果是前者,是否要抛出a NullPointerException或其他类型?

另外,jsight响应中的一个小缺陷:List接口,您不能在其上使用new运算符。java.util.ArrayList在这种情况下,我可能会使用a ,尤其是因为我们预先知道该列表可能会持续多长时间。



2

@乔纳森:我可能会误会,但我相信在这种情况下,String.valueOf()会调用String.valueOf(Object)函数,而不是装箱成String.valueOf(int)。String.valueOf(Object)如果为null,则仅返回“ null”;如果非null,则调用Object.toString(),这不应该涉及装箱(尽管显然要实例化新的字符串对象)。


2

我认为将Object.toString()用于除调试以外的其他目的可能是一个非常糟糕的主意,即使在这种情况下,两者在功能上是等效的(假定列表中没有空值)。开发人员可以自由更改任何toString()方法的行为而不会发出任何警告,包括标准库中任何类的toString()方法。

甚至不用担心装箱/拆箱过程导致的性能问题。如果性能至关重要,则只需使用一个阵列即可。如果确实很关键,请不要使用Java。试图超越JVM只会导致心痛。


2

仅针对专家的答案:

    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);

这有效,但以效率低下为代价。Java字符串是每个字符两个字节,因此“,”会在对整数本身进行计数之前,为每个整数添加四个字节的固定成本。
罗伯特·克里斯蒂安

我认为就原始CPU周期效率而言,正则表达式可能是一个更大的问题。在内存方面,我猜想一个合理的实现(假设的“ Sun”不合理的实现String)将共享相同的后备数组(来自all),因此实际上实际上将具有相当高的内存效率,这对于长期性能至关重要。除非您只想保留其中一个要素,否则……
汤姆·霍顿

2

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仅在迭代结果时才应用转换功能。


1

您无法避免“装箱费用”;Java的伪通用容器只能存储对象,因此必须将int装箱为Integers。原则上,它可以避免从Object到Integer的贬低(因为它毫无意义,因为Object对于String.valueOf和Object.toString都足够好),但我不知道编译器是否足够聪明。从String到Object的转换应该或多或少是无操作的,因此我不希望为此担心。


编译器不够聪明,无法做到这一点。当javac运行时,它实际上会剥离所有泛型类型信息。泛型集合的基础实现始终存储对象引用。实际上,您可以省略<T>参数化并获得“原始”类型。“列表l =新的List()”与“ List <String> l =新的List <String>()”。当然,这意味着“ List <String> l =(List <String>)new List <Integer>()”实际上会编译并运行,但是显然非常危险。
Dave Dopson 2011年

1

我没有看到遵循空间复杂性原理的任何解决方案。如果整数列表包含大量元素,那么这将是一个大问题。

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();
    }

1

使用流:如果说结果是整数列表(List<Integer> result),则:

List<String> ids = (List<String>) result.stream().map(intNumber -> Integer.toString(intNumber)).collect(Collectors.toList());

解决它的方法之一。希望这可以帮助。


1

使用原始列表中的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)));

0

只是为了好玩,一个应该在JDK7中使用jsr166y fork-join框架的解决方案。

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))

0

这是一件非常基本的事情,我不会使用外部库(这会导致您的项目中可能不需要的依赖项)。

我们有一类专门设计用于完成此类工作的静态方法。因为此代码非常简单,所以让Hotspot为我们进行优化。最近,这似乎是我的代码的主题:编写非常简单(直接)的代码,然后让Hotspot发挥作用。我们很少会遇到类似这样的代码的性能问题-当出现新的VM版本时,您将获得所有额外的速度优势等。

尽管我非常喜欢Jakarta系列,但它们不支持Generics,并使用1.4作为LCD。我对Google Collections保持警惕,因为它们被列为Alpha支持级别!


-1

我只是想用面向对象的解决方案来解决这个问题。

如果您对域对象建模,则解决方案将在域对象中。这里的域是我们想要字符串值的整数列表。

最简单的方法是根本不转换列表。

话虽如此,为了不进行转换就将Integer的原始列表更改为Value列表,其中Value看起来像这样...

class Value {
    Integer value;
    public Integer getInt()
    {
       return value;
    }
    public String getString()
    {
       return String.valueOf(value);
    }
}

与复制列表相比,这将更快并且占用更少的内存。

祝好运!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.