Set Method of ArrayList throwing IndexOutOfBoundsException - java

While working on ArrayList, I found after setting the initial size of array using the constructor with initialCapacity, then use set() will throw an exception although the array is created, but size isn't set correctly.
Using ensureCapacity() won't work either because it is based on the elementData array instead of size.
There are other side effects because of the static DEFAULT_CAPACITY with ensureCapacity().
The only way to make this work is to use add() as many time as required after using the constructor.
Please check the code below.
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
List test = new ArrayList(10);
test.set(5, "test");
System.out.println(test.size());
}
I am not sure why java is throwing this exception.
Behaviour I expected: test.size() should return 10 and set(5, ...) should work.
ACTUAL: throws an Exception IndexOutOfBoundsException.
So is it set method that is causing problem ?

test.set(5, "test"); is the statement that throws this exception, since your ArrayList is empty (size() would return 0 if you got to that statement), and you can't set the i'th element if it doesn't already contain a value. You must add at least 6 elements to your ArrayList in order for test.set(5, "test"); to be valid.
new ArrayList(10) doesn't create an ArrayList whose size is 10. It creates an empty ArrayList whose initial capacity is 10.

The exception is not thrown by test.size() but by test.set(5, "test");. This is because you are setting an element at index 5 but the list is currently empty.
List test = new ArrayList(10);
does not create a list initialized with 10 null elements. It creates a list that has an initial capacity of 10 elements, that is the backing array has a size of 10, but the list itself is still empty.
If you want to initialize a list with 10 null elements, you can use
List<String> list = new ArrayList<>(Collections.nCopies(10, null));
As a side note, you should never use raw types like List but always prefer a parameterized list.

List test = new ArrayList(10); creates empty list which would have capacity of 10 elements.It is not containing element at 6th position so you will not be able to set element at this position.

List test = new ArrayList(10); creates empty ArrayList of raw types (Object) with initial capacity(capacity of list initially, initialize internal array with length 10) not to be confused with size(number of elements list contains).
To understand more first note that ArrayList is nothing but manipulation of array to dynamically change size of the array which we were not able to do with array directly. Ultimately, it's a smart array.
By setting initial capacity we are telling ArrayList to create size of array 10 initially (by default initial capacity is 10).
This is what constructor is doing,
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];//creates initial array
}
You can increase or decrease it accordingly, say you are sure that you are going to need list with 20 elements it'll be better to set initial capacity at start. It avoids resizing of array if you are sure about minimum number of elements you will definitely have in list.
test.set(5, "test"); method replaces element at specific position here it will going to replace element at index 5 with test. But our list is empty, it does not have any element.
Documentation of this method says,
IndexOutOfBoundsException - if the index is out of range (index < 0 ||
index >= size())
Note that size of list is 0 so index (5) is greater than size(0).

Replaces the element at the specified position in this list with the specified element.
set
Parameters
index
int: index of the element to replace
element
E: element to be stored at the specified position
Returns
E
the element previously at the specified position
Throws
IndexOutOfBoundsException

The thing is that your list "Test" is empty and when you are trying to
execute this statement test.set(5, "test"); it won't be able to set that
value in the list & will show Out of bounds exception as it will not create 10 empty spaces.
So, you can initialize your list before:
for(int i=0;i<10;i++) // As you took ten in your code
{
test.add(null); // some people also use test.add(0) instead of null ,
//but '0' also contains a value & considering your code please use null
}

Related

How to put a element in specific location of array list

I want to add a element in specific location of array list For that i tried to initialize the array list with inital capacity.
import java.util.ArrayList;
public class AddInArrayList{
public static void main(String[] args) {
ArrayList list = new ArrayList(4);
Object obj1 = new Object();
list.add(1, obj1);
}
}
OUTPUT
Exception in thread "main" java.lang.IndexOutOfBoundsException:
Index: 1, Size: 0
at java.util.ArrayList.add(ArrayList.java:359)
at AddInArrayList.main(AddInArrayList.java:7)
Is There any way to add a element by specific index location ?
You are confused about the meaning of capacity: the number you pass to the constructor does not set the inital list size.
You can't insert an element at index 1 of an empty list because list slots cannot be empty. If you wanted a function that expands the list before inserting at an index greater than its length, you could use:
static void addAtPos(List list, int index, Object o) {
while (list.size() < index) {
list.add(null);
}
list.add(index, o);
}
That said, ArrayLists are based on arrays which do not perform well with mid-insertion. So a different data structure will almost certainly be better suited to your problem, but you'd have to let us know what you're trying to achieve.
Arrays will not let you to perform insertion at an index which is greater than array.size.
So if you want to associate each item with a number/index it is better to use maps.
Map map = new HashMap<Integer, Object>();
Object obj1 = new Object();
map.put(1, obj1);
You're getting IndexOutOfBoundsException because when you call add(index, value), the value has to be not less than 0 and not bigger than list.size()-1. In your case it should be add(0, obj1).
initial capacity will be used only to set the initial "buffer" size of underlying array. so after calling new ArrayList(4) you list is still empty.
If you know your List will contain about 10_000 elements, create the ArrayList instance with intial capacity c = 10_000 + x. In this way you will avoid expensive ArrayList#grow(newcapacity) (Java 8) calls.
The method ArrayList#add(position, element) could be also called ArrayList#addAndMoveOtherToTheRight(position, element)

Variable length objects and using traditional for loop

In one of my methods, I need to pass objects as variable length parameters.
However, first I need to process the last object and then based on that many other processing will be done. I could not figure out how to use the index for each of the items in the variable argument list using traditional for loop and then index. So I used below code. Is this the right method to copy the object reference to another Array or ArrayList as I did? Otherwise what is the best method to access the specific object first and then loop through all other objects.
public static int generateConnectedPatterns(String endStr,Moorchana.MoorchanInnerClass...totalPatterns) {
// First copy all the objects to new ArrayList or Array of objects
ArrayList <Moorchana.MoorchanInnerClass> objectList = new ArrayList<>();
objectList.addAll(Arrays.asList(totalPatterns));
//Temporarily use lastObject variable for convenience.
Moorchana.MoorchanInnerClass lastObject = objectList.get(objectList.size()-1);
// Split the last input string into swaras
ArrayList<Integer> indices = new ArrayList<>();
ArrayList<String> tempPatternList = new ArrayList<>();
splitInputPatternIntoArrayList(tempPatternList , indices, lastObject.rawInputString);
if (Moorchana.validatePresenceInSwaraPool(endStr, lastObject.returnOuterObjectRef().swaraPool) == -1) {
return (-1);
}
// Get the index of the ending String
int indexofEndStr = lastObject.returnOuterObjectRef().getSwaraIndex(endStr);
// Now get the number of patterns to be generated.
int count = lastObject.returnOuterObjectRef().getPatternCount(indices, indexofEndStr);
// Now Do remaining programming here based on the count.
return(Constants.SUCCESS);
}
A varargs is basically an array.
Once you checked for null and length, you can access the last element just as you would with an array.
On the other hand, Arrays.asList returns a fixed-size list, which means you will not be able to manipulate its size later on, so beware of UnsupportedOperationExceptions.
In short, you can use the varargs as array and reference the last element once the necessary checks are performed.
Treat totalPatterns as an array.
To identify the last element: totalPatterns[totalPatterns.length-1]
for iteration, you could use an enhanced for loop.
for ( Moorchana.MoorchanInnerClass d : totalPatterns){...}
Note: Do a null check before you process the array, if you are not sure of the input being passed.

Length of ArrayList in Java

How do I find the size of an ArrayList in Java? I do not mean the number of elements, but the number of indexes.
public static void main(String[] args) {
ArrayList hash = new ArrayList(5);
System.out.println(hash.size());
}
Prints out "0." Using:
System.out.println(hash.toArray().length);
Also prints out a "0."
I have looked in http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html but I do not see a method that will help me. Is my ArrayList reverting to a size of 0 if I do not add anything to it?
EDIT The assignment is to create a hash table using ArrayList. I am supposed to create a hash function using the formula
double hashkey = Math.floor(hash.size()*(Math.E*key-Math.floor(Math.E*key)));
Where key is an integer. hashkey then becomes the index where the value will be stored. I am using hash.size() as a placeholder at the moment, but that value should be the capacity of my ArrayList.
ArrayList.size() will give the current size.That's why hash.size() giving you the current size of your ArrayList hash. It will not give you the capacity.
You just initialized the list. Have not add any elements to your arraylist, that's why its giving 0.
There is no such method in the ArrayList API. The capacity of an ArrayList is hidden by design.
However, I think that your question is based on a misunderstanding.
How do I find the size of an ArrayList in Java? I do not mean the number of elements, but the number of indexes.
In fact, the size of a List, the number of elements in a List, and the number of indexes (i.e. indexable positions) for a List ... are all the same thing.
The capacity of an ArrayList is something different. It is the number of elements that the object could contain, without reallocating the list's backing array. However, the fact that the list has a capacity N does NOT mean that you can index up to N - 1. In fact, you can only index up to size() - 1, irrespective of the capacity.
Now to deal with your examples:
ArrayList list = new ArrayList(5);
System.out.println(list.size());
This prints out zero because the list has zero elements. The ArrayList() and ArrayList(int) constructors both create and return lists that are empty. The list currently has space for 5 elements (because you gave it an initial capacity of 5) but you can't index those slots.
System.out.println(list.toArray().length);
This prints zero because when you copy the list's contents to an array (using toArray()), the array is the same size as the list. By definition.
This does not mean that the list's backing array has changed. On the contrary, it is still big enough to hold 5 elements without reallocation ... just like before.
But ... I hear you say ... the array's length is zero!
Yes, but that is not the backing array! The toArray() method allocates a new array and copies the List contents into that array. It does NOT return the actual backing array.
Maybe you should encapsulate your ArrayList in a class and add another attribute private int capacity in that class as well.
public class AdvancedArrayList<T>
{
private int capacity;
private ArrayList<T> list;
public AdvancedArrayList<T>(int capacity)
{
this.capacity = capacity;
list = new ArrayList<>();
}
public ArrayList<T> getList()
{
return list;
}
public int getCapacity()
{
return capacity;
}
public void addElement(T element)
{
if(list.size() < capacity)
list.add(element);
else
System.out.println("Capacity is full");
}
}
Notice that size is different than capacity.

IndexOutOfBoundsException when adding to ArrayList at index

I get exception Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 1, Size: 0 for the below code. But couldn't understand why.
public class App {
public static void main(String[] args) {
ArrayList<String> s = new ArrayList<>();
//Set index deliberately as 1 (not zero)
s.add(1,"Elephant");
System.out.println(s.size());
}
}
Update
I can make it work, but I am trying to understand the concepts, so I changed declaration to below but didnt work either.
ArrayList<String> s = new ArrayList<>(10)
ArrayList index starts from 0(Zero)
Your array list size is 0, and you are adding String element at 1st index. Without adding element at 0th index you can't add next index positions. Which is wrong.
So, Simply make it as
s.add("Elephant");
Or you can
s.add(0,"Elephant");
You must add elements to ArrayList serially, starting from 0, 1 and so on.
If you need to add elements to specific position you can do the following -
String[] strings = new String[5];
strings[1] = "Elephant";
List<String> s = Arrays.asList(strings);
System.out.println(s);
This will produce the sollowing output
[null, Elephant, null, null, null]
Your ArrayList is empty. With this line:
s.add(1,"Elephant");
You are trying to add "Elephant" at index 1 of the ArrayList (second position), which doesn't exist, so it throws a IndexOutOfBoundsException.
Use
s.add("Elephant");
instead.
ArrayList is not self-expandable. To add an item at index 1, you should have element #0.
If you REALLY want "Elephant" at index 1, then you can add another (e.g. null) entry at index 0.
public class App {
public static void main(String[] args) {
ArrayList<String> s = new ArrayList<>();
s.add(null);
s.add("Elephant");
System.out.println(s.size());
}
}
Or change the calls to .add to specify null at index 0 and elephant at index 1.
add(int index, E element) API says, Your array list has zero size, and you are adding an element to 1st index
Throws:
IndexOutOfBoundsException - if the index is out of range (index < 0 || index > size())
Use boolean add(E e) instead.
UPDATE based on the question update
I can make it work, but I am trying to understand the concepts, so I
changed declaration to below but didnt work either.
ArrayList<String> s = new ArrayList<>(10)
When you call new ArrayList<Integer>(10), you are setting the list's initial capacity to 10, not its size. In other words, when constructed in this manner, the array list starts its life empty.
For Android:
If you need to use a list that is going to have a lot of gaps it is better to use SparseArray in terms of memory (an ArrayList would have lots of null entries).
Example of use:
SparseArray<String> list = new SparseArray<>();
list.put(99, "string1");
list.put(23, "string2");
list.put(45, "string3");
Use list.append() if you add sequential keys, such as 1, 2, 3, 5, 7, 11, 13...
Use list.put() if you add non-sequential keys, such as 100, 23, 45, 277, 42...
If your list is going to have more than hundreds of items is better to use HashMap, since lookups require a binary search and adds and removes require inserting and deleting entries in the array.
You can initialize the size (not the capacity) of an ArrayList in this way:
ArrayList<T> list = new ArrayList<T>(Arrays.asList(new T[size]));
in your case:
ArrayList<String> s = new ArrayList<String>(Arrays.asList(new String[10]));
this creates an ArrayList with 10 null elements, so you can add elements in random order within the size (index 0-9).
Don't add index as 1 directly in list
If you want to add value in list add it like this
s.add("Elephant");
By default list size is 0
If you will add any elements in list, size will increased automatically
you cant add directly in list 1st index.
//s.add(0, "Elephant");
By the way, ArrayList<String> s = new ArrayList<>(10);
set the initialCapacity to 10.
Since the capacity of Arraylist is adjustable, it only makes the java knows the approximate capacity and try to avoid the performance loss caused by the capacity expansion.

java arraylist ensureCapacity not working

Either I'm doing this wrong or i'm not understanding how this method works.
ArrayList<String> a = new ArrayList<String>();
a.ensureCapacity(200);
a.add(190,"test");
System.out.println(a.get(190).toString());
I would have thought that ensureCapacity would let me insert a record with an index up to that value. Is there a different way to do this?
I get an IndexOutOfBounds error on the third line.
No, ensureCapacity doesn't change the logical size of an ArrayList - it changes the capacity, which is the size the list can reach before it next needs to copy values.
You need to be very aware of the difference between a logical size (i.e. all the values in the range [0, size) are accessible, and adding a new element will add it at index size) and the capacity which is more of an implementation detail really - it's the size of the backing array used for storage.
Calling ensureCapacity should only ever make any difference in terms of performance (by avoiding excessive copying) - it doesn't affect the logical model of what's in the list, if you see what I mean.
EDIT: It sounds like you want a sort of ensureSize() method, which might look something like this:
public static void ensureSize(ArrayList<?> list, int size) {
// Prevent excessive copying while we're adding
list.ensureCapacity(size);
while (list.size() < size) {
list.add(null);
}
}
So as others have mentioned ensureCapacity isn't for that.
It looks like you want to start out with an ArrayList of 200 nulls? Then this would be the simplest way to do it:
ArrayList<String> a = new ArrayList<String>(Arrays.asList( new String[200] ));
Then if you want to replace element 190 with "test" do:
a.set(190, "test");
This is different from
a.add(190, "test");
which will add "test" in index 190 and shift the other 9 elements up, resulting in a list of size 201.
If you know you are always going to have 200 elements it might be better to just use an array.
Ensuring capacity isn't adding items to the list. You can only get element 190 or add at element 190 if you've added 191 elements already. "Capacity" is just the number of objects the ArrayList can hold before it needs to resize its internal data structure (an array). If ArrayList had a getCapacity(), then doing this:
ArrayList<String> a = new ArrayList<String>();
a.ensureCapacity(200);
System.out.println(a.size());
System.out.println(a.getCapacity());
would print out 0 and some number greater than or equal to 200, respectively
ArrayList maintains its capacity (the size of the internal array) separately from its size (the number of elements added), and the 'set' method depends on the index already having been assigned to an element. There isn't a way to set the size. If you need this, you can add dummy elements with a loop:
for (int i = 200; --i >= 0;) a.add(null);
Once again JavaDoc to clarify the situation:
Throws: IndexOutOfBoundsException
- if index is out of range (index < 0 || index > size()).
Note that size() returns the number of elements currently held by the List.
ensureCapacity just makes sure that the underlying array's capacity is greater than or equal to the argument. It doesn't change the size of the ArrayList. It does't make any changes visible through the API, so you won't notice a difference except that it will probably be longer before the ArrayList resizes it's internal array.
Adding 190 null entries to an ArrayList reeks of a misuse of the data structure.
Think about using a standard primitive array.
If you require a generics or want more efficient use of space then consider SparseArray or even a Map like a HashMap may be appropriate for your purposes.
public static void fillArrayList(ArrayList<String> arrayList, long size) {
for (int i = 0; i < size + 1; i++) {
arrayList.add(i,"-1");
}
}
public static void main(String[] args) throws Exception {
ArrayList<String> a = new ArrayList<String>(10);
fillArrayList(a, 190);
a.add(190,"test");
System.out.println(a.get(190).toString());
}

Categories