IndexOutOfBoundsException when adding to ArrayList at index - java

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.

Related

Remove elements from a List at a specific index

I am trying to program a method that deletes the first, second and third element of every group of 4 elements.
It seems not working at all.
Could anyone please help?
public static void reduziereKommentare(List<String> zeilen) {
if (!zeilen.isEmpty()) {
if (zeilen.size() % 4 != 0) {
throw new RuntimeException("Illegal size " + zeilen.size() + " of list, must be divisible by 4.");
}
for (int i = 1; i <= zeilen.size() % 4; i++) {
zeilen.remove(i);
zeilen.remove(i + 1);
zeilen.remove(i + 2);
}
}
System.out.println(zeilen);
}
As said in the comments, removing an element impacts the indexing. Whenever I need to do something like this, I either use an Iterator, or loop backwards.:
for (int i = zeilen.size() - 4; i >= 0; i -= 4) {
zeilen.remove(i + 2);
zeilen.remove(i + 1);
zeilen.remove(i);
}
Note that I subtract 4 from i each iteration, so I go back a full block of four each time.
Also note that I remove the largest indexed elements first. If I use i, i + 1 and i + 2 inside the loop, I again run into the same issue. I could also have used i 3 times, but this makes it more clear.
My take...does not require the size precondition check but you may want to still catch that if it represents an error of broader scope than this method.
Given this test code...
// Test code
List<String> myList = new ArrayList<>();
for (int i = 0; i < 20; i++) {
myList.add(String.valueOf(i));
}
the 'zeilen' loop can be implemented as ...
// "before" diagnostics
System.out.println(zeilen);
// The 'zeilen' loop
for (int i = 0, limit = zeilen.size(); i < limit; i++) {
if ((i+1) % 4 > 0) zeilen.remove(i/4);
}
// "after" diagnostics
System.out.println(zeilen);
and produces
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
[3, 7, 11, 15, 19]
Works with any length list leaving every '4th' element in list.
A few more test cases :
Given Results in
[] []
[0,1] []
[0,1,2,3] [3]
[0,1,2,3,4] [3]
[0,1,2,3,4,5,6,7] [3,7]
[0,1,2,3,4,5,6,7,8] [3,7]
Would it not be easier to simply add every fourth item to a new list and return that? This would also eliminate any repetitive copying that could be involved when removing elements from a list. And the target list can be appropriately sized to start.
public static List<String> reduziereKommentare(List<String> zeilen) {
Objects.requireNonNull(zeilen);
List<String> zeilen1= new ArrayList<>(zeilen.size()/4);
for(int i = 3; i < zeilen.size(); i+=4) {
zeilen1.add(zeilen.get(i));
}
return zeilen1;
}
You could also use a stream.
zeilen = IntStream.iterate(3, i ->i < zeilen.size(), i->i+=4)
.mapToObj(zeilen::get).toList();
Notes:
whether the list is empty or the size is not divisible by 4, this will work. It will just ignore the extra elements.
assigning the result to the original variable will result in the old list being garbage collected.
I only check for a null argument since that would cause an exception. Of course, if alerting the user of the size is important just add the other check(s) back in.
Your code sample uses a data type of List - List<String> zeilen - but you separately wrote a comment which states that you're starting from an array:
"I used the Arrays.asList() function to add elements to the list"
The signature for asList() shows the input argument is an array, defined using varargs:
public static <T> List<T> asList(T... a)
Thus, you would start from something like this:
// rely on automatic array creation via varargs
List<String> list = Arrays.asList("one", "two", "three");
or from an explicit array, like this:
String[] strings = {"one", "two", "three"};
List<String> list = Arrays.asList(strings);
Here's a more complete picture of your current solution:
start with an array – String[] – creating it explicitly or relying on automatic array creation via varargs
create a List<String> from that array using Arrays.asList()
traverse the List skipping three items at a time, keeping only each fourth item (so: 4th, 8th, 12th, 16th, etc.)
Since the starting point is a String array, and knowing that you're
interested in keeping only every 4th element,
you could:
create a new, empty java.util.List<String>
iterate over each element of the array
for every 4th, 8th, etc element, add that to the final result list; ignore everything else
Here's the code to do that:
private static List<String> buildListOfEveryFourthElement(String[] array) {
List<String> everyFourthElement = new ArrayList<>();
if (array != null) {
// start from "1", a bit easier to reason about "every 4th element"?
int current = 1;
for (String s : array) {
if (current > 1 && current % 4 == 0) {
everyFourthElement.add(s);
}
current++;
}
}
return everyFourthElement;
}
I omitted the check for whether the input is exactly divisible by 4, but you could easily edit the first if statement
to include that: if (array != null && array.length % 4 == 0) { .. }
A benefit to this "build the List as you go" approach (vs. calling Arrays.asList() with a starting array)
is that the original input array would not be associated in any way with the result list.
So what? As you mentioned in one of your comments that you discovered it's not permissible
to modify the list – calling .remove() will throw java.lang.UnsupportedOperationException.
Note this will also happen if you try to add() something to the list.
Why does it throw an exception?
Because asList() returns a java.util.List which is backed by the input array, meaning the list and array are
sort of tied together. If it allowed you to remove (or add) items from (or to) the
list then it would also have to automatically update the backing array, and they didn't implement it that way.
Here's a brief snip from asList() Javadoc:
Returns a fixed-size list backed by the specified array. (Changes to the returned list "write through" to the array.)
By creating a new List and populating it along the way, you are free to modify that list later in your code
by removing or adding elements, sorting the whole thing, etc. You would also be guarded against any changes to the array
showing up as (possibly surprising) changes in the list – because
the list is backed by the array, a change in an array element would be visible in the associated list.

Set Method of ArrayList throwing IndexOutOfBoundsException

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
}

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)

Java ArrayList IndexOutOfBoundsException despite giving an initial capacity

When I do
ArrayList<Integer> arr = new ArrayList<Integer>(10);
arr.set(0, 1);
Java gives me
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.rangeCheck(Unknown Source)
at java.util.ArrayList.set(Unknown Source)
at HelloWorld.main(HelloWorld.java:13)
Is there an easy way I can pre-reserve the size of ArrayList and then use the indices immediately, just like arrays?
How about this:
ArrayList<Integer> arr = new ArrayList<Integer>(Collections.nCopies(10, 0));
This will initialize arr with 10 zero's. Then you can feel free to use the indexes immediately.
Here's the source from ArrayList:
The constructor:
public ArrayList(int initialCapacity)
{
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
this.elementData = new Object[initialCapacity];
}
You called set(int, E):
public E set(int index, E element)
{
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
Set calls rangeCheck(int):
private void rangeCheck(int index)
{
if (index >= size) {
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
}
It may be subtle, but when you called the constructor, despite initializing an Object[], you did not initialize size. Hence, from rangeCheck, you get the IndexOutOfBoundsException, since size is 0. Instead of using set(int, E), you can use add(E e) (adds e of type E to the end of the list, in your case: add(1)) and this won't occur. Or, if it suits you, you could initialize all elements to 0 as suggested in another answer.
I believe the issue here is that although you have suggested the allocated space of entries in the Array, you have not actually created entries.
What does arr.size() return?
I think you need to use the add(T) method instead.
Programming aside, what you are trying to do here is illogical.
Imagine an empty egg carton with space for ten eggs. That is more or less what you have created. Then you tell a super-precise-and-annoying-which-does-exactly-what-you-tell-him robot to replace the 0th egg with another egg. The robot reports an error. Why? He can't replace the 0th egg, because there is no egg there! There is a space reserved for 10 eggs, but there are really no eggs inside!
You could use arr.add(1), which will add 1 in the first empty cell, i.e. the 0-indexed one.
Or you could create your own list:
public static class PresetArrayList<E> extends ArrayList<E> {
private static final long serialVersionUID = 1L;
public PresetArrayList(int initialCapacity) {
super(initialCapacity);
addAll(Collections.nCopies(initialCapacity, (E) null));
}
}
Then:
List<Integer> list = new PresetArrayList<Integer>(5);
list.set(3, 1);
System.out.println(list);
Prints:
[null, null, null, 1, null]
This is not an Java-specific answer but an data structure answer.
You are confusing the Capacity concept with the Count (or Size) one.
Capacity is when you tell the list to reserve/preallocate a number of slots in advance (in this ArrayList case, you are saying to it create an array of 10 positions) in its' internal storage. When this happens, the list still does not have any items.
Size (or Count) is the quantity of items the list really have. In your code, you really doesn't added any item - so the IndexOutOfBoundException is deserved.
While you can't do what you want with arraylist, there is another option: Arrays.asList()
Capacity is used to prepare ArrayLists for expansion. Take the loop
List<Integer> list = new ArrayList<>();
for(final int i = 0; i < 1024; ++i) {
list.add(i);
}
list starts off with a capacity of 10. Therefore it holds a new Integer[10] inside. As the loop adds to the list, the integers are added to that array. When the array is filled and another number is added, a new array is allocated twice the size of the old one, and the old values are copied to the new ones. Adding an item is O(1) at best, and O(N) at worst. But adding N items will take about 2*1024 individual assignments: amortized linear time.
Capacity isn't size. If you haven't added to the array list yet, the size will be zero, and attempting to write into the 3rd element will fail.

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