如何在Java中将List<Integer>转换为int[]?

我是Java新手。如何在Java中将List<Integer>转换为int[]

我很困惑,因为List.toArray()实际上返回了一个Object[],它既不能转换为Integer[]也不能转换为int[]

现在我正在使用一个循环来做到这一点:

int[] toIntArray(List<Integer> list) {
int[] ret = new int[list.size()];
for(int i = 0; i < ret.length; i++)
ret[i] = list.get(i);
return ret;
}

有没有更好的方法来做到这一点?

这个问题类似于 如何在Java中将int[]转换为整数[]?.

717235 次浏览

不幸的是,由于Java处理原始类型、装箱、数组和泛型的性质,我不相信真的有更好的方法来做到这一点。

  • List<T>.toArray不会工作,因为没有从Integerint的转换
  • 您不能使用int作为泛型的类型参数,因此将是一个特定于int的方法(或使用反射进行讨厌的欺骗的方法)。

我相信有一些库为所有原始类型自动生成了这种方法的版本(即有一个模板为每种类型复制)。它很丑陋,但恐怕就是这样:(

尽管Arrays类在泛型出现在Java之前就已经出现了,但如果今天引入它,它仍然必须包含所有可怕的重载(假设您想使用原始数组)。

实际上没有办法“单行”你想做的事情,因为toArray返回一个Object[],你不能从Object[]转换为int[]或Integer[]转换为int[]。

最简单的方法是使用Apache Commons Lang。它有一个方便的ArrayUtils类,可以做你想做的事情。使用toPrimitive方法重载Integer数组。

List<Integer> myList;
... assign and fill the list
int[] intArray = ArrayUtils.toPrimitive(myList.toArray(new Integer[myList.size()]));

这样你就不会重新发明轮子。Commons Lang有很多有用的东西Java遗漏了。在上面,我选择创建一个大小合适的整数列表。您也可以使用0长度的静态整数数组,让Java分配一个大小合适的数组:

static final Integer[] NO_INTS = new Integer[0];
....
int[] intArray2 = ArrayUtils.toPrimitive(myList.toArray(NO_INTS));

用途:

int[] toIntArray(List<Integer> list)  {
int[] ret = new int[list.size()];
int i = 0;
for (Integer e : list)
ret[i++] = e;
return ret;
}

对代码的这种轻微更改是为了避免昂贵的列表索引(因为List不一定是ArrayList,但它可能是一个链表,随机访问的成本很高)。

除了Commons Lang之外,您还可以使用番石榴的方法Ints.toArray(Collection<Integer> collection)执行此操作:

List<Integer> list = ...
int[] ints = Ints.toArray(list);

这节省了您必须自己进行Commons Lang等效的中间数组转换。

也可以尝试美元检查此修订):

import static com.humaorie.dollar.Dollar.*
...


List<Integer> source = ...;
int[] ints = $(source).convert().toIntArray();

我建议您使用Java集合API中的List<?>框架实现。在这种情况下,它似乎很有帮助:

package mypackage;


import java.util.AbstractList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;


public class Test {


// Helper method to convert int arrays into Lists
static List<Integer> intArrayAsList(final int[] a) {
if(a == null)
throw new NullPointerException();
return new AbstractList<Integer>() {


@Override
public Integer get(int i) {
return a[i]; // Autoboxing
}
@Override
public Integer set(int i, Integer val) {
final int old = a[i];
a[i] = val; // Auto-unboxing
return old; // Autoboxing
}
@Override
public int size() {
return a.length;
}
};
}


public static void main(final String[] args) {
int[] a = {1, 2, 3, 4, 5};
Collections.reverse(intArrayAsList(a));
System.out.println(Arrays.toString(a));
}
}

小心装箱/拆箱的缺点。

int[] ret = new int[list.size()];
Iterator<Integer> iter = list.iterator();
for (int i=0; iter.hasNext(); i++) {
ret[i] = iter.next();
}
return ret;

使用lambda你可以这样做(在JDK lambda中编译):

public static void main(String ars[]) {
TransformService transformService = (inputs) -> {
int[] ints = new int[inputs.size()];
int i = 0;
for (Integer element : inputs) {
ints[ i++ ] = element;
}
return ints;
};


List<Integer> inputs = new ArrayList<Integer>(5) { {add(10); add(10);} };


int[] results = transformService.transform(inputs);
}


public interface TransformService {
int[] transform(List<Integer> inputs);
}

我注意到进行循环的几种用法,但你甚至不需要循环内部的任何东西。我提到这一点只是因为最初的问题是试图找到不那么冗长的代码。

int[] toArray(List<Integer> list) {
int[] ret = new int[ list.size() ];
int i = 0;
for( Iterator<Integer> it = list.iterator();
it.hasNext();
ret[i++] = it.next() );
return ret;
}

如果Java像C++那样在进行循环中允许多个声明,我们可以更进一步,执行for(int i=0, Iterator it…

最后(这部分只是我的观点),如果你要有一个帮助函数或方法为你做某事,只需设置它并忘记它。它可以是一行或十行;如果你再也不会看它,你就不会知道其中的区别。

通过在Java8中添加流,我们可以编写如下代码:

int[] example1 = list.stream().mapToInt(i->i).toArray();
// OR
int[] example2 = list.stream().mapToInt(Integer::intValue).toArray();

思考过程:

  • 简单的Stream#toArray返回一个Object[]数组,所以它不是我们想要的。此外,Stream#toArray(IntFunction<A[]> generator)也不做我们想要的,因为泛型类型A不能表示原始类型int

  • 所以最好有一些流可以处理原始类型int而不是包装器Integer,因为它的toArray方法很可能也会返回一个int[]数组(返回其他类似Object[]甚至盒装的Integer[]在这里会不自然)。幸运的是Java8有这样一个流,就是IntStream

  • 所以现在我们唯一需要弄清楚的是如何将我们的Stream<Integer>(将从list.stream()返回)转换为闪亮的IntStream

    Stream的留档中快速搜索,同时寻找返回IntStream的方法,将我们指向我们的解决方案mapToInt(ToIntFunction<? super T> mapper)方法。我们需要做的就是提供从Integerint的映射。

    由于ToIntFunction功能接口,我们可以通过lambda方法参考提供它的实例。

    无论如何,要将整数转换为int,我们可以使用Integer#intValue,因此在mapToInt中我们可以编写:

    mapToInt( (Integer i) -> i.intValue() )
    

    (或者有些人可能更喜欢:mapToInt(Integer::intValue)。)

    但是类似的代码可以使用拆箱生成,因为编译器知道这个lambda的结果必须是int类型(mapToInt中使用的lambda是ToIntFunction接口的实现,它期望作为主体的方法类型:int applyAsInt(T value),期望返回int)。

    所以我们可以简单地写:

    mapToInt((Integer i)->i)
    

    此外,由于编译器可以推断(Integer i)中的Integer类型,因为List<Integer>#stream()返回Stream<Integer>,我们也可以跳过它,这给我们留下了

    mapToInt(i -> i)
    

如果您只是将Integer映射到int,那么您应该考虑使用并行,因为您的映射逻辑不依赖于其范围之外的任何变量。

int[] arr = list.parallelStream().mapToInt(Integer::intValue).toArray();

只要意识到这一点

请注意,并行性不会自动比串行执行操作更快,尽管如果您有足够的数据和处理器内核,它可以更快。虽然聚合操作使您能够更轻松地实现并行性,但确定您的应用程序是否适合并行性仍然是您的责任。


有两种方法可以将整数映射到它们的原始形式:

  1. 通过ToIntFunction

    mapToInt(Integer::intValue)
    
  2. Via explicit unboxing with lambda expression.

    mapToInt(i -> i.intValue())
    
  3. Via implicit (auto-) unboxing with lambda expression.

    mapToInt(i -> i)
    

Given a list with a null value

List<Integer> list = Arrays.asList(1, 2, null, 4, 5);

以下是处理null的三个选项:

  1. 在映射之前过滤掉null值。

    int[] arr = list.parallelStream().filter(Objects::nonNull).mapToInt(Integer::intValue).toArray();
    
  2. Map the null values to a default value.

    int[] arr = list.parallelStream().map(i -> i == null ? -1 : i).mapToInt(Integer::intValue).toArray();
    
  3. Handle null inside the lambda expression.

    int[] arr = list.parallelStream().mapToInt(i -> i == null ? -1 : i.intValue()).toArray();
    

使用Eclipse集合,如果您有类型为java.util.List<Integer>的列表,则可以执行以下操作:

List<Integer> integers = Lists.mutable.with(1, 2, 3, 4, 5);
int[] ints = LazyIterate.adapt(integers).collectInt(i -> i).toArray();


Assert.assertArrayEquals(new int[]{1, 2, 3, 4, 5}, ints);

如果你已经有了像MutableList这样的Eclipse集合类型,你可以执行以下操作:

MutableList<Integer> integers = Lists.mutable.with(1, 2, 3, 4, 5);
int[] ints = integers.asLazy().collectInt(i -> i).toArray();


Assert.assertArrayEquals(new int[]{1, 2, 3, 4, 5}, ints);

注意:我是Eclipse集合的提交者

这是一个Java8单行代码:

public int[] toIntArray(List<Integer> intList){
return intList.stream().mapToInt(Integer::intValue).toArray();
}

Java8为我们提供了一种通过流实现此目的的简单方法…

使用集合stream()函数,然后映射到int,您将获得一个IntStream。使用IntStream,我们可以调用toArray(),它给我们int []

int [] ints = list.stream().mapToInt(Integer::intValue).toArray();

到int[]

到IntStream

这个简单的循环总是正确的!没有错误

  int[] integers = new int[myList.size()];
for (int i = 0; i < integers.length; i++) {
integers[i] = myList.get(i);
}