80

On the following code:

static void findSubsets (ArrayList<Integer> numbers, int amount, int index)
{
    ArrayList <Integer> numbersCopy = new ArrayList<Integer>(numbers.size());
    Collections.copy(numbersCopy, numbers);
}

I'm getting the error:

Exception in thread "main" java.lang.IndexOutOfBoundsException: Source does not fit in dest
        at java.util.Collections.copy(Collections.java:548)
        at backtracking2.Main.findSubsets(Main.java:61)

Why?

Java Devil
  • 10,629
  • 7
  • 33
  • 48
andandandand
  • 21,946
  • 60
  • 170
  • 271

6 Answers6

99

Capacity does not equal size. The size parameter that you are passing in simply allocates enough memory for the size. It does not actually define elements. It's actually kind of a silly requirement of Collections.copy, but it is one nonetheless.

The key part from the Collections.copy JavaDocs:

The destination list must be at least as long as the source list. If it is longer, the remaining elements in the destination list are unaffected.

You should just pass the List to the ArrayList's constructor to copy all of the List to avoid the issue altogether.

pickypg
  • 22,034
  • 5
  • 72
  • 84
  • 10
    I downrated this, because adding it to the constructor will do a [b]shallow[/b] copy and will not be the same as a deep copy. Manipulating the elements in the original list, will also manipulate them in the 'copied to' list – Boy Nov 29 '14 at 13:12
  • 8
    @Boy Your point is incorrect. See the [source code for ArrayList](http://hg.openjdk.java.net/jdk7/modules/jdk/file/a37326fa7f95/src/share/classes/java/util/ArrayList.java#l150) where a deep copy _of the list_ is made via a call to `toArray` and [`Arrays.copyOf`](https://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html#copyOf(U[],%20int,%20java.lang.Class)). Changes made to either list after `numbersCopy = new ArrayList(numbers)` does _not_ effect the other. That would certainly defeat the purpose of the constructor (and it takes a `Collection` and not a `List` anyway). – pickypg Dec 01 '14 at 02:07
  • 2
    @Boy Unless you're getting at the fact that the _elements themselves_ are not also reconstructed for a true deep copy? Since Java does not require copy constructors, this would be a nearly impossible requirement and one that [`Collections.copy` does not perform either](http://hg.openjdk.java.net/jdk7/modules/jdk/file/a37326fa7f95/src/share/classes/java/util/Collections.java#l545). – pickypg Dec 01 '14 at 02:10
  • 2
    I did not know that the 'new' didn't affect each others list. Sorry for being incorrect... – Boy Dec 01 '14 at 10:48
  • A deep copy is better defined as "any change to any part of the new object will have no effect on the old object", so a deep copy of "just the list bit" doesn't really make sense. Were any parts of the original object mutable, the new and old object could affect each other, so that wouldn't be a deep copy. However, in the case of immutable elements in the list (like `Integer` in this question), there's no difference in function between a shallow and deep copy. – paxdiablo Jul 25 '20 at 01:35
30

That's a very good question and it almost certainly has to do with the fact that setting a collections capacity does not necessarily allocate the underlying objects, but why are you doing it that way when you can just:

ArrayList <Integer> numbersCopy = new ArrayList<Integer>(numbers);
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • 13
    it copies reference – temirbek Jul 20 '17 at 11:55
  • @temirbek, no it will not. I just tested it plus source code (http://hg.openjdk.java.net/jdk7/modules/jdk/file/a37326fa7f95/src/share/classes/java/util/ArrayList.java#l150) says `Arrays.copyOf()` means it will be unreferenced copy – Farid Oct 05 '19 at 13:37
  • @Snedden27: yes, shallow, but it doesn't matter in this case since `Integer` is immutable. – paxdiablo Jul 25 '20 at 01:29
6

The constructor ArrayList(Collection<? extends E> c) will copy every elements from c into the newly created instance, thus copying numbers into numbersCopy. It is the same as numbersCopy.addAll(numbers) also, which is really what you need.

It does make sense that Collection.copy requires the dest array to be large enough to hold all elements from the source array. A similar analogy is the C function memcpy and the like.

Yanick Rochon
  • 51,409
  • 25
  • 133
  • 214
1

While creating an ArrayList to copy another ArrayList using Collections.copy() method, we need to make sure that the destination List contains same number of values (not just same size) as source List. For example, if source ArrayList has values [Red,Blue,Green], then the destination ArrayList should also contain same number of elements like [Orange,Yellow,Blue].If we create an ArrayList with same size that of source ArrayList, it will give OutOfBounds exception.

sayhan
  • 1,168
  • 1
  • 16
  • 22
Arun Nair
  • 19
  • 2
1

You can also use, Collections.addAll like Assume we need to copy List1 to List2, then List2.addAll(List1); Here the files will be added, if you want it more efficient then make sure you clear the list2 before adding the items of list1, like this, list2.clear();

Vijay
  • 1,163
  • 8
  • 22
-1

In java 8 +

List<Integer> numbersCopy = numbers.stream().collect(Collectors.toList());

It easier in java 10+

List<Integer> numbersCopy = List.copyOf(numbers);

List.copyOf() returns an unmodifiable List containing the elements of the given Collection.

Ahmad Al-Kurdi
  • 2,248
  • 3
  • 23
  • 39