概述
IDEA几乎是Javaer的开发IDE标配。
Call to ‘toArray()’ with pre-sized array argument ‘new String[results.size()]’
在IDEA里阅读代码时遇到如下黄色的代码库,鼠标放置上去,给出如下warning提示:
代码折叠一下:
不难看出这是一个自己实现的org.apache.commons.lang3.StringUtils.split(String str, String separatorChars)
方法,方法最后一行把List<String>
转换成String数组。
按照IDEA的提示,调整后的代码:
return results.toArray(new String[0]);
源码如下:
public static String[] split(String string, String separators) {
if (string == null) {
return null;
} else {
int length = string.length();
if (length == 0) {
return new String[0];
} else {
ArrayList<String> results = new ArrayList<>();
int i = 0;
int start = 0;
boolean tokenInProgress = false;
if (separators == null) {
while (i < length) {
if (Character.isWhitespace(string.charAt(i))) {
if (tokenInProgress) {
results.add(string.substring(start, i));
tokenInProgress = false;
}
++i;
start = i;
} else {
tokenInProgress = true;
++i;
}
}
} else if (separators.length() == 1) {
char separator = separators.charAt(0);
while (i < length) {
if (string.charAt(i) == separator) {
if (tokenInProgress) {
results.add(string.substring(start, i));
tokenInProgress = false;
}
++i;
start = i;
} else {
tokenInProgress = true;
++i;
}
}
} else {
while (i < length) {
if (separators.indexOf(string.charAt(i)) >= 0) {
if (tokenInProgress) {
results.add(string.substring(start, i));
tokenInProgress = false;
}
++i;
start = i;
} else {
tokenInProgress = true;
++i;
}
}
}
if (tokenInProgress) {
results.add(string.substring(start, i));
}
return results.toArray(new String[results.size()]);
}
}
}
分析
Google搜索到如下pinpoint-issue:
Call to ‘toArray()’ with pre-sized array argument ‘new PathMatcher[collection.size()]’
Inspection info: There are two styles to convert a collection to an array: either using a pre-sized array (like c.toArray(new String[c.size()])) or using an empty array (like c.toArray(new String[0]).
In older Java versions using pre-sized array was recommended, as the reflection call which is necessary to create an array of proper size was quite slow. However since late updates of OpenJDK 6 this call was intrinsified, making the performance of the empty array version the same and sometimes even better, compared to the pre-sized version. Also passing pre-sized array is dangerous for a concurrent or synchronized collection as a data race is possible between the size and toArray call which may result in extra nulls at the end of the array,if the collection was concurrently shrunk during the operation.
This inspection allows to follow the uniform style: either using an empty array (which is recommended in modern Java) or using a pre-sized array (which might be faster in older Java versions or non-HotSpot based JVMs).
粗糙翻译中文版
将集合转换为数组有两种方法:
- 使用预先调整大小的数组:
c.toArray(new String[c.size()])
- 使用空数组:
c.toArray(new String[0])
在JDK低版本中,建议使用预先调整大小的数组,因为创建适当大小的数组所需的反射调用非常慢。但在JDK6后,这个调用被内在化(intrinsified),使得空数组版本的性能与预先设置的版本相同,有时甚至更好。另外,传递预先确定大小的数组对于并发或同步的集合是危险的,因为如果集合在操作期间同时减少(元素被删除),那么在size()和toArray()调用之间可能会发生数据竞争,可能会导致数组末尾出现额外的空值。
根据JDK版本不同,选择使用哪一种方法:
- JDK6以后,使用空数组
- JDK6以前,或非HotSpot JVM中,使用预先设置大小的数组