Can't add to an array list - java

I have the oddest problem, probably with a simple solution.
I have created and initialized a list and then proceeded to create 4 objects of the list's type. In the constructor of these they place themselves in the list. Or at least are supposed to. I always get an out of bound exception and I cant figure out why. I set the list to have a size of 402 (for all possible VK values) but in the console and debug it always says it has size 0, no matter how large or empty I set it too....
public class InputHandler implements KeyListener
{
public static List<Key> keyList = new ArrayList<Key>(KeyEvent.KEY_LAST);
public Key up = new Key(KeyEvent.VK_UP);
public Key down = new Key(KeyEvent.VK_DOWN);
public Key left = new Key(KeyEvent.VK_LEFT);
public Key right = new Key(KeyEvent.VK_RIGHT);
public class Key
{
public int keyCode;
public Key(int defaultCode)
{
this.keyCode = defaultCode;
keyList.add(keyCode,this);
}
public Key reMapKey(int newKey)
{
keyList.remove(keyCode);
keyList.set(newKey, this);
this.keyCode = newKey;
return this;
}
}
}
There is more to the code but I attempted to SSCCE it.
The only info of value from the console is this:
Exception in thread "RogueLoveMainThread" java.lang.IndexOutOfBoundsException: Index: 38, Size: 0
Much apologies for my stupidity

You've created a new ArrayList with a capacity of 402, but it's still got a size of 0 after the constructor call. From the docs of the constructor call you're using:
public ArrayList(int initialCapacity)
Constructs an empty list with the specified initial capacity.
Parameters:
initialCapacity - the initial capacity of the list
And from the docs of ArrayList itself:
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 capacity is not the size.
So, some options:
Populate the list with null entries until you have got the size you want
Use an array instead of a list (after all, you only need it to be a fixed size, right?)
Use a Map<Integer, Key> instead

keyList.add(keyCode, this) inserts at the position of keyCode. As your list is still empty (size 0) you cannot insert at any position position greater than 0.
You might want to have map codes to keys, do you? There is a Map<K, V> for this:
static Map<Integer, Key> keyMap = new TreeMap<>();
public Key(int defaultCode) {
keyMap.add(keyCode, this);
}
If you need a key by its code, you can receive it from the Map as follows:
keyMap.get(keyCode);

Related

The call to "get" always fails to index as index is out of bounds

I hope I am not writing here a duplicate question, I tried to look it up but I didn't find anything.
So I have a class with the name Map, for which I try to configure my generator function so that it takes the parameter ListOfLocations together with two more integers width and height.
There is another class named Places, where I give the coordinates from the List of locations and it creates an instance. And a third one that handles the coordinates.
public class Map {
private ArrayList <ArrayList<Places>> newMap = new ArrayList<>();
public Map(int width, int height, Collection <Coordinate> places){
//Create places
for (int i=0;i<=width-1;i++){
for (int j=0;j<=height-1;j++){
newMap.get(i).add(new Place(new Coordinate(i,j)));
}
}
The idea is that it goes through all the combinations (i,j) it creates a coordinate and passes that coordinate to the class Place. Since I have my Map as an ArrayList of ArrayLists (I want it in 2D) I try to call a field with .get
Ex. when it is handling width i it should take the list on position i and add a new Place.
But I get a
The call to "get" always fails as index out of bounds.
The same happens in two other places where I have the .get call.
Could someone explain to me where my mistake is?
Thanks in advance :)
You initialize the list but never populate it :
// The List is not null but is actually empty
private ArrayList <ArrayList<Places>> newMap = new ArrayList<>();
Hence, newMap.get(0) does not make sense. You get the first element of a list which is empty.
You can do it like this :
public class Map {
private ArrayList <ArrayList<Places>> newMap = new ArrayList<>();
public Map(int width, int height, Collection <Coordinate> places){
for (int i=0;i<=width-1;i++){
ArrayList<Places> list = new ArrayList<Places>();
for (int j=0;j<=height-1;j++){
list.add(new Place(new Coordinate(i,j)));
}
newMap.add(list);
}
Some advices :
Don't call your class Map, there is already a class with this name and it will bring some confusion.
When declaring the list, prefer declaring it as a List (interface), not an ArrayList (the actual implementation).
like this :
private List<List<Places>> newMap = new ArrayList<>();

Java - Array index out of range - Vector?

I'm testing a method that adds a linked list of hash pairs inside a vector. Although, I'm running into a IndexOutOfBounds but I'm having trouble understanding where the problem exists.
import java.util.*;
class HashPair<K, E> {
K key;
E element;
}
public class Test4<K, E> {
private Vector<LinkedList<HashPair<K, E>>> table;
public Test4(int tableSize) {
if (tableSize <= 0)
throw new IllegalArgumentException("Table Size must be positive");
table = new Vector<LinkedList<HashPair<K, E>>>(tableSize);
}
public E put(K key, E element) {
if (key == null || element == null)
throw new NullPointerException("Key or element is null");
int i = hash(key);
LinkedList<HashPair<K, E>> onelist = table.get(i);
ListIterator<HashPair<K, E>> cursor = onelist.listIterator();
HashPair<K, E> pair;
E answer = null;
while (cursor.hasNext()) {
pair = cursor.next();
if (pair.key.equals(key)) {
answer = pair.element;
pair.element = element;
return answer;
}
}
pair = new HashPair<K, E>();
pair.key = key;
pair.element = element;
onelist.addFirst(pair);
return answer;
}
private int hash(K key) {
return Math.abs(key.hashCode() % table.capacity());
}
public static void main(String[] args) {
Test4<Integer, Integer> obj = new Test4<Integer, Integer>(10);
obj.put(0, 10);
}
}
My compiler says that the problem is here:
LinkedList<HashPair<K, E>> onelist = table.get(i);
From what I understand is that I'm trying to get the table index of i which is a hash value generated from the hash(K key) method. So in my main method if I set the key to 0 as an example? Why is the index out of range?
Here is the exception
Exception in thread "main" 0java.lang.ArrayIndexOutOfBoundsException:
Array index out of range: 0
at java.util.Vector.get(Vector.java:748)
at Test4.put(Test4.java:24)
at Test4.main(Test4.java:55)
The problem here is that you are considering the capacity of a vector to be the number of elements in the vector. This is not what capacity of a collection represents.
The capacity of a collection in the standard Java libraries is the size of the internal array used by that collection. The number of elements in the collection, however, is represented by size.
Whenever an element is added to/removed from such a collection, the size property is modified. This does not affect the capacity of the collection unless the internal array needs to be resized.
The solution: modify hash() to the following:
private int hash(K key) {
return Math.abs(key.hashCode() % table.size());
}
And make sure that the table vector contains at least one element before calling hash and table.get.
I presume that you are creating an implementation of a HashMap with buckets. If you are, then ponder this: How can you go about storing a value in a bucket if there aren't any buckets? You need to have at least one bucket before trying to get a bucket.
It seems your code is getting stuck at line 748, which is:
LinkedList<HashPair<K, E>> onelist = table.get(i);
The description Array index out of range: 0 means you're trying to get an object at slot '0', when there is no such slot available at the time. In short: your vector is empty. And by looking at your code, the reason becomes pretty evident. The only treatment this Vector called table receives before Test4.put() is called gets down to this at line 15:
table = new Vector<LinkedList<HashPair<K, E>>>(tableSize);
So, yes, you're properly creating an object and initializing a variable, you are even specifying a default capacity, but you never added something into your brand new Vector, and both lists and vectors do require to be filled manually with stuff first. Keep on mind that this "capacity" refers to how much stuff is this Vector supposed to hold without need to resize the array it uses internally. It gives me the impression you are trying to create a class whose objects have a behavior like HashMaps, but I can't wrap my mind around the need of using a Vector of LinkedLists of KeyPairs when just a single collection of KeyPairs should be enough unless... wait, what is that hash() method doing? Oh... ohh... oh, I see what you did there.
So, right, the solution. As your Vector is properly created but empty, you need to fill it with whatever it is supposed to hold. In this case, it holds LinkedLists of KeyPairs, so let's fill it with just enough of them to hold the capacity you set through the constructor. This modification to the constructor should do the thing:
public Test4(int tableSize) {
if (tableSize <= 0)
throw new IllegalArgumentException("Table Size must be positive");
table = new Vector<LinkedList<HashPair<K, E>>>(tableSize);
//Prepare the fast lookup table (at least that's what I think it could be called)
for (int i = 0; i < tableSize; i++) {
table.add(new LinkedList<HashPair<K, E>>());
}
}
And that's pretty much it. I even tested it here just to be sure it worked fine after my patch.
Hope this helps you.
PS: Splitting your structure in n pieces to speedup search/store? I like the idea.

Comparison Error when Storing values in a List, Boolean Map

I have a fully working version of MineSweeper implemented in Java. However, I am trying to add an additional feature that updates a Map to store the indexes of the locations of the mines within a 2D array. For example, if location [x][y] holds a mine, I am storing a linked list containing x and y, which maps to a boolean that is true to indicate that the space holds a mine. (This feature is seemingly trivial, but I am just doing this to practice with Collections in Java.)
My relevant private instance variables include:
public Class World{ ...
private LinkedList<Integer> index;
private Map<LinkedList<Integer>, Boolean> revealed;
"index" is the list to be stored in the map as the key for each boolean.
In my constructor I have:
public World(){ ...
tileArr = new Tile[worldWidth][worldHeight];
revealed = new TreeMap<LinkedList<Integer>, Boolean>();
index = new LinkedList<Integer>();
... }
Now, in the method in which I place the mines, I have the following:
private void placeBomb(){
int x = ran.nextInt(worldWidth); //Random stream
int y = ran.nextInt(worldHeight); //Random stream
if (!tileArr[x][y].isBomb()){
tileArr[x][y].setBomb(true);
index.add(x); //ADDED COMPONENT
index.add(y);
revealed.put(index, true);
index.remove(x);
index.remove(y); //END OF ADDED COMPONENT
} else placeBomb();
}
Without the marked added component my program runs fine, and I have a fully working game. However, this addition gives me the following error.
Exception in thread "main" java.lang.ClassCastException: java.util.LinkedList
cannot be cast to java.lang.Comparable
If anyone could help point out where this error might be, it would be very helpful! This is solely for additional practice with collections and is not required to run the game.
There are actually about 3 issues here. One that you know about, one that you don't and a third which is just that using LinkedList as a key for a map is clunky.
The ClassCastException happens because TreeMap is a sorted set and requires that every key in it implement the Comparable interface, or else you have to provide a custom Comparator. LinkedList doesn't implement Comparable, so you get an exception. The solution here could be to use a different map, like HashMap, or you could write a custom Comparator.
A custom Comparator could be like this:
revealed = new TreeMap<List<Integer>, Boolean>(
// sort by x value first
Comparator.comparing( list -> list.get(0) )
// then sort by y if both x values are the same
.thenComparing( list -> list.get(1) )
);
(And I felt compelled to include this, which is a more robust example that isn't dependent on specific elements at specific indexes):
revealed = new TreeMap<>(new Comparator<List<Integer>>() {
#Override
public int compare(List<Integer> lhs, List<Integer> rhs) {
int sizeComp = Integer.compare(lhs.size(), rhs.size());
if (sizeComp != 0) {
return sizeComp;
}
Iterator<Integer> lhsIter = lhs.iterator();
Iterator<Integer> rhsIter = rhs.iterator();
while ( lhsIter.hasNext() && rhsIter.hasNext() ) {
int intComp = lhsIter.next().compareTo( rhsIter.next() );
if (intComp != 0) {
return intComp;
}
}
return 0;
}
});
The issue that you don't know about is that you're only ever adding one LinkedList to the map:
index.add(x);
index.add(y);
// putting index in to the map
// without making a copy
revealed.put(index, true);
// modifying index immediately
// afterwards
index.remove(x);
index.remove(y);
This is unspecified behavior, because you put the key in, then modify it. The documentation for Map says the following about this:
Note: great care must be exercised if mutable objects are used as map keys. The behavior of a map is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is a key in the map.
What will actually happen (for TreeMap) is that you are always erasing the previous mapping. (For example, the first time you call put, let's say x=0 and y=0. Then the next time around, you set the list so that x=1 and y=1. This also modifies the list inside the map, so that when put is called, it finds there was already a key with x=1 and y=1 and replaces the mapping.)
So you could fix this by saying something like either of the following:
// copying the List called index
revealed.put(new LinkedList<>(index), true);
// this makes more sense to me
revealed.put(Arrays.asList(x, y), true);
However, this leads me to the 3rd point.
There are better ways to do this, if you want practice with collections. One way would be to use a Map<Integer, Map<Integer, Boolean>>, like this:
Map<Integer, Map<Integer, Boolean>> revealed = new HashMap<>();
{
revealed.computeIfAbsent(x, HashMap::new).put(y, true);
// the preceding line is the same as saying
// Map<Integer, Boolean> yMap = revealed.get(x);
// if (yMap == null) {
// yMap = new HashMap<>();
// revealed.put(x, yMap);
// }
// yMap.put(y, true);
}
That is basically like a 2D array, but with a HashMap. (It could make sense if you had a very, very large game board.)
And judging by your description, it sounds like you already know that you could just make a boolean isRevealed; variable in the Tile class.
From the spec of a treemap gives me this:
The map is sorted according to the natural ordering of its keys, or by a Comparator provided at map creation time, depending on which constructor is used.
The Java Linkedlist can not be compared just like that. You have to give it a way to compare them or just use another type of map, that does not need sorting.

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)

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.

Categories