java.lang.IndexOutOfBoundsException: Source does not fit in dest - java

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?

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.

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

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.

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.

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();

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.

Related

Java - Difference between fixed-sized list and list with initial capacity specified

I am having an issue in understanding this.
while we do
List<Integer> list = Arrays.asList(array);
we can not use methods like add, remove on that list. I know that Arrays.asList() returns a fixed-sized list.
What I don't understand is if we create a list with initial capacity specified like
List<Integer> list2 = new ArrayList<Integer>(10);
we can perform all the operations on that list. What is the difference between fixed-sized list and list with initial capacity specified?
I have read many answers on this but having such a hard time understanding this. Can anyone explain?
Thanks.
Arrays.asList(array) returns an object of type java.util.Arrays.ArrayList, which does not support add and remove operations.
While the code below will return an object of type java.util.ArrayList, which supports add and remove operations.
List<Integer> list2 = new ArrayList<Integer>(10);`
Very simply, Arrays.asList is so you can use List methods with an array. ArrayList(int) is for when you need to create a really large ArrayList and want to help speed things up a bit.
In more detail: the List returned by asList is intended as a wrapper to an array. Since you cannot resize an array, the methods that change the size of a List are unimplemented. Most of the time I just use asList to add a fixed number of elements to a collection simply. eg.
new ArrayList<String>(Arrays.asList("hello", "world"));
Confusingly, the implementation of ArrayList is very similar -- it's a List backed by an array. However, ArrayList allows you to change it's size. To do this it keeps a separate fields about the how many objects are in the list and the length of the backing array. Add an element and the ArrayList just sets array[size] to the element and then increments the size field. But what if array[size] is out of bounds? At this point the ArrayList creates a new, larger array and copies over the elements from the previous backing array. However, if you are creating a large List then this constant creation of new backing arrays can start to take up a lot of time. As such, if you know the approximate number of elements that will be in the List you can use this to inform the ArrayList about the size of the initial backing array it should create. This is what the ArrayList(int) constructor is for. Only in exceptional circumstances will you need to worry about giving the ArrayList a length hint.

Copying an ArrayList

I have an ArrayList of generic object type, i.e. List queue. I want to write a function EnqueueModified, that takes an arraylist and a list object as input and returns another ArrayList that contains the elments of the old arraylist and the list object but without affecting the original arraylist passed. i.e. Enqueue operation should be performed on a new copy of the arraylist and returned.
This can be done as follows:
public List<E> EnqueueModified(E e, List<E> queue) {
List<E> clone = new ArrayList<E>(queue);
clone.add(e);
return clone;
}
but is there a better method to do this? instead of using a copy constructor, is there any faster way to create a copy of the list? I cannot use cloning as it does not support for generic List.
To copy a list, you have to create a new list and fill it with items from the old list.
The constructor you are using might not actually be the best option, though. If you check the source code (google arraylist source code) you notice that it creates an array that is exactly as big as there are elements in the old collection.
Then it adds an element to that array. Because the array is too small, it has to create another copy of the array, only a bit bigger, and move the elements there again.
You could get a better performance by using
clone = new ArrayList(queue.size() + 1);
clone.addAll(queue);
clone.add(e);
Also, method names should start with a lower case letter. So use: enqueueModified(...)

why LinkedList doesn't have initialCapacity in java?

I wonder why LinkedList doesn't have initialCapacity.
I know good when to use ArrayList and when LinkedList.
Its good practice to define Collection final size like:
List<String> arraylist = new ArrayList<String>(5);
For LinkedList for example:
List<String> linkedlist = new LinkedList<String>(); // right way
but
List<String> arraylist = new LinkedList<String>(5); // compilation error
Can somebody spread a light on that issue?
[EDIT]
BTW, I can write
List<String> arraylist = new ArrayList<String>(5);
List<String> linkedlist = new LinkedList<String>(arraylist);
LinkedList by nature does not have "capacity", since it does not allocate memory to the items before the items are added to the list. Each item in a LinkedList holds a pointer to the next in the list.
There would be no point in allocating memory to the list beforehand, since LinkedList does not have capacity.
Its model is not based on an array but rather a true linked list, and so there is no need and further it would not make sense. It doesn't make much sense to have empty links like you have empty array items.
Why would you need a capacity on a LinkedList? A LinkedList does not work with fixed sized arrays. Every LinkedListElement has a pointer (a link!) to the next Element in the list. Which Because of that it is possible to add an element to a linked list in constant time. But it is costly to have random access to the elements in the List. You need to go through all the Elements in the list until you reach your destination.
Why would LinkedList have an initial capacity?
ArrayList is backed up by an array, so the initial capacity is the initial size of the array. LinkedList has no need of that.
Linkedlist does not need an initial value. Thats is the primary difference between array and linked list.
array will end somewhere. But linkedlist not. Linked list does not work on boundary values.
When you declare an array you have to know its size because pointers need to be created in memory. A linked list does not need this because there is no need for pointers to memory before any object is added to the list.
A linked list is defined recursively as:
an empty list
en element that points to the empty list
therefore whenever you add an element, you allocate memory (or rather in Java the compiler does this) when you create the element, and then when you add it to the list it now points to the list (or the last element in the list points to it).
So you don't need to declare initial size of linked list because a linked list always starts with the empty list, and when an element is added it points to the list.
ArrayList And LinkedList both have implementation class of List Interface.
ArrayList is using Resizable Array or Grow-able Array.In array Data structure using Contiguous memory allocation and with the help of that we can access array's element with index. When we declare any array then we should declare initial capacity because finding of Contiguous memory blocks for storing array's element.
LinkedList is using double linked list as under Line data structure. In linked list data structure using non contiguous memory allocation and using head and tail concept for access these element. So in LinkedList we don't need to any initial capacity.

Regarding creation of dynamic array in java

Could you please advise how to create a dynamic array..!! A primitive array can be declared as
int[] myIntArray = new int[3];
But this time I know know the size of array is of 3 elements but what if I want to create a dynamic array how I will create that, Please advise.
An array has always to be initialised with a given size. Use a List if you wish to have a 'dynamic' collection and then convert to an array if needed. The array cannot be resized after instantiation whereas a List can (ignoring non modifiable lists).
You can instantiate an array using a variable, but once instantiated, the array will be stuck at that size.
int[] myArrayInt = new int[arraySizeVariable];
If you want something that is truly dynamic then I would suggest using an ArrayList instead.
List<Integer> myArrayList = new ArrayList<Integer>();
ArrayLists can grow and shrink dynamically:
ArrayList<Integer> list = new ArrayList<Integer>();
//...
list.add(5);
list.add(1);
//...
int index = list.indexOf(5);
list.remove(index);
use java.lang.reflect.Array
public static Object newInstance(Class<?> componentType, int length) {}
In Java you can have all sorts of dynamic groups of elements. The basic array [] is still going to be as static as it will in any other similar language, so you are going to want to use some implementation of the Collection.java interface.
The most basic one is a Vector which simply contains some objects, not necessarily of the same class, and will grow dynamically as you add or remove items from it. If you want them to be ordered then you can use an implementations of List.java. If you want the collection to be unique then you can use instances of Set.java.
public int[] createArray(int size){return new int[size];}
Well it's a dumb code. Creates array of size you want. It's not expandable once created. For that you need to expand manually by copying to a larger array when your old array is full. Or better, get it done by a collection called ArrayList, which doubles capacity when reaches to some threshold.
If you implement your own expandable array, it will be same as using ArrayList: see
Each ArrayList instance has a capacity. The capacity is the size of the array used to store the elements in the list. It is always at least as large as the list size. As elements are added to an ArrayList, its capacity grows automatically. The details of the growth policy are not specified beyond the fact that adding an element has constant amortized time cost.

How to copy values, not references, of List<Integer> into another list?

Namely, without referencing the same object, I need to copy values of elements of one list into another list. These are the lists:
List<Integer> listA = new ArrayList<Integer>();
List<Integer> ListB = new ArrayList<Integer>();
listA = (added some values);
listB = (do what?)...
PS. I appologize for beginner's question, but I have never done such a thing.
There is absolutely no reason to make a copy of an Integer. Integer is an immutable class. This means that its value is set when the Integer instance is created, and can never change. An Integer reference can thus be shared by multiple lists and threads without fear, because there's no way anybody can change its value. Your question thus makes no real sense.
To create an ArrayList b containing the same Integers as another List a, just use the following code:
List<Integer> b = new ArrayList<Integer>(a);
Sure the Integer won't be cloned, but this is a good thing, because cloning them is completely unnecessary.
You can try and give a look at the Collections.copy method:
public static void copy(List dest,
List src)
Copies all of the elements from one list into another. After the operation, the index of each copied
element in the destination list will be identical to its index in the
source list. 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. This method runs in linear time.
Parameters: dest - The destination list. src - The source list.
Note: The above should work for simple data types such as Integers, however, if you have your own objects which might in turn reference other objects, you will have to iterate over each object and copy it separately.
Use this method of Collections class to copy all elements of ArrayList to another ArrayList:
Collections.copy(listA, listB);
Try to use this, while the answers given by another guys are totally fine. But per my option, the following would be the best way:
List<Integer> listB = new ArrayList<Integer>(listA);
For clarification.
ArrayList<Integer> a = new ArrayList<Integer>(Arrays.asList(1,2,3));
ArrayList<Integer> b = new ArrayList<Integer>(a);
ArrayList<Integer> c = a;
c.set(0, 5);
System.out.println(a);
System.out.println(b);
System.out.println(c);
Will print out
[5, 2, 3]
[1, 2, 3]
[5, 2, 3]
Using the new keyword will automatically take the values from an existing array and copy those to the new array.
I'm also just a little bit confused as to why Collections.copy(dest, src) is listed on here as an answer. Considering if the new array has just been initialized you'll get.
Exception in thread "main" java.lang.IndexOutOfBoundsException: Source does not fit in dest
This happens because Collections.copy uses List<> instead of ArrayList<> so if the source array is larger than the destination array you'll get this error. There ARE workarounds, such as a for loop to add X number of elements for Y number of elements in the first array but considering you can just use the new keyword and all this gets done automatically I feel as if this answer should be changed to be JB Nizet's answer.
I also made sure to actually run this code so all of this is up to date as of Java: 1.8.0_333
You won't have a lot of luck with clone() and Cloneable - it will only create a shallow copy. You could use something like this - http://javatechniques.com/blog/faster-deep-copies-of-java-objects/ .
Try This.
ListB.addAll(listA);

Categories