Related
I have an array a which is constantly being updated. Let's say a = [1,2,3,4,5]. I need to make an exact duplicate copy of a and call it b. If a were to change to [6,7,8,9,10], b should still be [1,2,3,4,5]. What is the best way to do this? I tried a for loop like:
for(int i=0; i<5; i++) {
b[i]=a[i];
}
but that doesn't seem to work correctly. Please don't use advanced terms like deep copy, etc., because I do not know what that means.
You can try using System.arraycopy()
int[] src = new int[]{1,2,3,4,5};
int[] dest = new int[5];
System.arraycopy( src, 0, dest, 0, src.length );
But, probably better to use clone() in most cases:
int[] src = ...
int[] dest = src.clone();
you can use
int[] a = new int[]{1,2,3,4,5};
int[] b = a.clone();
as well.
If you want to make a copy of:
int[] a = {1,2,3,4,5};
This is the way to go:
int[] b = Arrays.copyOf(a, a.length);
Arrays.copyOf may be faster than a.clone() on small arrays. Both copy elements equally fast but clone() returns Object so the compiler has to insert an implicit cast to int[]. You can see it in the bytecode, something like this:
ALOAD 1
INVOKEVIRTUAL [I.clone ()Ljava/lang/Object;
CHECKCAST [I
ASTORE 2
Nice explanation from http://www.journaldev.com/753/how-to-copy-arrays-in-java
Java Array Copy Methods
Object.clone(): Object class provides clone() method and since array
in java is also an Object, you can use this method to achieve full
array copy. This method will not suit you if you want partial copy of
the array.
System.arraycopy(): System class arraycopy() is the best way to do
partial copy of an array. It provides you an easy way to specify the
total number of elements to copy and the source and destination array
index positions. For example System.arraycopy(source, 3, destination,
2, 5) will copy 5 elements from source to destination, beginning from
3rd index of source to 2nd index of destination.
Arrays.copyOf(): If you want to copy first few elements of an array or
full copy of array, you can use this method. Obviously it’s not
versatile like System.arraycopy() but it’s also not confusing and easy
to use.
Arrays.copyOfRange(): If you want few elements of an array to be
copied, where starting index is not 0, you can use this method to copy
partial array.
I have a feeling that all of these "better ways to copy an array" are not really going to solve your problem.
You say
I tried a for loop like [...] but that doesn't seem to be working correctly?
Looking at that loop, there's no obvious reason for it not to work ... unless:
you somehow have the a and b arrays messed up (e.g. a and b refer to the same array), or
your application is multi-threaded and different threads are reading and updating the a array simultaneously.
In either case, alternative ways of doing the copying won't solve the underlying problem.
The fix for the first scenario is obvious. For the second scenario you will have to figure out some way of synchronizing the threads. Atomic array classes don't help because they have no atomic copy constructors or clone methods, but synchronizing using a primitive mutex will do the trick.
(There are hints in your question that lead me to think that this is indeed thread related; e.g. your statement that a is constantly changing.)
You can try using Arrays.copyOf() in Java
int[] a = new int[5]{1,2,3,4,5};
int[] b = Arrays.copyOf(a, a.length);
All solution that call length from array, add your code redundant null checkersconsider example:
int[] a = {1,2,3,4,5};
int[] b = Arrays.copyOf(a, a.length);
int[] c = a.clone();
//What if array a comes as local parameter? You need to use null check:
public void someMethod(int[] a) {
if (a!=null) {
int[] b = Arrays.copyOf(a, a.length);
int[] c = a.clone();
}
}
I recommend you not inventing the wheel and use utility class where all necessary checks have already performed. Consider ArrayUtils from apache commons. You code become shorter:
public void someMethod(int[] a) {
int[] b = ArrayUtils.clone(a);
}
Apache commons you can find there
You can also use Arrays.copyOfRange.
Example:
public static void main(String[] args) {
int[] a = {1,2,3};
int[] b = Arrays.copyOfRange(a, 0, a.length);
a[0] = 5;
System.out.println(Arrays.toString(a)); // [5,2,3]
System.out.println(Arrays.toString(b)); // [1,2,3]
}
This method is similar to Arrays.copyOf, but it's more flexible. Both of them use System.arraycopy under the hood.
See:
https://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html
https://docs.oracle.com/javase/tutorial/java/nutsandbolts/arrays.html
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/util/Arrays.java?av=f
If you must work with raw arrays and not ArrayList then Arrays has what you need. If you look at the source code, these are the absolutely best ways to get a copy of an array. They do have a good bit of defensive programming because the System.arraycopy() method throws lots of unchecked exceptions if you feed it illogical parameters.
You can use either Arrays.copyOf() which will copy from the first to Nth element to the new shorter array.
public static <T> T[] copyOf(T[] original, int newLength)
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.
2770
2771 public static <T,U> T[] More ...copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
2772 T[] copy = ((Object)newType == (Object)Object[].class)
2773 ? (T[]) new Object[newLength]
2774 : (T[]) Array.newInstance(newType.getComponentType(), newLength);
2775 System.arraycopy(original, 0, copy, 0,
2776 Math.min(original.length, newLength));
2777 return copy;
2778 }
or Arrays.copyOfRange() will also do the trick:
public static <T> T[] copyOfRange(T[] original, int from, int to)
Copies the specified range of the specified array into a new array.
The initial index of the range (from) must lie between zero and
original.length, inclusive. The value at original[from] is placed into
the initial element of the copy (unless from == original.length or
from == to). Values from subsequent elements in the original array are
placed into subsequent elements in the copy. The final index of the
range (to), which must be greater than or equal to from, may be
greater than original.length, in which case null is placed in all
elements of the copy whose index is greater than or equal to
original.length - from. The length of the returned array will be to -
from. The resulting array is of exactly the same class as the original
array.
3035 public static <T,U> T[] More ...copyOfRange(U[] original, int from, int to, Class<? extends T[]> newType) {
3036 int newLength = to - from;
3037 if (newLength < 0)
3038 throw new IllegalArgumentException(from + " > " + to);
3039 T[] copy = ((Object)newType == (Object)Object[].class)
3040 ? (T[]) new Object[newLength]
3041 : (T[]) Array.newInstance(newType.getComponentType(), newLength);
3042 System.arraycopy(original, from, copy, 0,
3043 Math.min(original.length - from, newLength));
3044 return copy;
3045 }
As you can see, both of these are just wrapper functions over System.arraycopy with defensive logic that what you are trying to do is valid.
System.arraycopy is the absolute fastest way to copy arrays.
For a null-safe copy of an array, you can also use an optional with the Object.clone() method provided in this answer.
int[] arrayToCopy = {1, 2, 3};
int[] copiedArray = Optional.ofNullable(arrayToCopy).map(int[]::clone).orElse(null);
I had a similar problem with 2D arrays and ended here.
I was copying the main array and changing the inner arrays' values and was surprised when the values changed in both copies. Basically both copies were independent but contained references to the same inner arrays and I had to make an array of copies of the inner arrays to get what I wanted.
This is sometimes called a deep copy. The same term "deep copy" can also have a completely different and arguably more complex meaning, which can be confusing, especially to someone not figuring out why their copied arrays don't behave as they should. It probably isn't the OP's problem, but I hope it can still be helpful.
Everybody please actually read this question first before you see "stream" and "array" and just assume that the question is a duplicate. I know how to convert a stream to an array. This question is very specific: how to follow the contract of Collection.toArray(T[] array). All those people saying that this is a duplicate: do the other answers re-use an existing array if it is big enough? Do they mark an element with null if the existing array is too big? (No and no.)
I know that the Java Stream<> interface provides several ways to convert a stream to an array. But the Collection.toArray(T[] array) method is a little different. It has a few clever (at the time) requirements, including:
If the array you pass is big enough, the array you pass must be used; otherwise a new one must be created.
If the array is bigger than necessary, null must be added after the last element.
So if my Collection<T> implementation retrieves its values from some Stream<FooBar> (with a converter strategy that converts to T, how can I convert from my stream to the array required by Collection.toArray(T[] array)?
Without a lot of thought, it would seem I have to do this:
#Override
public <T> T[] toArray(T[] array) {
try (final Stream<FooBar> stream = getStream()) {
T[] result = stream.map(converter::toT).toArray(length ->
(T[])Array.newInstance(array.getClass(), length));
if(result.length <= array.length) {
System.arraycopy(result, 0, array, 0, result.length);
if(result.length < array.length) {
array[result.length] = null;
}
result = array;
}
}
return result;
}
But is there some more concise way to do this? Is there some way I could transfer the stream directly into the given array if possible? And does the Stream<> API already provide for something like this: creating an array as the Collection<>.toArray(T[] array) API expects?
A very recommended read is the article Arrays of Wisdom of the Ancients.
In short, contrary to intuition, passing a pre-sized array to the Collections.toArray(T[]) method turns out to be less efficient than passing a zero sized array, which only serves to determine the result type but lets the collection allocate the result array.
That’s why Java 11’s new default method <T> T[] toArray(IntFunction<T[]> generator) does not use the function to allocate an array of the collection’s size but rather to allocate a zero sized array to be passed to <T> T[] toArray(T[] a).
So it’s worth rethinking whether you really want such a contract for a method or which actual use cases you really want to optimize for (as you can’t serve all at once).
E.g. considering that passing a zero sized array is the most efficient choice anyway, you could optimize for exactly that case
#Override
public <T> T[] toArray(T[] array) {
T[] template = array.length == 0? array: Arrays.copyOf(array, 0);
try(Stream<FooBar> stream = getStream()) {
T[] result = stream.map(converter::toT)
.toArray(length -> Arrays.copyOf(template, length));
if(result.length > array.length) return result;
System.arraycopy(result, 0, array, 0, result.length);
if(result.length < array.length) array[result.length] = null;
return array;
}
}
Note that when you have to implement that method because you’re implementing a Collection, there are plenty of helpful abstract base classes in the JDK which provide an implementation already.
You could even utilize such an implementation when you are not implementing a collection, e.g.
public <T> T[] toArray(T[] array) {
try(final Stream<FooBar> stream = getStream()) {
return new AbstractCollection<XYZ>() {
public Iterator<XYZ> iterator() {
return stream.map(converter::toT).iterator();
}
public int size() { return 0; } // don't know beforehand
}.toArray(array);
}
}
You have to replace XYZ with the return type of the converter.toT(FooBar) method.
Which leads to the bigger question, how converter::toT is supposed to convert to the right type without actually knowing what T is.
I'm looking for a way to cut a initial array from a specific index to another index
int[] array = {10,5,4,4,3,5,6};
int[] arrayCopy;
In this example, if I want to segment from index[1] to index[4]. The new array witch I store in arrayCopy should looks like this one arrayCopy[] = {5,4,4,3}. The constante problem is that my objectif is to keep reference of the original array.So if in arrayCopy I change a element il will change too in array
arrayCopy[] = {5,4,4,3}
arrayCopy[0] = 20 // arrayCopy[] = {20,4,4,3} and array = {10,20,4,4,3,5,6};
I tried Arrays.copyOfRange() but it's a deep copy and System.arraycopy() make a shallow copy but it doesn't accomplish what I want.
I tried to make my own method
public E[] fillArray(int[] _array, int begin, int end){
int[] arrayTemp;
for ( int i = begin ; i <= end; i++ ) {
arrayTemp[i] = _array[i];
}
return arrayTemp;
}
Output
arrayCopy = fillArray(array,1,4);
Exception in thread "main" java.lang.NullPointerException
Note: I want to keep the array mechanism and not using an ArrayList or ...
Can I change the second array and the first array will change too?
There is no way for Java arrays to support that feature.
A Java array is an Object, so all arrays are independent objects, with their own memory structure for the array values.
(This is unlike C, where an array is done by pointer manipulation, so a second pointer can point into the memory sequence of an array already referenced by another pointer.)
If you want a sub-array of the first array, that is mapped such that changes to the sub-array is reflected in the main array, and vice-versa, you need something else.
One option is to use a List, and create the sub-list using subList(int fromIndex, int toIndex):
Returns a view of the portion of this list between the specified fromIndex, inclusive, and toIndex, exclusive. (If fromIndex and toIndex are equal, the returned list is empty.) The returned list is backed by this list, so non-structural changes in the returned list are reflected in this list, and vice-versa.
If you already have an array, you can wrap the array with a list using Arrays.asList(T... a), then use the subList() as for any other list.
Returns a fixed-size list backed by the specified array. (Changes to the returned list "write through" to the array.)
Note that List doesn't work for primitive types, so if your array is a primitive, you should use a Buffer of the appropriate type ( ByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer, LongBuffer, ShortBuffer).
E.g. for an int[], create the buffer using IntBuffer.wrap(int[] array, int offset, int length):
Wraps an int array into a buffer.
The new buffer will be backed by the given int array; that is, modifications to the buffer will cause the array to be modified and vice versa.
If you always access the array through the IntBuffer, by using IntBuffer.wrap(int[] array) to wrap the full array, your code could use either IntBuffer and not know if it is accessing the full array or the sub-array.
This should work.
public static int[] fillArray(int[] _array, int begin, int end){
int[] arrayTemp = new int[end-begin+1];
for ( int i = begin ; i <= end; i++ ) {
arrayTemp[i-begin] = _array[i];
}
return arrayTemp;
}
I have an array a which is constantly being updated. Let's say a = [1,2,3,4,5]. I need to make an exact duplicate copy of a and call it b. If a were to change to [6,7,8,9,10], b should still be [1,2,3,4,5]. What is the best way to do this? I tried a for loop like:
for(int i=0; i<5; i++) {
b[i]=a[i];
}
but that doesn't seem to work correctly. Please don't use advanced terms like deep copy, etc., because I do not know what that means.
You can try using System.arraycopy()
int[] src = new int[]{1,2,3,4,5};
int[] dest = new int[5];
System.arraycopy( src, 0, dest, 0, src.length );
But, probably better to use clone() in most cases:
int[] src = ...
int[] dest = src.clone();
you can use
int[] a = new int[]{1,2,3,4,5};
int[] b = a.clone();
as well.
If you want to make a copy of:
int[] a = {1,2,3,4,5};
This is the way to go:
int[] b = Arrays.copyOf(a, a.length);
Arrays.copyOf may be faster than a.clone() on small arrays. Both copy elements equally fast but clone() returns Object so the compiler has to insert an implicit cast to int[]. You can see it in the bytecode, something like this:
ALOAD 1
INVOKEVIRTUAL [I.clone ()Ljava/lang/Object;
CHECKCAST [I
ASTORE 2
Nice explanation from http://www.journaldev.com/753/how-to-copy-arrays-in-java
Java Array Copy Methods
Object.clone(): Object class provides clone() method and since array
in java is also an Object, you can use this method to achieve full
array copy. This method will not suit you if you want partial copy of
the array.
System.arraycopy(): System class arraycopy() is the best way to do
partial copy of an array. It provides you an easy way to specify the
total number of elements to copy and the source and destination array
index positions. For example System.arraycopy(source, 3, destination,
2, 5) will copy 5 elements from source to destination, beginning from
3rd index of source to 2nd index of destination.
Arrays.copyOf(): If you want to copy first few elements of an array or
full copy of array, you can use this method. Obviously it’s not
versatile like System.arraycopy() but it’s also not confusing and easy
to use.
Arrays.copyOfRange(): If you want few elements of an array to be
copied, where starting index is not 0, you can use this method to copy
partial array.
I have a feeling that all of these "better ways to copy an array" are not really going to solve your problem.
You say
I tried a for loop like [...] but that doesn't seem to be working correctly?
Looking at that loop, there's no obvious reason for it not to work ... unless:
you somehow have the a and b arrays messed up (e.g. a and b refer to the same array), or
your application is multi-threaded and different threads are reading and updating the a array simultaneously.
In either case, alternative ways of doing the copying won't solve the underlying problem.
The fix for the first scenario is obvious. For the second scenario you will have to figure out some way of synchronizing the threads. Atomic array classes don't help because they have no atomic copy constructors or clone methods, but synchronizing using a primitive mutex will do the trick.
(There are hints in your question that lead me to think that this is indeed thread related; e.g. your statement that a is constantly changing.)
You can try using Arrays.copyOf() in Java
int[] a = new int[5]{1,2,3,4,5};
int[] b = Arrays.copyOf(a, a.length);
All solution that call length from array, add your code redundant null checkersconsider example:
int[] a = {1,2,3,4,5};
int[] b = Arrays.copyOf(a, a.length);
int[] c = a.clone();
//What if array a comes as local parameter? You need to use null check:
public void someMethod(int[] a) {
if (a!=null) {
int[] b = Arrays.copyOf(a, a.length);
int[] c = a.clone();
}
}
I recommend you not inventing the wheel and use utility class where all necessary checks have already performed. Consider ArrayUtils from apache commons. You code become shorter:
public void someMethod(int[] a) {
int[] b = ArrayUtils.clone(a);
}
Apache commons you can find there
You can also use Arrays.copyOfRange.
Example:
public static void main(String[] args) {
int[] a = {1,2,3};
int[] b = Arrays.copyOfRange(a, 0, a.length);
a[0] = 5;
System.out.println(Arrays.toString(a)); // [5,2,3]
System.out.println(Arrays.toString(b)); // [1,2,3]
}
This method is similar to Arrays.copyOf, but it's more flexible. Both of them use System.arraycopy under the hood.
See:
https://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html
https://docs.oracle.com/javase/tutorial/java/nutsandbolts/arrays.html
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/util/Arrays.java?av=f
If you must work with raw arrays and not ArrayList then Arrays has what you need. If you look at the source code, these are the absolutely best ways to get a copy of an array. They do have a good bit of defensive programming because the System.arraycopy() method throws lots of unchecked exceptions if you feed it illogical parameters.
You can use either Arrays.copyOf() which will copy from the first to Nth element to the new shorter array.
public static <T> T[] copyOf(T[] original, int newLength)
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.
2770
2771 public static <T,U> T[] More ...copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
2772 T[] copy = ((Object)newType == (Object)Object[].class)
2773 ? (T[]) new Object[newLength]
2774 : (T[]) Array.newInstance(newType.getComponentType(), newLength);
2775 System.arraycopy(original, 0, copy, 0,
2776 Math.min(original.length, newLength));
2777 return copy;
2778 }
or Arrays.copyOfRange() will also do the trick:
public static <T> T[] copyOfRange(T[] original, int from, int to)
Copies the specified range of the specified array into a new array.
The initial index of the range (from) must lie between zero and
original.length, inclusive. The value at original[from] is placed into
the initial element of the copy (unless from == original.length or
from == to). Values from subsequent elements in the original array are
placed into subsequent elements in the copy. The final index of the
range (to), which must be greater than or equal to from, may be
greater than original.length, in which case null is placed in all
elements of the copy whose index is greater than or equal to
original.length - from. The length of the returned array will be to -
from. The resulting array is of exactly the same class as the original
array.
3035 public static <T,U> T[] More ...copyOfRange(U[] original, int from, int to, Class<? extends T[]> newType) {
3036 int newLength = to - from;
3037 if (newLength < 0)
3038 throw new IllegalArgumentException(from + " > " + to);
3039 T[] copy = ((Object)newType == (Object)Object[].class)
3040 ? (T[]) new Object[newLength]
3041 : (T[]) Array.newInstance(newType.getComponentType(), newLength);
3042 System.arraycopy(original, from, copy, 0,
3043 Math.min(original.length - from, newLength));
3044 return copy;
3045 }
As you can see, both of these are just wrapper functions over System.arraycopy with defensive logic that what you are trying to do is valid.
System.arraycopy is the absolute fastest way to copy arrays.
For a null-safe copy of an array, you can also use an optional with the Object.clone() method provided in this answer.
int[] arrayToCopy = {1, 2, 3};
int[] copiedArray = Optional.ofNullable(arrayToCopy).map(int[]::clone).orElse(null);
I had a similar problem with 2D arrays and ended here.
I was copying the main array and changing the inner arrays' values and was surprised when the values changed in both copies. Basically both copies were independent but contained references to the same inner arrays and I had to make an array of copies of the inner arrays to get what I wanted.
This is sometimes called a deep copy. The same term "deep copy" can also have a completely different and arguably more complex meaning, which can be confusing, especially to someone not figuring out why their copied arrays don't behave as they should. It probably isn't the OP's problem, but I hope it can still be helpful.
I am trying to convert a Set to an Array.
Set<String> s = new HashSet<String>(Arrays.asList("mango","guava","apple"));
String[] a = s.toArray(new String[0]);
for(String x:a)
System.out.println(x);
And it works fine. But I don't understand the significance of new String[0] in String[] a = s.toArray(new String[0]);.
I mean initially I was trying String[] a = c.toArray();, but it wan't working. Why is the need for new String[0].
It is the array into which the elements of the Set are to be stored, if it is big enough; otherwise, a new array of the same runtime type is allocated for this purpose.
Object[] toArray(), returns an Object[] which cannot be cast to String[] or any other type array.
T[] toArray(T[] a) , returns an array containing all of the elements in this set; the runtime type of the returned array is that of the specified array. If the set fits in the specified array, it is returned therein. Otherwise, a new array is allocated with the runtime type of the specified array and the size of this set.
If you go through the implementing code (I'm posting the code from OpenJDK) , it will be clear for you :
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;
}
The parameter is a result of one of the many well-known limitations in the Java generics system. Basically, the parameter is needed in order to be able to return an array of the correct type.