这两种将集合转换为数组对象的方法的区别
Difference in these two approach for converting collection to array object
以下两种将集合转换为数组对象的方法有什么根本区别
ArrayList<String> iName = new ArrayList<String>();
String[] array= iName.toArray(new String[iName.size()]);//1
String[] array= iName.toArray(new String[0]);//2
什么时候应该使用方法 1,什么时候应该使用方法 2?
第一种方法更好,因为您创建了一个数组,toArray
使用它来存储输入列表的元素。第二种方法导致 toArray
创建另一个数组,因为它不能在空数组中存储任何内容。
如果将长度大于输入列表大小的数组传递给方法,您将遇到不同的行为,因为在这种情况下,size
的数组元素(其中size
是输入列表的大小)将被赋值为空。
将小于列表大小的数组传递给方法的唯一情况是,如果您在调用方法时不实例化数组,而是使用预先存在的数组:
array = iName.toArray(array);
在这里您事先不知道 array
是否足够大以包含 iName
的元素。如果不是,toArray
将 return 一个新数组。如果是,toArray
将 return 输入数组。
基本上这两种方法做同样的事情并且会产生相同的输出,但在幕后它们的行为有点不同。
在第一种方法中,由于数组的大小足够大,List 可以将其项目复制到数组中,并且 returns 相同。当您使用第二种方法时,List class 所做的几乎与您的第一种方法完全相同:创建一个具有正确大小的新数组来复制值。
从效率的角度来看:在第一种方法中,创建了一个数组但没有使用这不是一件好事,即使创建一个数组不会花费太多时间或处理能力,但它是多余的,不应该这样做。如果你知道List的大小,所有集合都知道它们的大小,你应该使用第一种方法。
如果您查看实现,您就会明白其中的区别:
public <T> T[] toArray(T[] a) {
if (a.length < size)
// Make a new array of a's runtime type, but my contents:
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}
如果您提供的数组小于 ArrayList,则会创建一个新数组。如果提供的数组比 ArrayList 大,它将用于复制列表后备数组的内容。
就性能而言,最佳做法是使用第一种方法 (iName.toArray(new String[iName.size()])
),但第二种方法的代价并不大(创建 0 大小的数组)。
我个人使用第二种方法,因为我认为它使代码更具可读性。
这两种方式的区别:
String[] array = iName.toArray(new String[iName.size()]);
String[] array = iName.toArray(new String[0]);
如果有可能同时修改源集合(在本例中为 iName
),则完全不同。如果没有并发的可能,那么优先选择第一行。
这并不严格适用于您的示例,其中源集合是 ArrayList
,这不是线程安全的。但是如果源集合是并发集合,那么并发修改下的行为就很重要了。在这种情况下,第一行有竞争条件。调用线程首先获取大小;然后另一个线程可能会添加或删除一个元素,从而改变它的大小。但是随后调用线程分配了 old 大小的数组并将其传递给 toArray
.
这不会导致错误。如果您仔细阅读 Collection.toArray(T[])
的规范,这些案例定义明确。如果集合增长了,就会为其分配一个新数组,从而使调用者的数组分配变得多余。如果集合缩小了,数组的尾部将以空元素结束。这不一定是错误,但任何使用结果数组的代码都必须准备好处理空值,这可能令人不快。
传递零长度数组可以避免这些问题,但可能会分配无用的零长度数组。 (可以保留一个缓存版本,但它会增加混乱。)如果集合为空,则简单地返回零长度数组。但是,如果集合有元素,则集合本身会分配正确大小的数组并填充它。这避免了调用者提交 "wrong" 大小的数组的竞争条件。
在 Java 8 个流中 API,Stream.toArray
method avoids this issue by having the caller pass in an array factory. This lets the caller specify the type but allows the collection to specify the proper size. This hasn't yet been retrofitted to Collections
though. This is covered by an RFE JDK-8060192。
以下两种将集合转换为数组对象的方法有什么根本区别
ArrayList<String> iName = new ArrayList<String>();
String[] array= iName.toArray(new String[iName.size()]);//1
String[] array= iName.toArray(new String[0]);//2
什么时候应该使用方法 1,什么时候应该使用方法 2?
第一种方法更好,因为您创建了一个数组,toArray
使用它来存储输入列表的元素。第二种方法导致 toArray
创建另一个数组,因为它不能在空数组中存储任何内容。
如果将长度大于输入列表大小的数组传递给方法,您将遇到不同的行为,因为在这种情况下,size
的数组元素(其中size
是输入列表的大小)将被赋值为空。
将小于列表大小的数组传递给方法的唯一情况是,如果您在调用方法时不实例化数组,而是使用预先存在的数组:
array = iName.toArray(array);
在这里您事先不知道 array
是否足够大以包含 iName
的元素。如果不是,toArray
将 return 一个新数组。如果是,toArray
将 return 输入数组。
基本上这两种方法做同样的事情并且会产生相同的输出,但在幕后它们的行为有点不同。
在第一种方法中,由于数组的大小足够大,List 可以将其项目复制到数组中,并且 returns 相同。当您使用第二种方法时,List class 所做的几乎与您的第一种方法完全相同:创建一个具有正确大小的新数组来复制值。
从效率的角度来看:在第一种方法中,创建了一个数组但没有使用这不是一件好事,即使创建一个数组不会花费太多时间或处理能力,但它是多余的,不应该这样做。如果你知道List的大小,所有集合都知道它们的大小,你应该使用第一种方法。
如果您查看实现,您就会明白其中的区别:
public <T> T[] toArray(T[] a) {
if (a.length < size)
// Make a new array of a's runtime type, but my contents:
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}
如果您提供的数组小于 ArrayList,则会创建一个新数组。如果提供的数组比 ArrayList 大,它将用于复制列表后备数组的内容。
就性能而言,最佳做法是使用第一种方法 (iName.toArray(new String[iName.size()])
),但第二种方法的代价并不大(创建 0 大小的数组)。
我个人使用第二种方法,因为我认为它使代码更具可读性。
这两种方式的区别:
String[] array = iName.toArray(new String[iName.size()]);
String[] array = iName.toArray(new String[0]);
如果有可能同时修改源集合(在本例中为 iName
),则完全不同。如果没有并发的可能,那么优先选择第一行。
这并不严格适用于您的示例,其中源集合是 ArrayList
,这不是线程安全的。但是如果源集合是并发集合,那么并发修改下的行为就很重要了。在这种情况下,第一行有竞争条件。调用线程首先获取大小;然后另一个线程可能会添加或删除一个元素,从而改变它的大小。但是随后调用线程分配了 old 大小的数组并将其传递给 toArray
.
这不会导致错误。如果您仔细阅读 Collection.toArray(T[])
的规范,这些案例定义明确。如果集合增长了,就会为其分配一个新数组,从而使调用者的数组分配变得多余。如果集合缩小了,数组的尾部将以空元素结束。这不一定是错误,但任何使用结果数组的代码都必须准备好处理空值,这可能令人不快。
传递零长度数组可以避免这些问题,但可能会分配无用的零长度数组。 (可以保留一个缓存版本,但它会增加混乱。)如果集合为空,则简单地返回零长度数组。但是,如果集合有元素,则集合本身会分配正确大小的数组并填充它。这避免了调用者提交 "wrong" 大小的数组的竞争条件。
在 Java 8 个流中 API,Stream.toArray
method avoids this issue by having the caller pass in an array factory. This lets the caller specify the type but allows the collection to specify the proper size. This hasn't yet been retrofitted to Collections
though. This is covered by an RFE JDK-8060192。