89

The toArray method in ArrayList, Bloch uses both System.arraycopy and Arrays.copyOf to copy an array.

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; } 

How can I compare these two copy methods and when should I use which?

3
  • 3
    What is "Bloch"? Why is the code snippet relevant? Commented May 2, 2015 at 13:56
  • 9
    @Ciro Bloch is the guy who wrote the ArrayList implementation. Commented Jun 4, 2015 at 23:33
  • 2
    See also: stackoverflow.com/q/44487304/14955 Commented Jun 12, 2017 at 3:14

10 Answers 10

121

The difference is that Arrays.copyOf does not only copy elements, it also creates a new array. System.arraycopy copies into an existing array.

Here is the source for Arrays.copyOf, as you can see it uses System.arraycopy internally to fill up the new array:

public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) { T[] copy = ((Object)newType == (Object)Object[].class) ? (T[]) new Object[newLength] : (T[]) Array.newInstance(newType.getComponentType(), newLength); System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; } 
Sign up to request clarification or add additional context in comments.

8 Comments

Its obvious....Arrays.copyOf should create a new instance of array as we are not passing one to it; while we pass a destination to System.arraycopy. Regarding speed, again obviously System.arraycopy should win as it is a native method and ultimately Arrays.copyOf also calls this method for copying an array.
The Java source doesn't matter since the intrinsic was created.
also System.arraycopy has more detailed parameters, you can specify start index for both arrays.
public class TestClass { public static void main(String[] args) { byte a[] = { 65, 66, 67, 68, 69, 70, 71, 72, 73, 74 }; System.arraycopy(a, 0, a, 1, a.length - 1); System.out.println(new String(a)); } }
code above prints AABCDEFGHI that means it's creating a new array.
|
46

While System.arraycopy is implemented natively, and is therefore could be1 faster than a Java loop, it is not always as fast as you might expect. Consider this example:

Object[] foo = new Object[]{...}; String[] bar = new String[foo.length]; System.arraycopy(foo, 0, bar, 0, bar.length); 

In this case, the foo and bar arrays have different base types, so the implementation of arraycopy has to check the type of every reference copied to make sure that it is actually a reference to a String instance. That is significantly slower than a simple C-style memcopy of the array contents.

The other point is that Arrays.copyOf uses System.arraycopy under the hood. Therefore System.arraycopy is on the face of it should not be slower than Arrays.copyOf. But you can see (from the code quoted above) that Arrays.copyOf will in some cases use reflection to create the new array. So the performance comparison is not straightforward.

There are a couple of flaws in the analysis of the previous paragraph:

  1. We are looking at the code from a specific version of Java. These methods may change in future vresions, invalidating previous assumptions about efficiency.

  2. We are ignoring the possibility that the JIT compiler could do some clever special case optimization for these methods. And it apparently this does happen with Arrays.copyOf; see Why is Arrays.copyOf 2 times faster than System.arraycopy for small arrays?. This method is marked as "intrinsic" in current-generation Java implementations. That means that the JIT compiler may ignore what is in the Java source code!

But either way, the difference between the two versions is O(1) (i.e. independent of array size) and relatively small. Therefore, my advice would be to use the version that makes your code easiest to read. Only worry about which version is faster if profiling of your application tells you that the difference will actually matter.


1 - It could be faster, but it is also possible that the JIT compiler does such a good job of optimizing a hand-coded loop that there is no difference.

6 Comments

+1 for pointing out the type checking that has to take place sometimes.
@StephenC, Regarding your first paragraph, are there cases where System.arrayCopy could actually be slower?
@Pacerier - I'm not aware of any. But it is not impossible.
A little late on this response but keeping in mind that System.arrayCopy is referenced by Arrays.copyOf (As is mentioned in the accepted answer) I would have to aruge that it is impossible for System.arrayCopy to be slower. This provided, of course, that it is not a custom implementation of JVM with a custom implementation of the methods.
@Wayne - You are making assumptions about the optimizations that JIT compiler does. It is possible that it is completely ignoring the source code / bytecodes that you are looking at. Or that it might do that in some future version of Java. Or that the source code might be different in some other version. Or that there is some clever optimization that can be done on a direct arraycopy call that can't be done on an indirect call. All of these things are possible ... if not plausible.
|
14

If you want an exact copy of an array (say, if you want to do a defensive copy), the most effective way of copying an array is probably using the array object's clone() method:

class C { private int[] arr; public C(int[] values){ this.arr = values.clone(); } } 

I haven't bothered to test the performance of it, but it stands a good chance to be pretty fast since it's all native (allocation and copying in call), and cloning is kind of a special JVM blessed way of copying objects (and it's mostly evil for other purposes) and is likely to be able to take some "shortcuts".

Personally, I'd still use clone if it was slower than any other way of copying, because it's easier to read and nigh-impossible to screw up when writing. System.arrayCopy, on the other hand...

8 Comments

Right, but System.arrayCopy is native as well (and it is dedicated to that task) while clone seem to have to deal with many conditions...
@Pacerier "I don't often use clone... but when I do, I use it on arrays."
I was talking about that .clone() when used on arrays.... In any case, it still returns an Object which must then be casted back into an array (= additional work).
@Pacerier actually it's overloaded with the correct return type for all array types, so you don't have to do any casting yourself, and it's not certain the VM will have to check any casts.
Good point, so you are saying that native clone() will be faster than native System.arrayCopy because clone() is dedicated to this task as well?
|
13

System.arrayCopy is much faster. It's in system because it uses a direct memory copy outside of Java land. Use it when possible.

3 Comments

But System.arraycopy only copies into an existing array. Arrays.copyOf also creates the output array for you.
That's true, and so long as you're using System.arraycopy under the covers whatever convenience wrapper you use is just gravy.
And, there are cases where System.arrayCopy can't use a direct memory copy.
12

Have you looked at the Sun's implementation of Arrays.copyOf()?

 public static int[] copyOf(int[] original, int newLength) { int[] copy = new int[newLength]; System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; } 

As can be seen, it uses System.arraycopy() internally, so the performance would be the same.

Comments

2

System.arrayCopy is implemented natively, and hence will be faster than any Java code. I recommend you to use it.

1 Comment

Just because it uses native code via JNI, it does not mean that it will be faster: javaspecialists.eu/archive/Issue124.html
2

Instead of debating, these are the actual results. Clearly, your choice will depend on how much data you want to copy.

byte[] copy performance test

10,000,000 iterations 40b array.copyOfRange: 135ms systems.arraycopy: 141ms

10,000,000 iterations 1000b array.copyOfRange: 1861ms systems.arraycopy: 2211ms

10,000,000 iterations 4000b array.copyOfRange: 6315ms systems.arraycopy: 5251ms

1,000,000 iterations 100,000b array.copyOfRange: 15,198ms systems.arraycopy: 14783ms

2 Comments

Not sure why the downvote, this was relevant and useful to the discussion.
I would guess, because you did not mention your JDK, OS, HW and did not publish your source-code in order to validate it.
1

I posted this on another answer but may be useful here as well.

I know this is not definitive by any means, as benchmarking these kinds of operations is a science on its own, but just for the fun, I made some tests to compare System.arraycopy and Arrays.copyOfRange.

  • Base array is a String[] array, filled with nulls. The size of the array goes from 10 million to 100 million elements.

  • The array is split 24 times.

  • The elapsed time shows the best time from 3 different launches for each base size.

enter image description here

I don't believe there's enough difference in order to conclude that arraycopy is faster in any way. Also, in order to be complete, the test should also include different split sizes (other than 24), as well as other data types and value-filled arrays (other than null).

Test it online (I tested it locally, but may be useful).


Test code

Common block:

 String[] a = new String[baseSize]; // f.e - 10.000.000 int size = baseSize / 24; int rem = baseSize % 24; 

And for each method:

System.arraycopy

 long start = System.currentTimeMillis(); String[][]pieces = new String[23][size]; String[] last = new String[size + rem]; for (int i = 0; i < 23; i++) System.arraycopy(a, (size * i), pieces[i], 0 , size); System.arraycopy(a, (size * 23), last, 0 ,(size) + rem); long elapsed = System.currentTimeMillis() - start; 

Arrays.copyOfRange

 long start = System.currentTimeMillis(); String[][] pieces = new String[23][]; for (int i = 0; i < 23; i++) pieces[i] = Arrays.copyOfRange(a, size * i, size * (i + 1)); String[] last = Arrays.copyOfRange(a, size * 23, (size * 24) + rem); long elapsed = System.currentTimeMillis() - start; 

The code is easily configurable, so feel free to play with the total pieces to split into, data types, filled arrays and so on. Have fun!

Comments

0

If you look at both the source code for System.arraycopy() of and Array.copyOf(), for performance.

System.arraycopy() is C code, it operates directly on your array, it does not return any values, and because of that it should operate much faster than Array.copyOf(). Nonetheless, if you need a new array to be created or if you just need the value of the copy operation then you have to create a new array for that, set the new array length, etc... Thus, you can't do a return System.arraycopy(source, 0, destination, 0, length).

For what Array.copyOf() can do then, it make a new array for you. You can assign the return value from Array.copyOf() to an array or returning it from a method as Array.copyOf() return to you a value instead of operating directly on your destination array. Thus, your code will look much cleaner. Nonetheless, for the cost of performance, Array.copyOf() is a generic type method and it does not know ahead of time what it will be working with. Thus, it has to call Array.newInstance() or new Object() and then cast it to the input's array type.

So to sum up. Use System.arraycopy() because of performance. Use Array.copyOf() for cleaner code.

1 Comment

Not true -- copyOf is overloaded with a method for each primitive type.
-1
 class ArrayCopyDemo { public static void main(String[] args) { char[] copyFrom = { 'd', 'e', 'c', 'a', 'f', 'f', 'e', 'i', 'n', 'a', 't', 'e', 'd' }; char[] copyTo = new char[7]; System.arraycopy(copyFrom, 2, copyTo, 0, 7); System.out.println(new String(copyTo)); } } 

1 Comment

This doesn't answer the question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.