运行以下代码时,不会输出任何输出。
int[] array = {3, 2, 5, 4};
if (Arrays.asList(array).contains(3))
{
System.out.println("The array contains 3");
}
答案 0 :(得分:51)
当您将基本数组(在您的情况下为Arrays.asList
)传递给List<int[]>
时,它会创建一个带有单个元素的contains(3)
- 数组本身。因此contains(array)
返回false。 Integer[]
将返回true。
如果您使用int[]
代替Integer[] array = {3, 2, 5, 4};
if (Arrays.asList(array).contains(3))
{
System.out.println("The array contains 3");
}
,则可以使用。
asList
进一步解释:
List<T> asList(T...)
的签名是int[]
。基元不能替换泛型类型参数。因此,当您将int[]
传递给此方法时,整个T
数组将替换List<int[]>
,并获得Integer[]
。另一方面,当您将Integer
传递给该方法时,T
会替换List<Integer>
并获得{{1}}。
答案 1 :(得分:17)
在Java 8中,您根本不需要转换数组;只需通过Arrays#stream
将其转换为流,然后使用anyMatch
谓词查看所需的值是否包含在数组中。
int[] array = {3, 2, 5, 4};
if (Arrays.stream(array).anyMatch(x -> x == 3)) {
System.out.println("The array contains 3");
}
答案 2 :(得分:-1)
Arrays.asList(T... a)
为任何对象类型T[]
提供T
,它将匹配任何对象数组(即Object
的子类)。唯一不匹配的是基元数组,因为基元类型不是从Object
派生的。也就是说,int[]
不是Object[]
的(子类)。
然后发生的是,varags机制启动并将其视为传递单个对象,并创建该类型的单个元素数组。因此,您传递int[][]
(此处,T
为int[]
)并最终得到1个元素List<int[]>
,这不是您想要的。
你仍然有一些不错的选择:
Int.asList(int[])
适配器如果您的项目已经使用了番石榴,那就像使用Guava提供的适配器一样简单:Int.asList()。相关类中的每种基本类型都有一个类似的适配器,例如,Booleans
用于boolean
等。
您的功能可以写成:
int[] array = {3, 2, 5, 4};
if (Ints.asList(array).contains(3))
{
System.out.println("The array contains 3");
}
这种方法的优点是它在现有数组周围创建了一个瘦包装器,因此包装器的创建是恒定时间(不依赖于数组的大小),并且所需的存储空间很小除了基础整数数组之外的常量(小于100个字节)。
缺点是访问每个元素需要底层int
的装箱操作,并且设置需要拆箱。如果您大量访问列表,这可能会导致大量的瞬态内存分配。在您的玩具示例中,搜索期间将只有一个装箱操作,因为该元素立即被找到。类似地,只能稀疏地访问数组的二进制搜索等算法可能会合理地执行。
但是,如果平均多次访问每个对象,最好使用一次将对象装箱并将其存储为Integer
的实现。这可以像制作列表的副本一样简单:new ArrayList<>(Ints.asList(array))
,或者在Java 8中,您可以使用IntStream.boxed()
方法(如下所述)来创建List<Integer>
。两者都应该大致相同。
如Makato的answer所述,您可以使用Arrays.stream(int[])
方法将int
数组转换为Stream
。根据您的使用情况,您可以直接使用流,例如,确定元素3
是否存在,您可以使用IntStream.anyMatch()
。在这种情况下,这个解决方案非常快,根本不会产生任何装箱或拆箱,并且不会创建底层阵列的任何副本。
或者,如果确实需要List<Integer>
,则可以将stream.boxed().collect(Collectors.toList())
用作suggested here。这种方法的缺点是它完全封装了列表中的每个元素,这可能会使其内存占用量增加近一个数量级,它会创建一个新的Object[]
来保存所有盒装元素。如果您随后大量使用该列表并且需要Integer
个对象而不是int
s,这可能会有所回报,但这是值得注意的。