Search code examples
javaandroidarraylistnull-pointer

How to store custom objects in an ArrayList


I'm making a game with cards, characters cards.

I first create the cards chosen by the user, then add them to a List, shuffle it and then display 'em one by one, with their players name (chosen in a previous activity by the user).

The fact is, when I try to get the a Card class from the List, and invoking its methods getPlayer() & getCharacter (which return the player's name and the characters' name of the specific card) I get the nullPointer Exception.

java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.example.leonardo.lupusintabula.characters.Card.getCharacter()' on a null object reference

randomButton.setText(characters.get(0).getCharacter() + " / " + characters.get(0).getPlayer());

The onCreate():

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_random_assignment);

    //Retrieving
      ...
    //Done retrieving
    initializeVariables();
    createCharacters();
    run();
}

As the issue is probably in characters, I'm listing you all the code it's in:

// Where the characters are stored
private ArrayList<Card> characters;


public void initDeck() {
    addCharacter(demoniac, demoniacAmount, characters);
    addCharacter(guard, guardAmount, characters);
    addCharacter(medium, mediumAmount, characters);
    addCharacter(mythomaniac, mythomaniacAmount, characters);
    addCharacter(owl, owlAmount, characters);
    addCharacter(werehamster, werehamsterAmount, characters);
    addCharacter(getVillagerBundle(), villagerAmount, characters);
    addCharacter(masonOne, 1, characters);
    addCharacter(masonTwo, 1, characters);
}

public void addCharacter(Card card, int amount, List<Card> cards) {
    if (amount < 0) {
        throw new IllegalArgumentException("Must add a non-negative number of characters for " + card.getCharacter() );
    }

    for (int i = 0; i < amount; i++) {
        cards.add(card);
    }
}



//Pick a random one and display it
public void pick(View view){
    if(characters != null) {
        if (i < characters.size()) {
            randomButton.setText(characters.get(i).getCharacter() + " / " + characters.get(i).getPlayer());
            i++;
        } else {
            randomButton.setText(R.string.play);
        }
    }
}

void run() {
    // initialize the characters
    initDeck();

    // shuffle them
    Collections.shuffle(characters);

    //Display the 1st card
    if(characters != null) {
        randomButton.setText(characters.get(0).getCharacter() + " / " + characters.get(0).getPlayer());
    }
}


private void initializeVariables() {
    ...
    ...

    characters = new ArrayList<Card>();
 }

}

What am I doing wrong? If you need other part of the code feel free to ask, I'll provide it to you as soon as possible!

This may drive you crazy but it's the only way I found to achieve the creation of the characters (each character extends the Card class!):

public void createCharacters() {
    if (demoniacAmount != 0) {
        demoniac = new Demoniac(nameList.get(listIndex));
        listIndex++;
    } else if (guardAmount != 0) {
        guard = new Guard(nameList.get(listIndex));
        listIndex++;
    } else if (mediumAmount != 0) {
        medium = new Medium(nameList.get(listIndex));
        listIndex++;
    } else if (mythomaniacAmount != 0) {
        mythomaniac = new Mythomaniac(nameList.get(listIndex));
        listIndex++;
    } else if (owlAmount != 0) {
        owl = new Owl(nameList.get(listIndex));
        listIndex++;
    } else if (werehamsterAmount != 0) {
        werehamster = new Werehamster(nameList.get(listIndex));
        listIndex++;
    } else if (masonsAmount != 0) {
        masonOne = new Masons(nameList.get(listIndex));
        masonTwo = new Masons(nameList.get(listIndex));
        listIndex += masonsAmount;
    } else if (villagerAmount > 5) {
            villagerSix = new Villager(nameList.get(listIndex));
            villagerBundle.add(villagerSix);

            if (villagerAmount > 6) {
                villagerSeven = new Villager(nameList.get(listIndex));
                villagerBundle.add(villagerSeven);

                if (villagerAmount > 7) {
                    villagerEight = new Villager(nameList.get(listIndex));
                    villagerBundle.add(villagerEight);

                    if (villagerAmount > 8) {
                        villagerNine = new Villager(nameList.get(listIndex));
                        villagerBundle.add(villagerNine);

                        if (villagerAmount > 9) {
                            villagerTen = new Villager(nameList.get(listIndex));
                            villagerBundle.add(villagerTen);

                            if (villagerAmount > 10) {
                                villagerEleven = new Villager(nameList.get(listIndex));
                                villagerBundle.add(villagerEleven);

                                if (villagerAmount > 11) {
                                    villagerTwelve = new Villager(nameList.get(listIndex));
                                    villagerBundle.add(villagerTwelve);

                                    Toast.makeText(RandomAssignment.this, "works", Toast.LENGTH_SHORT).show();
                                }
                            }
                        }
                    }
                }
            }
        }
        listIndex += villagerAmount;
    }

Solution

  • From my other answer, from which you took my code. The initDeck method actually reads like this

    public void initDeck() {
        if (characters == null)
            characters = new ArrayList<String>();
    
            // addCharacter...
    

    That will at least avoid a null pointer on the list...


    You need to add more code to your question, but the problem starts in this block

    addCharacter(demoniac, demoniacAmount, characters);
    addCharacter(guard, guardAmount, characters);
    addCharacter(medium, mediumAmount, characters);
    addCharacter(mythomaniac, mythomaniacAmount, characters);
    addCharacter(owl, owlAmount, characters);
    addCharacter(werehamster, werehamsterAmount, characters);
    addCharacter(getVillagerBundle(), villagerAmount, characters);
    addCharacter(masonOne, 1, characters);
    addCharacter(masonTwo, 1, characters);
    

    which (roughly) calls this code

    public void addCharacter(Card card, int amount, List<Card> cards) {
        for (int i = 0; i < amount; i++) {
            cards.add(card);
        }
    }
    

    The issue is that somewhere ANY of these variables are null and they are being added to the list as such

    • demoniac
    • guard
    • medium
    • mythomaniac
    • owl
    • werehamster
    • getVillagerBundle()
    • masonOne
    • masonTwo

    You could either fix that by assigning all those variables to a new Card(), or avoid the problem like so

    public void addCharacter(Card card, int amount, List<Card> cards) {
        for (int i = 0; i < amount; i++) {
            if (card != null) {
                cards.add(card);
            } else {
                Log.e("addCharacter", "Hey! Are you sure you meant to add a null card?");
            }
        }
    }
    

    Now what you have shown more of the code, the error starts here

    if (demoniacAmount != 0) {
        demoniac = new Demoniac(nameList.get(listIndex));
        listIndex++;
    } else if (guardAmount != 0) {
        guard = new Guard(nameList.get(listIndex));
        listIndex++;
    }
    

    What if demoniacAmount and guardAmount are both not zero, hmm? Only that first if condition will be entered. And guard will end up being null because it was never initialized. It makes no sense to do an else-if for completely different variables!

    Properly perform your if-checking like so for all those conditions. (And I will leave the messy code as much as it bothers me)

    if (demoniacAmount != 0) {
        demoniac = new Demoniac(nameList.get(listIndex));
        listIndex++;
    } 
    
    if (guardAmount != 0) {
        guard = new Guard(nameList.get(listIndex));
        listIndex++;
    }