Java 高效数组复制

介绍

实践中经常需要复制数组的一段连续内容, 比如给一个数组追加一个元素形成一个新数组. 那么怎样做才是较快的呢?

测试

方法1: 自己new数组, 然后for循环复制

方法2: 使用 Arrays.copyOf, 或 System.arraycopy. 本质前者是基于后者的, 两者性能相当, 前者多了2次native调用获取数组元素类型和创建数组.

上JMH测benchmark.

@Warmup(iterations = 2, time = 3)
@Measurement(iterations = 3, time = 3)
@State(Scope.Benchmark)
@Fork(1)
public class ArrayCopyPerformanceTest {
    private Object[] array;

    private int n = 100_000;

    @Setup
    public void setup() {
        Random r = new Random(7086);
        array = new Object[n];
        for (int i = 0; i < n; i++) {
            array[i] = r.nextInt();
        }
    }

    @Benchmark
    public void test_slow(Blackhole b) {
        Object[] newArray = new Object[array.length + 1];
        for (int i = 0; i < array.length; i++) {
            newArray[i] = array[i];
        }
        newArray[array.length] = 999;
        b.consume(newArray);
    }

    /**
     * {@link Arrays#copyOf(Object[], int)} 本质也是基于 {@link System#arraycopy(Object, int, Object, int, int)}
     *
     * @param b
     */
    @Benchmark
    public void test_quick(Blackhole b) {
        Object[] newArray = Arrays.copyOf(array, array.length + 1);
        newArray[array.length] = 999;
        b.consume(newArray);
    }

    @Benchmark
    public void test_System_arraycopy(Blackhole b) {
        Object[] newArray = new Object[array.length + 1];
        System.arraycopy(array, 0, newArray, 0, array.length);
        newArray[array.length] = 999;
        b.consume(newArray);
    }
}

 

测试结果

Benchmark                                        Mode  Cnt      Score      Error  Units
ArrayCopyPerformanceTest.test_System_arraycopy  thrpt    3  14178.469 ± 4671.961  ops/s
ArrayCopyPerformanceTest.test_quick             thrpt    3  14373.704 ± 4041.568  ops/s
ArrayCopyPerformanceTest.test_slow              thrpt    3   7180.952 ± 7185.595  ops/s

结论

使用Arrays.copyOf或System.arraycopy的ops是for循环版本的2倍! 经进一步测试, 这个结论在数组较大和较小时都是适用的.

哪怕不进行测试也是很明显的, 既然库函数已经提供这个功能了, 还是native的实现, 那么没道理它的效率比自己for循环实现的版本更低.

 

你可能感兴趣的:(Java)