Search code examples
javaandroidexecution

Java & Order of Execution


I released my first Android app and I'm attempting to troubleshoot some bugs that have resulted in crashes (as identified via the Google Play Console).

The code simplified the code as much as possible - the following method is called:

private void gameMethod(int switchCase, ArrayList gameArray) {


boolean magicBoolean = false;
ArrayList magicList = new ArrayList<>();

switch(switchCase) {
    case 1:
          for(int i = 0; i < 4; i++) {
   
              if(gameArray.get(i) == 2) {
         
                  magicBoolean = true;
              } 

              if(magicBoolean) {
                  magicList.add(gameArray.get(i));
              } 
           }
           break;

     case 2:
          // basic repeat of case 1
          break;
     case 3:
          // basic repeat of case 1
          break;
                                                        
}


newMagicMethod(ArrayList magicList);

As you can see, the 2nd method (newMagicMethod) uses the magicList which is populated via the switch. The magicList size will never be 0, the first method is only called when the array has more than 1 item in it.

In my crash report it is telling me the following:

Exception java.lang.IndexOutOfBoundsException: Index: 0, Size: 0

So I conclude that somehow the 2nd method is attempting to use the magicList (e.g find and use the 1st item on the list) and then crashes when the list is empty.

My question would be is there any way that the Java code would attempt to execute the call to the newMagicMethod() FIRST before the switch statement is executed. Obviously is this is the case this would explain how the arrayList could be empty and would cause a crash. Otherwise I have look for other reasons as to why the arrayList could be empty.

If I could confirm if code like this can execute out of order, I would figure out a way to resolve/define the order.


Solution

  • The short answer is NO — the switch statement itself is not asynchronous. It will be fully executed, and only after that will your newMagicMethod() be called.

    However, it seems that the code you provided is pseudo-code, since it wouldn't compile. For example, you can't declare an ArrayList inline within a method call, as you currently do here, where you presumably meant to use the magicList variable declared further up within gameMethod():

    newMagicMethod(ArrayList magicList)
    

    Given that you've only provided pseudo-code, here are a couple of things to consider:

    • Do you have any asynchronous calls in your case blocks? If so, you may have introduced a race condition where there's no guarantee that your collection will be populated before the call to newMagicMethod().
    • Are you sure the logic in your case blocks guarantees that at least one object will end up in your collection? The most likely explanation here is that you failed to account for a scenario whereby your calls to add() will be bypassed. You can use breakpoints or logging to catch such unexpected scenarios.
    • Do you have a default block, where you log the fact that your collection will be empty, or maybe throw an exception? It's all-too-common for developers to assume they've covered all cases in a switch statement, when in fact there are one or more cases for which they forgot to account.