This code tracks what missiles players buy and sets the most recent 3 at the top of the list of missile options for players to easily buy them again. After players purchase missiles, the game crashes, but only if they purchase certain ones or purchase a certain amount.
Process: com.apps.fast.counterforcetest, PID: 16063
java.lang.IndexOutOfBoundsException: Index: 5, Size: 3
at java.util.LinkedList.checkElementIndex(LinkedList.java:555)
at java.util.LinkedList.remove(LinkedList.java:525)
at com.apps.fast.launch.components.ClientDefs.SetMissilePreferred(ClientDefs.java:199)
at com.apps.fast.launch.launchviews.PurchaseLaunchableView$1$1.onClick(PurchaseLaunchableView.java:198)
Here is the code the error points to in CLientDefs.java:199
public static void SetMissilePreferred(int lMissile) {
// Set a purchased missile to go to the top of the preferred list.
if (MissilePreferences == null)
MissilePreferences = new LinkedList<>();
if (MissilePreferences.contains(lMissile))
MissilePreferences.remove(lMissile); //<---- Line 199
MissilePreferences.push(lMissile);
if (MissilePreferences.size() > PREFERENCE_LIST_SIZE)
MissilePreferences.removeLast();
}
MissilePreferences
is a List of Integers.
2
Answers
Try debugging the code so that you know what are the elements in the list and what element is being removed. I am still confused as to how can you get an index out of bounds exception when you are just accessing the element from the list by its value.
There’s a bit of a mixup going on here:
lMissile
is anint
, right? Representing an ID? So when you callcontains
, you’re checking if that ID exists inMissilePreferences
. You want to know if theList
contains thatint
.Here’s the method signature for
contains
:It doesn’t take a primitive like an
int
, it takes anObject
– so yourint
is being autoboxed into anInteger
– which makes sense because aList
can’t contain primitives either, only objects.MissilePreferences
is a list ofInteger
s.So that’s all fine, it converts your
int
to anInteger
and tells you if it exists in the list ofInteger
s, perfect! But then you callremove
with that originalint
. And there are two versions of that method that take a parameter:Those do two very different things. The
Object
version removes the first instance of that object from the list. Theint
version treats theint
as an index and removes whatever is in that position.When you use
contains
, you’re treating yourint
as an element in the list you want to find, and it’s automatically converted to anInteger
. And you want to do the same withremove
– but there’s a different version of that method that takes theint
you’re providing directly. It won’t autobox that and call the other method, obviously! You’d have to do it yourself:That’s what you have to watch out for – outside of arrays and some special classes you might run into elsewhere, collection objects don’t contain primitives, so you often want to explicitly work with the
Object
wrapper versions they contain. Especially important forint
s because of situations like this!That said, you could just do this:
No need to use
contains
– you can just callremove
and it’ll remove the first matching object if it has one. It returns true if it removed anything, in case you need to check that