0

In BlueJ and Eclipse I get a nullpointer exception when checking for String-equality.

Here's my code:

import java.util.Set;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.Iterator;

/**
 * Class Room - a room in an adventure game.
 *
 * This class is part of the "World of Zuul" application. 
 * "World of Zuul" is a very simple, text based adventure game.  
 *
 * A "Room" represents one location in the scenery of the game.  It is 
 * connected to other rooms via exits.  For each existing exit, the room 
 * stores a reference to the neighboring room.
 *
 * @author  Michael Kölling and David J. Barnes
 * @version 2016.02.29
 */

public class Room
{
    private String description;
    private String itemDescription;
    private HashMap<String, Room> exits;        // stores exits of this room.
    private ArrayList<Item> items;

    /**
     * Create a room described "description". Initially, it has
     * no exits. "description" is something like "a kitchen" or
     * "an open court yard".
     * @param description The room's description.
     */
    public Room(String description)
    {
        this.description = description;
        this.itemDescription = "This room contains: ";
        exits = new HashMap<>();
        items = new ArrayList<Item>();
    }

    public Room(String description, Item item)
    {
        items = new ArrayList<Item>();
        this.description = description;
        addItem(item);
        this.itemDescription = "This room contains: " + item.getLongDescription() ;
        exits = new HashMap<>();
    }
    /**
     * Define an exit from this room.
     * @param direction The direction of the exit.
     * @param neighbor  The room to which the exit leads.
     */
    public void setExit(String direction, Room neighbor)
    {
        exits.put(direction, neighbor);
    }

    public void addItem(Item item)
    {
        items.add(item);
        System.out.println(itemDescription.equals("This room contains: "));
        this.itemDescription = this.itemDescription + /*(this.itemDescription.equals("This room contains: ") ?
        "" : ", ")*/ ", " + item.getLongDescription();
    }

    public void removeItem(String shortItemDescription){
        int i= 0;
        Iterator<Item> it = items.iterator();
        while(it.hasNext()){
            if (it.next().getShortDescription().equals(shortItemDescription)){
                it.remove();
                i++;
            }
            else
                i++;
        }
    }

    public  ArrayList<Item> getItems(){
        return items;
    }

    /**
     * @return The short description of the room
     * (the one that was defined in the constructor).
     */
    public String getShortDescription()
    {
        return description;
    }

    /**
     * Return a description of the room in the form:
     *     You are in the kitchen.
     *     Exits: north west
     * @return A long description of this room
     */
    public String getLongDescription()
    {
        return "You are " + description + ".\n" + (itemDescription.equals("This room contains: ") ?
                "This room is empty" : itemDescription) + ".\n" + getExitString();
    }

    /**
     * Return a string describing the room's exits, for example
     * "Exits: north west".
     * @return Details of the room's exits.
     */
    private String getExitString()
    {
        String returnString = "Exits:";
        Set<String> keys = exits.keySet();
        for(String exit : keys) {
            returnString += " " + exit;
        }
        return returnString;
    }

    /**
     * Return the room that is reached if we go from this room in direction
     * "direction". If there is no room in that direction, return null.
     * @param direction The exit's direction.
     * @return The room in the given direction.
     */
    public Room getExit(String direction)
    {
        return exits.get(direction);
    }
}

In the method addItem(Item item) I get a nullpointer exception error when checking for the String comparison-method itemDescription.equals("This room contains: "), as well as in the System.out.println()-statement as in the outcommented ternary operator-test for itemDescription.equals("This room contains: ").

The strange thing is that the ternary operator in getLongDescription() functions fine.

Arty
  • 819
  • 3
  • 13
  • 24
Afrim124
  • 33
  • 2
  • 6
  • Use a debugger. Put a breakpoint on the line that fails. Check each of the references to see which is null. – Michael Mar 23 '18 at 10:13
  • `getLongDescription` is on a `item`, the exception is on `itemDescription` so there is "nothing" strange about this, those two are not related. Unless you need a value from that `item` .... `itemDescription` doesn't seems to be null (since instanciate in both constructor) but you need to debug this yourself or propose a [mcve]. – AxelH Mar 23 '18 at 10:14
  • Please check the order of instructions in your constructors. At least in one of them the method `addItem` is called before `this.itemDescription` is initialized – Stefan Freitag Mar 23 '18 at 10:20
  • Thanks a lot Stefan Freitag. That solved my problem completely! – Afrim124 Mar 23 '18 at 10:46

1 Answers1

1

If you build a Room instance with an Item. You call addItem before instantiating the itemDescription variable.

public Room(String description, Item item) 
{
    // ...
    addItem(item);
    this.itemDescription = "This room contains: " + item.getLongDescription() ;
    // ...
}

So in the method addItem, this.itemDescription is still null.

public void addItem(Item item)
{
    // ...
    System.out.println(itemDescription.equals("This room contains: ")); 
    // ...
}

And this breaks.

To correct the problem, call addItem after you instanciate itemDescription. Note that you don't need to add the item description since this is already done in the addItem method.

public Room(String description, Item item) 
{
    // ...
    this.itemDescription = "This room contains: ";
    addItem(item);
    // ...
}

You are going to regret that String itemDescription really fast !

Instead, create method getRoomDescription that will iterate the items list and generate that String itemDescription (using a StringBuilder) !

Something like

public String getRoomDescription(){
    StringBuilder sb = new StringBuilder("Rooms contains :");
    for(Item i : items){
         sb.append("\n".append(i.getLongDescription());
    }
    return sb.toString();
}

Editing the itemDescription variable is messy and is prone to problem (like you have encountered).


Last thing, the test you do with

itemDescription.equals("This room contains: ")

Should give you the same result as

items.size() == 0

But is easier to understand (no value in items list) and is less prone to mistake if you edit the way you want to print the description.

AxelH
  • 14,325
  • 2
  • 25
  • 55
  • This question is still a duplicate, but I had to mention the last part. The alternative is more interesting, cleaner and easier to maintain ! – AxelH Mar 23 '18 at 10:25
  • And you, too. Thanks a lot for the in-depth commenting. – Afrim124 Mar 23 '18 at 10:49