我如何在Java中转换列表<整数>到int[] ?

我很困惑,因为List.toArray()实际上返回一个对象[],它既不能转换为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[]转换为Integer[] ?


当前回答

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

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

要注意这一点

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


有两种方法将integer映射到它们的原始形式:

通过ToIntFunction。 mapToInt(整数::intValue) 通过lambda表达式显式开箱。 mapToInt(i -> i. intvalue ()) 通过隐式(自动)解盒lambda表达式。 mapToInt(i -> i)


给定一个空值的列表

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

这里有三个处理null的选项:

在映射之前过滤掉空值。 int[] arr = list.parallelStream().filter(对象::nonNull).mapToInt(Integer::intValue).toArray(); 将空值映射为默认值。 int[] arr = list.parallelStream()。映射(i -> i == null ?-1:i).mapToInt(Integer::intValue).toArray(); 在lambda表达式中处理null。 int[] arr = list.parallelStream()。mapToInt(i -> i == null ?-1: i.t intvalue ()).toArray();

其他回答

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

列表> < T。toArray不能工作,因为没有从Integer到int的转换 你不能使用int作为泛型的类型参数,所以它必须是一个特定于int的方法(或者使用反射来做讨厌的把戏)。

我相信有些库已经为所有的基本类型自动生成了这种方法的版本(也就是说,每个类型都复制了一个模板)。它很丑,但恐怕就是这样。

即使Arrays类出现在Java泛型出现之前,如果今天引入它(假设您想使用基本数组),它仍然必须包含所有可怕的重载。

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

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

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

小心装箱/拆箱的缺点。

最简单的方法是使用Apache Commons Lang。它有一个方便的ArrayUtils类,可以做任何您想做的事情。将toPrimitive方法与整数数组的重载一起使用。

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

这样你就不用白费力气了。Commons Lang有很多Java遗漏的有用的东西。上面,我选择创建一个大小合适的Integer列表。你也可以使用一个0长度的静态Integer数组,让Java分配一个合适大小的数组:

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

在Java 8中添加流后,我们可以编写如下代码:

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

思维过程:

The simple Stream#toArray returns an Object[] array, so it is not what we want. Also, Stream#toArray(IntFunction<A[]> generator) doesn't do what we want, because the generic type A can't represent the primitive type int So it would be nice to have some stream which could handle the primitive type int instead of the wrapper Integer, because its toArray method will most likely also return an int[] array (returning something else like Object[] or even boxed Integer[] would be unnatural here). And fortunately Java 8 has such a stream which is IntStream So now the only thing we need to figure out is how to convert our Stream<Integer> (which will be returned from list.stream()) to that shiny IntStream. Quick searching in documentation of Stream while looking for methods which return IntStream points us to our solution which is mapToInt(ToIntFunction<? super T> mapper) method. All we need to do is provide a mapping from Integer to int. Since ToIntFunction is functional interface we can provide its instance via lambda or method reference. Anyway to convert Integer to int we can use Integer#intValue so inside mapToInt we can write: mapToInt( (Integer i) -> i.intValue() ) (or some may prefer: mapToInt(Integer::intValue).) But similar code can be generated using unboxing, since the compiler knows that the result of this lambda must be of type int (the lambda used in mapToInt is an implementation of the ToIntFunction interface which expects as body a method of type: int applyAsInt(T value) which is expected to return an int). So we can simply write: mapToInt((Integer i)->i) Also, since the Integer type in (Integer i) can be inferred by the compiler because List<Integer>#stream() returns a Stream<Integer>, we can also skip it which leaves us with mapToInt(i -> i)