Java Arrays.asList() 不能正常工作?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1467913/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Arrays.asList() not working as it should?
提问by Savvas Dalkitsis
I have a float[] and i would like to get a list with the same elements. I could do the ugly thing of adding them one by one but i wanted to use the Arrays.asList method. There is a problem though. This works:
我有一个 float[] 并且我想获得一个具有相同元素的列表。我可以做一件一件一件丑陋的事情,但我想使用 Arrays.asList 方法。但是有一个问题。这有效:
List<Integer> list = Arrays.asList(1,2,3,4,5);
But this does not.
但这不是。
int[] ints = new int[] {1,2,3,4,5};
List<Integer> list = Arrays.asList(ints);
The asList method accepts a varargs parameter which to the extends of my knowledge is a "shorthand" for an array.
asList 方法接受一个 varargs 参数,据我所知,它是数组的“简写”。
Questions:
问题:
Why does the second piece of code returns a
List<int[]>
but notList<int>
.Is there a way to correct it?
Why doesn't autoboxing work here; i.e.
int[]
toInteger[]
?
为什么第二段代码返回 a
List<int[]>
但不返回List<int>
.有没有办法纠正它?
为什么自动装箱在这里不起作用;即
int[]
到Integer[]
?
采纳答案by JRL
How about this?
这个怎么样?
Integer[] ints = new Integer[] {1,2,3,4,5};
List<Integer> list = Arrays.asList(ints);
回答by ChssPly76
Because java arrays are objects and Arrays.asList()
treats your int array as a singleargument in the varargs list.
因为 java 数组是对象,Arrays.asList()
并将您的 int 数组视为varargs 列表中的单个参数。
回答by Jon Skeet
There's no such thing as a List<int>
in Java - generics don't support primitives.
List<int>
Java 中没有 a 这样的东西- 泛型不支持原语。
Autoboxing only happens for a single element, not for arraysof primitives.
自动装箱仅发生在单个元素上,而不发生在基元数组上。
As for how to correct it - there are various libraries with oodles of methods for doing things like this. There's no way round this, and I don't thinkthere's anything to make it easier within the JDK. Some will wrapa primitive array in a list of the wrapper type (so that boxing happens on access), others will iterate through the original array to create an independent copy, boxing as they go. Make sure you know which you're using.
至于如何纠正它 - 有各种各样的库提供了大量的方法来做这样的事情。没有办法解决这个问题,我认为在 JDK 中没有任何东西可以使它更容易。有些人会包裹在包装类型列表的基本数组(让拳击发生在接入),其他人将通过原始数组迭代,因为他们去建立一个独立的副本,装箱。确保你知道你在使用哪个。
(EDIT: I'd been assuming that the starting point of an int[]
was non-negotiable. If you can start with an Integer[]
then you're well away :)
(编辑:我一直假设 an 的起点int[]
是不可协商的。如果您可以从 an 开始,Integer[]
那么您就大功告成了 :)
Just for one example of a helper library, and to plug Guavaa bit, there's com.google.common.primitive.Ints.asList
.
仅举一个帮助程序库的示例,并稍微插入Guava,有com.google.common.primitive.Ints.asList
.
回答by Tom Neyland
If you pass an int[]
to Arrays.asList()
, the list created will be List<int[]>
, which is not vaild in java, not the correct List<Integer>
.
如果传递int[]
to Arrays.asList()
,则创建的列表将是List<int[]>
,这在 java 中无效,而不是正确的List<Integer>
.
I think you are expecting Arrays.asList()
to auto-box your ints, which as you have seen, it won't.
我认为您希望Arrays.asList()
自动装箱您的整数,正如您所见,它不会。
回答by Michael Borgwardt
The problem is not with Arrays.asList()
. The problem is that you expect autoboxing to work on an array - and it doesn't. In the first case, the compiler autoboxes the individual ints before it looks at what they're used for. In the second case, you first put them into an int array (no autoboxing necessary) and then pass that to Arrays.asList()
(not autoboxing possible).
问题不在于Arrays.asList()
. 问题是您希望自动装箱在数组上工作 - 而事实并非如此。在第一种情况下,编译器在查看它们的用途之前自动装箱单个整数。在第二种情况下,您首先将它们放入一个 int 数组(不需要自动装箱),然后将其传递给Arrays.asList()
(不能自动装箱)。
回答by Maciek Kreft
It's not possible to convert int[]
to Integer[]
, you have to copy values
无法转换int[]
为Integer[]
,您必须复制值
int[] tab = new int[]{1, 2, 3, 4, 5};
List<Integer> list = ArraysHelper.asList(tab);
public static List<Integer> asList(int[] a) {
List<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < a.length && list.add(a[i]); i++);
return list;
}
回答by YoYo
Enter Java 8, and you can do following to collect in a boxed Array:
进入Java 8,您可以执行以下操作来收集盒装数组:
Integer[] boxedInts = IntStream.of(ints).boxed().toArray(Integer[]::new);
Or this to collect in a boxed List
或者这个收集在盒装列表中
List<Integer> boxedInts = IntStream.of(ints).boxed().collect(Collectors.toList());
However, this only works for int[]
, long[]
, and double[]
. This will not work for byte[]
.
然而,这仅适用于int[]
,long[]
和double[]
。这对byte[]
.
Note that Arrays.stream(ints)
and IntStream.of(ints)
are equivalent. So earlier two examples can also be rewritten as:
注意Arrays.stream(ints)
和IntStream.of(ints)
是等价的。所以前面的两个例子也可以改写为:
Integer[] boxedIntArray = Arrays.stream(ints).boxed().toArray(Integer[]::new);
List<Integer> boxedIntList = Arrays.stream(ints).boxed().collect(Collectors.toList());
This last form could be favored as it omits a primitive specific subtype of Stream
. However, internally it is still a bunch of overloaded's which in this case still create a IntStream
internally.
最后一种形式可能会受到青睐,因为它省略了Stream
. 然而,在内部它仍然是一堆重载的,在这种情况下仍然在IntStream
内部创建一个。
回答by BeeOnRope
Arrays.asList(T... a)
effectively takes a T[]
which will match any array of true objects (subclasses of Object
) as an array. The only thing that won't match like that is an array of primitives, since primitive types do not derive from Object
. So an int[]
is not an Object[]
.
Arrays.asList(T... a)
有效地将 aT[]
匹配任何真实对象( 的子类Object
)作为数组。唯一不会像这样匹配的是原始数组,因为原始类型不是从Object
. 所以 anint[]
不是Object[]
。
What happens then is that the varags mechanism kicks in and treats it as if you had passed a single object, and creates a single element array of that type. So you pass an int[][]
(here, T
is int[]
) and end up with a 1-element List<int[]>
which is not what you want.
然后发生的是 varags 机制启动并将其视为您传递了单个对象,并创建该类型的单个元素数组。所以你传递了一个int[][]
(here, T
is int[]
) 并最终得到一个 1-elementList<int[]>
这不是你想要的。
You still have some pretty good options though:
不过,您仍然有一些不错的选择:
Guava's Int.asList(int[])
Adapter
Guava 的Int.asList(int[])
适配器
If your project already uses guava, it's as simple as using the adapter Guava provides: Int.asList(). There is a similar adapter for each primitive type in the associated class, e.g., Booleans
for boolean
, etc.
如果您的项目已经使用了 guava,那么就像使用 Guava 提供的适配器一样简单: Int.asList()。关联类中的每个原始类型都有一个类似的适配器,例如Booleans
forboolean
等。
int foo[] = {1,2,3,4,5};
Iterable<Integer> fooBar = Ints.asList(foo);
for(Integer i : fooBar) {
System.out.println(i);
}
The advantage of this approach is that it creates a thin wrapper around the existing array, so the creation of the wrapper is constant time (doesn't depend on the size of the array), and the storage required is only a small constant amount (less than 100 bytes) in addition to the underlying integer array.
这种方法的优点是它在现有数组周围创建了一个瘦包装器,因此包装器的创建是常数时间(不依赖于数组的大小),并且所需的存储量只是一个很小的常数(小于 100 字节)以及底层整数数组。
The downside is that accessing each element requires a boxing operation of the underlying int
, and setting requires unboxing. This may result in a large amount of transient memory allocation if you access the list heavily. If you access each object many times on average, it may be better to use an implementation that boxes the objects once and stores them as Integer
. The solution below does that.
缺点是访问每个元素需要对底层进行装箱操作int
,设置需要拆箱。如果您大量访问列表,这可能会导致大量的临时内存分配。如果您平均多次访问每个对象,最好使用将对象装箱一次并将它们存储为Integer
. 下面的解决方案就是这样做的。
Java 8 IntStream
Java 8 内部流
In Java 8, you can use the Arrays.stream(int[])
method to turn an int
array into a Stream
. Depending on your use case, you may be able to use the stream directly, e.g., to do something with each element with forEach(IntConsumer)
. In that case, this solution is very fast and doesn't incur any boxing or unboxing at all, and does not create any copy of the underlying array.
在 Java 8 中,您可以使用Arrays.stream(int[])
方法将int
数组转换为Stream
. 根据您的用例,您可以直接使用流,例如,对每个元素使用forEach(IntConsumer)
. 在这种情况下,此解决方案非常快,并且根本不会引起任何装箱或拆箱,并且不会创建底层数组的任何副本。
Alternately, if you really need a List<Integer>
, you can use stream.boxed().collect(Collectors.toList())
as suggested here. The downside of that approach is that it fully boxes every element in the list, which might increase its memory footprint by nearly an order of magnitude, it create a new Object[]
to hold all the boxed elements. If you subsequently use the list heavily and need Integer
objects rather than int
s, this may pay off, but it's something to be aware of.
或者,如果您确实需要List<Integer>
,则可以stream.boxed().collect(Collectors.toList())
按照此处的建议使用。这种方法的缺点是它将列表中的每个元素完全装箱,这可能会将其内存占用增加近一个数量级,它会创建一个新Object[]
元素来保存所有装箱元素。如果您随后大量使用列表并需要Integer
对象而不是int
s,这可能会有所回报,但需要注意。
回答by Stephen C
Why doesn't autoboxing work here; i.e. int[] to Integer[]?
为什么自动装箱在这里不起作用;即 int[] 到 Integer[]?
While autoboxing will convert an int
to an Integer
, it will not convert an int[]
to an Integer[]
.
虽然自动装箱会将 an 转换int
为Integer
,但不会将 an 转换int[]
为Integer[]
。
Why not?
为什么不?
The simple (but unsatisfying) answer is because that is what the JLS says. (You can check it if you like.)
简单(但不令人满意)的答案是因为这就是 JLS 所说的。(如果你喜欢,你可以检查它。)
The real answer is fundamental to what autoboxing is doing and why it is safe.
真正的答案是自动装箱正在做什么以及为什么它是安全的基础。
When you autobox 1
anywhere in your code, you get the same Integer
object. This is not true for all int
values (due to the limited size of the Integer
autoboxing cache), but if you use equals
to compare Integer
objects you get the "right" answer.
当您1
在代码中的任何地方自动装箱时,您将获得相同的Integer
对象。并非所有int
值都如此(由于Integer
自动装箱缓存的大小有限),但如果您equals
用来比较Integer
对象,您会得到“正确”的答案。
Basically N == N
is always true and new Integer(N).equals(new Integer(N))
is always true. Furthermore, these two things remaintrue ... assuming that you stick with Pure Java code.
基本上N == N
永远是真的,new Integer(N).equals(new Integer(N))
永远是真的。此外,这两件事仍然成立……假设您坚持使用纯 Java 代码。
Now consider this:
现在考虑这个:
int[] x = new int[]{1};
int[] y = new int[]{1};
Are these equal? No! x == y
is false and x.equals(y)
is false! But why? Because:
这些是平等的吗?不! x == y
是假的,x.equals(y)
是假的!但为什么?因为:
y[0] = 2;
In other words, two arrays with the same type, size and content are always distinguishable because Java arrays are mutable.
换句话说,具有相同类型、大小和内容的两个数组总是可区分的,因为 Java 数组是可变的。
The "promise" of autoboxing is that it is OK to do because the results are indistinguishable1. But, because all arrays are fundamentally distinguishable because of the definition of equals
for arrays AND array mutability. So, if autoboxing of arrays of primitive types waspermitted, it would undermine the "promise".
自动装箱的“承诺”是可以这样做,因为结果无法区分1。但是,因为equals
数组和数组可变性的定义,所有数组从根本上都是可区分的。所以,如果基本类型数组的自动装箱被允许的,它会破坏“承诺”。
1 - ..... provided that you don't use ==
to test if autoboxed values are equal.
1 - ..... 前提是您不用于==
测试自动装箱值是否相等。
回答by Donald Raab
Alternatively, you can use IntList
as the type and the IntLists
factoryfrom Eclipse Collectionsto create the collection directly from an array of int
values. This removes the need for any boxing of int
to Integer
.
或者,您可以使用Eclipse Collections 中IntList
的类型和IntLists
工厂来直接从值数组创建集合。这消除了对to 的任何装箱的需要。int
int
Integer
IntList intList1 = IntLists.mutable.with(1,2,3,4,5);
int[] ints = new int[] {1,2,3,4,5};
IntList intList2 = IntLists.mutable.with(ints);
Assert.assertEquals(intList1, intList2);
Eclipse Collections has support for mutable and immutable primitive List
as well as Set
, Bag
, Stack
and Map
.
Eclipse的集合具有可变和不可变的原始支持List
,以及Set
,Bag
,Stack
和Map
。
Note: I am a committer for Eclipse Collections.
注意:我是 Eclipse Collections 的提交者。