这个问题在这里已经有了答案:如何将包含整数的 ArrayList 转换为原始 int 数组? (19 个回答) 3 年前关闭。
我是 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;
}
有没有更好的方法来做到这一点?
这类似于问题How can I convert int[] to Integer[] in Java?。
Integer[] arr = (Integer[])list.toArray(new Integer[list.size]);
在 Java 8 中添加流后,我们可以编写如下代码:
int[] example1 = list.stream().mapToInt(i->i).toArray();
// OR
int[] example2 = list.stream().mapToInt(Integer::intValue).toArray();
思考过程:
简单的 Stream#toArray 返回一个 Object[] 数组,所以它不是我们想要的。此外, Stream#toArray(IntFunction generator) 没有做我们想要的,因为泛型类型 A 不能表示原始类型 int
所以最好有一些流可以处理原始类型 int 而不是包装 Integer,因为它的 toArray 方法很可能还会返回一个 int[] 数组(返回像 Object[] 甚至盒装的 Integer[]在这里会很不自然)。幸运的是,Java 8 有这样一个流,即 IntStream
所以现在我们唯一需要弄清楚的是如何将我们的 Stream
不幸的是,由于 Java 处理原始类型、装箱、数组和泛型的性质,我不相信真的有更好的方法来做到这一点。尤其是:
List
您不能将 int 用作泛型的类型参数,因此它必须是特定于 int 的方法(或使用反射来进行讨厌的诡计的方法)。
我相信有些库对所有原始类型都有这种方法的自动生成版本(即,有一个为每种类型复制的模板)。这很丑陋,但恐怕就是这样:(
即使 Arrays
类在泛型到达 Java 之前就已经出现,但如果它在今天被引入,它仍然必须包含所有可怕的重载(假设您想使用原始数组)。
binarySearch
、copyOf
、copyOfRange
的 Arrays 类中已经存在的可怕重载......?我想知道为什么他们不能添加另一组可怕的重载。
除了 Commons Lang,您还可以使用 Guava 的方法 Ints.toArray(Collection<Integer> collection)
执行此操作:
List<Integer> list = ...
int[] ints = Ints.toArray(list);
这使您不必进行 Commons Lang 等效项需要您自己进行的中间数组转换。
Object[] boxedArray = collection.toArray();
最简单的方法是使用 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 的静态 Integer 数组并让 Java 分配正确大小的数组:
static final Integer[] NO_INTS = new Integer[0];
....
int[] intArray2 = ArrayUtils.toPrimitive(myList.toArray(NO_INTS));
toPrimitive
链接已损坏。
myList.toArray()
将创建一个 Integer[]
并填充它,而 ArrayUtils.toPrimitive()
将分配一个 int[]
并将输入拆箱。
Java 8 为我们提供了一种通过流实现此目的的简单方法......
使用集合 stream()
函数,然后映射到整数,您将获得一个 IntStream。使用 IntStream
我们可以调用 toArray() 给我们 int []
int [] ints = list.stream().mapToInt(Integer::intValue).toArray();
利用:
int[] toIntArray(List<Integer> list) {
int[] ret = new int[list.size()];
int i = 0;
for (Integer e : list)
ret[i++] = e;
return ret;
}
对您的代码进行细微的更改是为了避免昂贵的列表索引(因为列表不一定是 ArrayList,但它可能是一个链表,随机访问的成本很高)。
list.get(i)
为每次访问执行边界检查和填充。我不知道新的解决方案是否真的更好,但至少迈克是这么说的,也许是这样。编辑:我忘记了Java允许索引到一个链表(我习惯了C++的std::list,它不允许它)。所以 arjantop 关于非 ArrayList 的说法也是正确的;即使没有边界检查,索引也不一定很快。
ArrayList
的边界检查是免费的。但是,如果 Java 更遵循 STL 并且只实现真正有意义的方法,我更愿意(LinkedList::get(int)
不这样做,因为它可能会很慢)。
这是一个 Java 8 单行代码:
public int[] toIntArray(List<Integer> intList){
return intList.stream().mapToInt(Integer::intValue).toArray();
}
如果您只是将 Integer
映射到 int
,那么您应该考虑 using parallelism,因为您的映射逻辑不依赖于其范围之外的任何变量。
int[] arr = list.parallelStream().mapToInt(Integer::intValue).toArray();
请注意这一点
请注意,并行性并不会自动比串行执行操作更快,尽管如果您有足够的数据和处理器内核,它可能会更快。虽然聚合操作使您能够更轻松地实现并行性,但您仍然有责任确定您的应用程序是否适合并行性。
有两种方法可以将整数映射到它们的原始形式:
通过 ToIntFunction。 mapToInt(Integer::intValue) 通过使用 lambda 表达式显式拆箱。 mapToInt(i -> i.intValue()) 通过 lambda 表达式的隐式(自动)拆箱。 mapToInt(i -> i)
给定一个具有 null
值的列表
List<Integer> list = Arrays.asList(1, 2, null, 4, 5);
以下是处理 null
的三个选项:
在映射之前过滤掉空值。 int[] arr = list.parallelStream().filter(Objects::nonNull).mapToInt(Integer::intValue).toArray();将空值映射到默认值。 int[] arr = list.parallelStream().map(i -> i == null ? -1 : i).mapToInt(Integer::intValue).toArray();在 lambda 表达式中处理 null。 int[] arr = list.parallelStream().mapToInt(i -> i == null ? -1 : i.intValue()).toArray();
mapToInt(Integer::intValue)
和 mapToInt(i -> i.intValue())
严格相同(表达完全相同的方法调用的两种方式),并且所有三个实际上相同(相同的字节码)。
这个简单的循环总是正确的!没有错误
int[] integers = new int[myList.size()];
for (int i = 0; i < integers.length; i++) {
integers[i] = myList.get(i);
}
List#get(int)
不能保证是一个恒定时间的操作,因此它不应该用于迭代。相反,请使用专为此用例设计的迭代器。使用 Java 5+ foreach 循环或调用 List#iterator()
并使用迭代器。此外,列表的大小可能会在此循环期间发生变化,从而导致 IndexOutOfBoundsException
或不完整的数组。许多迭代器实现都有详细记录的策略来处理这种情况。
我注意到 for 循环的几种用途,但您甚至不需要循环内的任何东西。我提到这一点只是因为最初的问题是试图找到不那么冗长的代码。
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 循环中声明多个声明,我们可以更进一步,执行 for(int i = 0, Iterator it...
最后(这部分只是我的观点),如果你打算有一个帮助功能或方法为你做某事,只需设置它并忘记它。它可以是单行或十行;如果您再也不会看它,您将不会知道其中的区别。
真的没有办法“单线”你正在尝试做的事情,因为 toArray 返回一个 Object[] 并且你不能从 Object[] 转换为 int[] 或 Integer[] 转换为 int[]。
int[] ret = new int[list.size()];
Iterator<Integer> iter = list.iterator();
for (int i=0; iter.hasNext(); i++) {
ret[i] = iter.next();
}
return ret;
也可以试试 Dollar (check this revision):
import static com.humaorie.dollar.Dollar.*
...
List<Integer> source = ...;
int[] ints = $(source).convert().toIntArray();
使用 Eclipse Collections,如果您有类型为 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 Collections 类型,则可以执行以下操作:
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 Collections 的提交者
我建议您使用 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));
}
}
当心装箱/拆箱的缺点。
使用 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);
}
不定期副业成功案例分享
mapTo...
函数不允许null
lambda .... 像 sort 那样....这使其默认为默认行为...在这种情况下,i -> i
将是一个完美的选择默认行为。