【发布时间】:2015-10-03 23:58:55
【问题描述】:
当我运行以下代码时,没有输出任何输出。
int[] array = {3, 2, 5, 4};
if (Arrays.asList(array).contains(3))
{
System.out.println("The array contains 3");
}
【问题讨论】:
当我运行以下代码时,没有输出任何输出。
int[] array = {3, 2, 5, 4};
if (Arrays.asList(array).contains(3))
{
System.out.println("The array contains 3");
}
【问题讨论】:
当您将基元数组(在您的情况下为int[])传递给Arrays.asList 时,它会创建一个带有单个元素的List<int[]> - 数组本身。因此contains(3) 返回 false。 contains(array) 将返回 true。
如果您使用Integer[] 而不是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>。
【讨论】:
在 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");
}
【讨论】:
The previous answer 解释了为什么您的方法不起作用。
要实现你喜欢的,你也可以使用Apache Commons Lang这样的工具:
import org.apache.commons.lang.ArrayUtils;
...
int[] array = {3, 2, 5, 4};
ArrayUtils.contains(array, 3);
【讨论】:
Arrays.asList(T... a) 为任何对象类型T 采用T[],它将匹配任何对象 数组(即Object 的子类)。唯一不匹配的是基元数组,因为基元类型不是从Object 派生的。也就是说,int[] 不是Object[] 的(子类)。
然后发生的事情是 varags 机制启动并将其视为您传递了单个对象,并创建了该类型的单个元素数组。因此,您传递了一个 int[][](这里,T 是 int[])并最终得到一个 1 元素 List<int[]>,这不是您想要的。
不过,你仍然有一些不错的选择:
Int.asList(int[]) 适配器如果您的项目已经使用了 guava,那么只需使用 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 对象而不是 ints,这可能会有所回报,但需要注意。
【讨论】:
Arrays.asList 可以做到。