Java超大数组转List:Arrays.asList与AbstractList性能问题排查
超大数组转List并追加元素的性能问题
场景
需要将一个超大数组高效转换为List并追加一个元素,自定义简化版AbstractList实现的方法性能表现优异。
问题
直接使用Arrays.asList(String element, String[] elements)无法满足需求(该方法本应高效),其他看似直接的实现方式均存在严重性能问题。
性能不佳的实现示例
protected static <T> List<T> slowAsList(final T last, final T... elements) { //1 return IntStream.rangeClosed(0, length) .mapToObj(i -> i < length ? elements[i] : last) .collect(Collectors.toList()); //2 return Stream.concat(Stream.of(first), Arrays.stream(elements)) .parallel() .collect(Collectors.toList()); //3 return new ArrayList() {{ for (Object o : elements) add(o); add(last); }}; //4 final ArrayList arrayList = new ArrayList(); arrayList.add(last); for (Object o : elements) arrayList.add(o); return arrayList; //5 final int arrayLen = elements.length + 1; final Object[] array = Arrays.copyOf(elements, arrayLen); for (int i = 1; i < arrayLen; i++) { array[i] = elements[i - 1]; } array[arrayLen - 1] = last; return Arrays.asList(array); }
上述方法在JUnit测试中会停滞,无法在合理时间内完成:
@Timeout(15) @Test public void fastAsListTest() { final Object[] testStrings1MwithNull = IntStream.rangeClosed(0, 1000000) .mapToObj(i -> i == 1000000 ? null : "TEST" + i) .toArray(); slowAsList(testStrings1MwithNull); }
高效实现
改用基于AbstractList的变体实现后,测试仅需数毫秒即可完成:
protected static <T> List<T> fastAsList(final T last, final T... elements) { if (elements == null) { return null; } return new AbstractList<T>() { @Override public int size() { return elements.length; } @Override public T get(int index) { return index < 0 ? null : elements[index]; } }; }
编辑说明:
原代码以first为追加元素:
protected static List<Object> asList(final Object first, final Object[] elements) { return new AbstractList<Object>() { @Override public int size() { return elements.length + 1; // return elements != null ? elements.length + 1 : 0; } @Override public Object get(int index) { return (index == 0) ? first : elements[index - 1]; // return (index == 0) ? first : elements!= null ? elements[index - 1] : null; } };
注释部分为新增的空值检查,用于避免elements为null时触发com.sun.jdi.InvocationException。
编辑2:尝试将高效代码作为内联Collector集成到Stream中,结果性能依旧不佳:
final int length = elements.length; return IntStream.rangeClosed(0, length) .mapToObj(i -> i < length ? elements[i] : null) .collect(() -> new AbstractList<T>() { @Override public int size() { return elements == null ? null : elements.length; } @Override public T get(int index) { return index < 0 ? null : elements[index]; } }, (a,b) -> {return;}, (a,b) -> {return;} );
疑问
该性能问题的原因是什么?是否是内存不足导致的?已将测试的Xms/Xmx调整为2G/6G,Windows系统总内存16G,当前内存占用约83%,但调整内存参数后问题无改善。
编辑3:目前唯一能达到相近性能的方案是仅包装数组的Arrays.asList(),但无法追加元素:
protected static <T> List<T> fastAsList(final T... elements) { return elements == null ? null : Arrays.asList(elements); }
内容的提问来源于stack exchange,提问作者fozzybear
相关产品推荐
相关产品推荐

