在Java中将'ArrayList<String>'转换为'String[]'

1271

我该如何在Java中将一个ArrayList<String>对象转换为String[]数组?


4
已经使用更新的方法回答了这个问题,该方法针对 JDK-11 引入的新的、与 Stream.toArray 语法相似且同样高效的 toArray(T[]) API 进行了优化。 - Naman
17个回答

2078
List<String> list = ..;
String[] array = list.toArray(new String[0]);
例如:
List<String> list = new ArrayList<String>();
//add some stuff
list.add("android");
list.add("apple");
String[] stringArray = list.toArray(new String[0]);
toArray()方法不带参数返回Object[]数组。因此,您需要将一个数组作为参数传递进去,该数组将填充来自列表中的数据并被返回。您可以传递一个空数组,也可以传递一个具有所需大小的数组。 重要更新:最初的代码使用了new String[list.size()]。然而,这篇博客文章揭示了由于JVM的优化,现在使用new String[0]更好。

它在logcat中显示了这个警告:转换为字符串:TypedValue {t = 0x12 / d = 0x0 a = 3 r = 0x7f050009} - Adil Malik
@ThorbjørnRavnAndersen:数组的尺寸在功能上并没有影响,但如果您传入正确尺寸的数组,可以节省JVM重新调整数组大小的工作。 - sferencik
76
事实证明,即使是创建并丢弃一个长度为零的数组,平均而言也比分配正确大小的数组要快。有关基准测试和解释,请参见此处:http://shipilev.net/blog/2016/arrays-wisdom-ancients/ - Stuart Marks
3
在Java中,拥有泛型类型并不足以实际创建基于该类型的对象;甚至一个数组也不行(这很荒谬,因为它应该适用于任何类型)。据我所知,它所能做的就是进行转换。事实上,要想创建该类型的对象,甚至需要拥有实际的“Class”对象,而从泛型类型推导出“Class”对象似乎完全不可能。正如我所说,原因在于整个构造都是虚假的;它全部在内部作为Object存储。 - Nyerguds
@Bozho,从你所喜欢的文章中可以得出结论:toArray(new T [0])似乎更快、更安全,而且契约上更干净,因此现在应该是默认选择。未来的VM优化可能会缩小toArray(new T [size])的性能差距,使得当前“被认为是最佳”的用法与实际最佳用法相当。toArray API的进一步改进将遵循与toArray(new T [0])相同的逻辑-集合本身应创建适当的存储器。 - jsears
显示剩余3条评论

258

Java 8中的一种替代方案:

String[] strings = list.stream().toArray(String[]::new);

Java 11+:

String[] strings = list.toArray(String[]::new);

28
还有任何好处吗? - James Watkins
1
我更喜欢那种语法,但是IntelliJ会显示编译器错误,并抱怨“T[]不是一个功能接口”。 - Glen Mazza
3
你只能在 Stream 对象上使用 toArray 方法。如果你使用 Collectors 对流进行 reduce 操作并试图应用 toArray,可能会导致编译错误。我建议你检查代码并确保只对 Stream 对象调用 toArray 方法。 - Udara Bentota
2
@JohnStrood String[]::new 相当于 i -> new String[i]。请参见 https://dev59.com/4F0b5IYBdhLWcg3wOvCd - Unmitigated
@JohnStrood 没问题。 - Unmitigated
显示剩余4条评论

55

从Java-11开始,可以使用APICollection.toArray(IntFunction<T[]> generator)来实现与以下代码相同的功能:

List<String> list = List.of("x","y","z");
String[] arrayBeforeJDK11 = list.toArray(new String[0]);
String[] arrayAfterJDK11 = list.toArray(String[]::new); // similar to Stream.toArray

49
你可以使用 toArray() 方法来处理 List:
ArrayList<String> list = new ArrayList<String>();

list.add("apple");
list.add("banana");

String[] array = list.toArray(new String[list.size()]);

或者您可以手动将元素添加到数组中:

ArrayList<String> list = new ArrayList<String>();

list.add("apple");
list.add("banana");

String[] array = new String[list.size()];

for (int i = 0; i < list.size(); i++) {
    array[i] = list.get(i);
}

希望这能有所帮助!


33
ArrayList<String> arrayList = new ArrayList<String>();
Object[] objectList = arrayList.toArray();
String[] stringArray =  Arrays.copyOf(objectList,objectList.length,String[].class);

使用copyOf,也可以将ArrayList转换为数组。


4
建议使用驼峰命名法,例如将"objectList = ..."改为"objectList = ...",将"stringArray"保持不变。另外,正确的方法名应该是"Arrays.copyOf",注意其中的大写字母"O"。 - Jason Weden
1
list.toArray() 内部使用 Arrays.copyOf()。 - David

11

在Java 8中:

String[] strings = list.parallelStream().toArray(String[]::new);

13
这已经在这个答案中被包含了。也许你可以将它作为那个答案的编辑,而不是新的答案。 - River
16
为什么要使用 parallelStream() 而不是简单地使用 stream() - Yoory N.

8

在Java 8中,可以使用以下方式实现:

String[] arrayFromList = fromlist.stream().toArray(String[]::new);

6
如果您的应用程序已经使用了Apache Commons库,您可以稍微修改接受的答案,以避免每次创建新的空数组:
List<String> list = ..;
String[] array = list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);

// or if using static import
String[] array = list.toArray(EMPTY_STRING_ARRAY);

ArrayUtils中还有几个预分配的不同类型的空数组。

此外,我们可以通过以下方式欺骗JVM为我们创建一个空数组:

String[] array = list.toArray(ArrayUtils.toArray());

// or if using static import
String[] array = list.toArray(toArray());

但实际上这样做没有任何优势,只是个人口味而已。以我的看法来看,这并不重要。


6
您可以使用Iterator<String>来迭代ArrayList<String>的元素:
ArrayList<String> list = new ArrayList<>();
String[] array = new String[list.size()];
int i = 0;
for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); i++) {
    array[i] = iterator.next();
}

现在您可以使用任何循环从String[]中检索元素。

我点踩了因为:1.没有使用泛型,这会强制你使用.toString(),而不需要显式转换,2.你甚至没有增加i,3.while最好被for替换。建议的代码:ArrayList<String> stringList = ... ; String[] stringArray = new String[stringList.size()]; int i = 0; for(Iterator<String> it = stringList.iterator(); it.hasNext(); i++) { stringArray[i] = it.next(); } - Olivier Grégoire
好的,我现在明白了。谢谢。 - Vatsal Chavda
理想情况下,您应该编辑您的代码以包含那些注释(也就是说...如果您认为它们对您的答案有好处!)。只要代码保持不变,我就不会考虑取消我的踩票。 - Olivier Grégoire
我是新来的,所以还不知道这里的运作方式。不过,感谢你的帮助,伙计。 - Vatsal Chavda
这好多了!我只进行了一点点编辑,但您刚刚体验了它的工作原理:提供答案,改善它们,然后获得荣誉 ;) - Olivier Grégoire

6
    List<String> list = new ArrayList<>();
    list.add("a");
    list.add("b");
    list.add("c");
    String [] strArry= list.stream().toArray(size -> new String[size]);

根据评论,我已经添加了一段说明如何进行转换。首先,List被转换为String流。然后使用Stream.toArray将流中的元素转换为数组。在上面的最后一个语句中,“size -> new String [size]”实际上是一个IntFunction函数,它分配具有String流大小的String数组。该语句与以下语句相同。

IntFunction<String []> allocateFunc = size -> { 
return new String[size];
};   
String [] strArry= list.stream().toArray(allocateFunc);

4
这个回答有什么价值?它似乎只是重复了其他回答,没有解释为什么回答了这个问题。 - Richard

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接