Difference between various Array copy methods - java

What is the difference between
System.arraycopy(),
clone()
manual copying by iterating through the elements
Arrays.copyOf()
and just doing arraynew = arrayold?

System.arraycopy() uses JNI (Java Native Interface) to copy
an array (or parts of it), so it is
blazingly fast, as you can confirm
here;
clone() creates a new array with the same characteristics as the old array, i.e., same size, same type, and same contents. Refer to here for some examples of clone in action;
manual copying is, well, manual copying. There isn't much to say about this method, except that many people have found it to be the most performant.
arraynew = arrayold doesn't copy the array; it just points arraynew to the memory address of arrayold or, in other words, you are simply assigning a reference to the old array.

System.arraycopy() copies data from one existing array into another one and depending on the arguments only copies parts of it.
clone() allocates a new array that has the same type and size than the original and ensures that it has the same content.
manual copying usually does pretty much the same thing than System.arraycopy(), but is more code and therefore a bigger source for errors
arraynew = arrayold only copies the reference to the array to a new variable and doesn't influence the array itself
There is one more useful option:
Arrays.copyOf() can be used to create a copy of another array with a different size. This means that the new array can be bigger or larger than the original array and the content of the common size will be that of the source. There's even a version that makes it possible to create an array of a different type, and a version where you can specify a range of elements to copy (Array.copyOfRange()).
Note that all of those methods make shallow copies. That means that only the references stored in the arrays are copied and the referenced objects are not duplicated.

Arrays.copyOf(..) uses System.arrayCopy(..) method internally.

There are answers but not a complete one.
The options considered are
Arrays.copyOf()
System.arraycopy()
Below is the java implementation of Arrays.copyOf()
public static double[] More ...copyOf(double[] original, int newLength) {
double[] copy = new double[newLength];
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
As you can see copyOf uses System.arraycopy internally.
If you already have an array created use System.arraycopy() to copy
If you need the result in a new array use Arrays.copyOf() to copy
Note: There is no point in comparing the speed obviously because their functionalities differ.

Related

Is it bad practice to return an array of objects directly?

For example, if we have a class and one of its method returns an object, we should return a deep copy of the object.
For example, before returning an array of integers, we should also make a deep copy/clone the array before returning it.
Is this also the case for an array of Objects? For example I have an array of objects of type packages:
//trunk[] is an instance variable array that contains objects of type Package in this class
//method to return array
public Package[] getTrunk() {
Package[] temp = new Package[trunk.length];
for(int i = 0; i < trunk.length; i++) {
temp[i] = trunk[i];
}
return temp;
}
Is there any use of using the for loop here since objects are reference types? If not, how should I return the array correctly?
If you return the trunk array, the caller can modify the trunk array. If you return a copy of the trunk array, the caller cannot modify the trunk array.
Do you care whether the caller can modify the trunk array?
The answer to that in part depends on who the caller is. If it's my code calling my code, and I know I'm not modifying the array, just looking at it and not even retaining a copy, then returning the actual array may be fine. Not every interface needs to be idiot-proof; idiot-proofing has a price tag.
(I see this is a 'public' interface but that might just mean a multi-package pre-module product structure)
To my mind, you shouldn't worry about some mythical "best practice", you should worry about how you want the software to behave.
There is no difference between an array of primitives and an array of complex types (Objects of some kind) regarding this question. So in general you can say, yes, you should only return a copy.
But there are some exceptions where not returning a copy may be the intended, because:
You actually want to caller to be able to manipulate the backed array
Copying takes time. Some core Java classes don't return a copy to avoid the overhead (e.g. ByteBuffer#array())

What exactly is wrong with newarray = oldarray.clone() for md arrays?

After some search for copying of multidimensional arrays manipulation in java I found this question: copy a 2d array in java and a downvoted answer suggests using the method in the title. So my questions are:
1) why is it bad? (becuase it looks quick and obvious)
2) is the best way still System.arraycopy each line?
Fundamentally, an array is an object. If you have a multidimensional array and you clone it, you won't get copies of the internal arrays (because they are also array Object(s)). You could use Arrays.copyOf(T[],int). From the linked Javadoc,
Copies the specified array, truncating or padding with nulls (if necessary) so the copy has the specified length. For all indices that are valid in both the original array and the copy, the two arrays will contain identical values. For any indices that are valid in the copy but not the original, the copy will contain null. Such indices will exist if and only if the specified length is greater than that of the original array. The resulting array is of exactly the same class as the original array.
Edit
The above is analogous to System.arraycopy() but also creates shallow copies. If you need to create deep copies of the multidimensional array you would have to iterate over the array clone and create a deep copy for each row.

Do I have to clone() an array of floats?

If I've got float[] a = {1,2,3};, can I copy it using only float[] b = a; to obtain a deep copy? How do I know when I need to use a.clone()?
To clarify: I want to be able to change a (e.g. a[0]=4;) without affecting b.
Just making float[] b = a; is not enough because then the array object will be shared between the 2 references a and b.
But because you have an array of primitive types is enough to use float[] b = a.clone(). The clone in this case will make a deep copy and will duplicate the array object including the primitive values inside.
If you had an array of some reference type you would need to clone the array and than iterate and clone every object to get a deep copy.
Shallow copying means only making the new reference to point to the memory location of the old array, while deep copying means allocating a new memory location and copying the contents of the first array to other.
Use deep copy only when you are afraid that someone will nullify/delete the first array. In that case your second array will also be pointing to non existent memory or null. If you have a requirement to save the contents in the second array then go for deep copy otherwise use shallow copy.
Read more about shallow and deep copy here: http://en.wikipedia.org/wiki/Object_copy
This is how you can make shallow or deep copy of your array:
Shallow copy
float[] b = a;
Deep copy
float[] b = Arrays.copyOf(a);
float[] b = a; means you are assigning the reference of the Array object held by variable a to variable b.
Use Arrays.copyOf() or System.arraycopy() to clone an array in Java. Also look at the micro-benchmarking.
How do I know when I need to use a.clone()?
Whenever you write a = b in Java where a and b are not primitives (i.e. boolean, char, byte, int, long, float, double), you are copying a reference.
In your example, when writing float[] a = {1,2,3}; then float[] b = a;, you only create one array, but have two variables "pointing" to it. So any change made to the array will be reflected on a and b.
To get a deep copy of your array and achieve your goal, simply clone it:
float[] b = a.clone();
no you need to do it for example like:
float[] b = (float[])a.clone();
I don't think that you can clone primitives, but if you had to you could always create a new array and a loop to copy all the values of one into the other.

How to get a sub array of array in Java, without copying data?

I have some library of classes, working with my data, which is being read into buffer. Is it possible somehow to avoid copying arrays again and again, passing parts of data deeper and deeper into processing methods? Well, it sounds strange, but in my particular case, there's a special writer, which divides data into blocks and writes them individually into different locations, so it just performs System.arraycopy, gets what it needs and calls underlying writer, with that new sub array. And this happens many times. What is the best approach to refactor such code?
Arrays.asList(array).subList(x, y).
This method doesn't give you an array, but a List, which is far more flexible.
Many classes in Java accept a subset of an arrays as parameter. E.g. Writer.write(char cbuf[], int off, int len). Maybe this already suffices for your usecase.
There is no real way to wrap any data without copying and receive real array in Java. You just cannot create new array over existing memory. You have basically 2 options:
Use methods that can accept range of array. This was already recommended.
Use wrapper that gives some kind of abstraction that is close to array and is suitable for many applications. Will be described below.
You may use java.nio.Buffer classes hierarchy, especially java.nio.ByteBuffer which offers buffer abstraction on whole array or sub-ranges. Often it is what people need. This also offers many interesting abilities like 'zero copy' flip and flexible byte area representation.
Here is example of wrapping using java.nio.ByteBuffer.
This should be very close to what you need. At least for some operations.
byte [] a1 = {0, 0, 1, 0};
ByteBuffer buf = ByteBuffer.wrap(a1,1,2);
Then you can do on buf any ByteBuffer operation.
Just a warning, buf.array() returns original a1 array (backend) with all elements.
There is no way to declare a subarray in Java if you use built in arrays like byte[]. The reason is: The length of the array is stored with the data, not with the declaration of the reference to it. Hence a subarray which does not copy the data has no place where it can store the length!
So for basic types you can use the mentioned efficient byte array copies and for higher types (List) there are methods available.
You could take the same approach as the String class takes; create a class for immutable objects which are constructed from an array, a start offset and an end offset which offers access to the sub-array. The user of such an object does not have to know the distinction between the whole array or a sub-array. The constructor does not have to copy the array, just store the array reference and its boundaries.
You could use (ArrayList).subList(value1, value2) i belive, perhaps that could help in your case? That is ofcourse if you want to use an ArrayList.
Perhaps instead of working with arrays you should work with a different type that maintains a reference to a slice of the original array, instead of copying the data over, similar to ArraySegment in C#. An additional benefit to this is that you can also shift the slice over the original array on-demand, without creating new instances. Pseudo code:
public class ArraySegment<T> implements Iterable<T>
{
private int from, to;
private T[] original;
public ArraySegment<T>(T[] original, int from, int to)
{
//constructor stuff
}
public T get(int index)
{
return original[index + from];
}
public int size()
{
return to - from + 1;
}
#Override
public Iterator<T> iterator()
{
//Iterator that iterates over the slice
}
//Can support setters on from/to variables
}
Google's Guava libraries support the slice concept in the form of a ByteSource.
Google Guava is a readily available open-source package of functionality, written from the ground up to follow Google best practices, which depend on significant array slicing capabilities.
Have a look on Arrays.copyOfRange(***) methods.

How do I clone a java byte array?

I have a byte array which i want to copy/clone to avoid calling code from modifying my internal representation.
How do I clone a java byte array?
JLS 6.4.5 The Members of an Array Type
The members of an array type are all of the following:
The public final field length, which contains the number of components of the array (length may be positive or zero).
The public method clone, which overrides the method of the same name in class Object and throws no checked exceptions. The return type of the clone method of an array type T[] is T[].
All the members inherited from class Object; the only method of Object that is not inherited is its clone method.
Thus:
byte[] original = ...;
byte[] copy = original.clone();
Note that for array of reference types, clone() is essentially a shallow copy.
Also, Java doesn't have multidimensional arrays; it has array of arrays. Thus, a byte[][] is an Object[], and is also subject to shallow copy.
See also
Wikipedia/Object copy
Java Nuts and Bolts/Arrays
Related questions
Deep cloning multidimensional arrays in Java… ?
How to effectively copy an array in java ?
How to deep copy an irregular 2D array
How do I do a deep copy of a 2d array in Java?
Other options
Note that clone() returns a new array object. If you simply want to copy the values from one array to an already existing array, you can use e.g. System.arraycopy (jdk 1.0+).
There's also java.util.Arrays.copyOf (jdk 1.6+) that allows you to create a copy with a different length (either truncating or padding).
Related questions
Difference between various Array copy methods
System.arraycopy(src, 0, dst, 0, src.length);
It's easy, and it's a great idea to do it.
byte[] copy = arr.clone();
Note that the return type of the clone() method of arrays is the type of the array, so no cast is required.
In order to avoid a possible Null Pointer Exception I use the following syntax:
byte[] copy = (arr == null) ? null : arr.clone();

Categories

Resources