Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Java Local Development Environments Advanced Tooling Finishing TreeStory

Patrick Allwood
Patrick Allwood
7,463 Points

java.lang.NullPointerException

My code runs perfectly on my IDE but continues to throw a null pointer exception where ever I compare strings on the code challenge page. I need to compare strings to see if the user would like another go, although I also compare user input to make sure they have entered something. Any ideas?

package com.teamtreehouse;

import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader;

public class Main {

public static void main(String[] args) {
// write your code here
    Prompter prompter = new Prompter();
    BufferedReader yesNoReader = new BufferedReader(new InputStreamReader(System.in));
    String yesNo = "no";
    String story = "Thanks __name__ for helping me out.  You are really a __adjective__ __noun__ and I owe you a __noun__.";
    Template tmpl = new Template(story);

    do{
        prompter.run(tmpl);
        System.out.printf("%n%nWould you like to have another go?  ");
        try {
            yesNo = yesNoReader.readLine();

        } catch (IOException e) {
            System.out.println("There was a problem with your answer");
            e.printStackTrace();
            System.exit(0);
        }
    }while(yesNo.compareToIgnoreCase("yes") == 0);
}

}

package com.teamtreehouse;

import java.io.*; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set;

public class Prompter { private BufferedReader mReader; private Set<String> mCensoredWords;

public Prompter() {
    mReader = new BufferedReader(new InputStreamReader(System.in));
    loadCensoredWords();
}

private void loadCensoredWords() {
    mCensoredWords = new HashSet<String>();
    Path file = Paths.get("resources", "censored_words.txt");
    List<String> words = null;
    try {
        words = Files.readAllLines(file);
    } catch (IOException e) {
        System.out.println("Couldn't load censored words");
        e.printStackTrace();
    }
    mCensoredWords.addAll(words);
}

public void run(Template tmpl) {
    List<String> results = null;

    try {
        results = promptForWords(tmpl);
    } catch (IOException e) {
        System.out.println("There was a problem prompting for words");
        e.printStackTrace();
        System.exit(0);
    }
    //Print out the results that were gathered here by rendering the template
    System.out.printf("Your TreeStory:%n%n%s", tmpl.render(results));
}

/**
 * Prompts user for each of the blanks
 *
 * @param tmpl The compiled template
 * @return
 * @throws IOException
 */
public List<String> promptForWords(Template tmpl) throws IOException {
    List<String> words = new ArrayList<String>();
    for (String phrase : tmpl.getPlaceHolders()) {
        String word = promptForWord(phrase);
        words.add(word);
    }
    return words;
}


/**
 * Prompts the user for the answer to the fill in the blank.  Value is guaranteed to be not in the censored words list.
 *
 * @param phrase The word that the user should be prompted.  eg: adjective, proper noun, name
 * @return What the user responded
 */
public String promptForWord(String phrase) throws IOException{

    String response = null;
   do {
        System.out.printf("Please give me a %s:  ", phrase);
        response = mReader.readLine();
    } while(mCensoredWords.contains(response) || response.isEmpty());

    return response;
}

}

Gavin Ralston
Gavin Ralston
28,770 Points

Please post the stack trace you get from the code challenge. "A" null pointer exception is a lot harder to find than, say, "THE" null pointer exception you're having. :)

Especially when the code is kind of not formatted right in your post :)

Patrick Allwood
Patrick Allwood
7,463 Points

Sorry, the null pointer exception refers to this line in main() class and is part of the do while loop:

           }while(yesNo.compareToIgnoreCase("yes") == 0);

The other null pointer exception refers to this line in the Prompter() class:

          } while(mCensoredWords.contains(response) || response.isEmpty());

If I remove the isEmpty() and the compareToIgnoreCase() from my code the exception goes away but the program of course fails to run as I cannot use the == comparator as that is not the result I am looking for. Is this an issue with the code challenge server or am I missing something about my code?

This is the stack trace:

Please give me a name: Please give me a adjective: Please give me a noun: Please give me a noun: Please give me a noun: Please give me a noun: java.lang.NullPointerException at com.teamtreehouse.Prompter.promptForWord(Prompter.java:78) at com.teamtreehouse.Prompter.promptForWords(Prompter.java:59) at com.teamtreehouse.Prompter.run(Prompter.java:39) at com.teamtreehouse.Main.main(Main.java:18) at JavaTester.run(JavaTester.java:77) at JavaTester.main(JavaTester.java:39)

Gavin Ralston
Gavin Ralston
28,770 Points

BufferedReader.readLine() Ignores line breaks/endings/returns, and also returns null if the end of the input is reached. Which means if someone entered nothing at all at your prompt, you'd be calling .compareToIgnoreCase() and .isEmpty() on null if the user or test just hit "Enter"

Which means it's possible you're pointing at a null value when you meant to be checking a char array (String) right?

What happens when you provide no input at the continue prompt or the word prompt? Does that behavior change if you initialize your response and yesNo String variables to an empty string?

Here's more discussion on null strings specifically related to calling isEmpty() on null.

Gavin Ralston
Gavin Ralston
28,770 Points

For example, this will work, but it's almost certainly not the right way to go about it:

In Main.java:

public static void main(String[] args) {

   // ...stuff...

    do{
        prompter.run(tmpl);
        System.out.printf("%n%nWould you like to have another go?  ");
        try {
            yesNo = yesNoReader.readLine();
            if (yesNo == null) {
              break;
            }

        } catch (IOException e) {
            System.out.println("There was a problem with your answer");
            e.printStackTrace();
            System.exit(0);
        }
    }while(yesNo.compareToIgnoreCase("yes") == 0);
}

In Prompter:

public String promptForWord(String phrase) throws IOException{

    String response = "";
   do {
        System.out.printf("Please give me a %s:  ", phrase);
        response = mReader.readLine();
        if (response == null) {
          break;
        }
    } while( mCensoredWords.contains(response) || response.isEmpty());

    return response;
}

You'll at least progress to the point where you'll see another issue with the project, but it's not a compiler error.

6 Answers

Gavin Ralston
Gavin Ralston
28,770 Points

After all the other stuff with the null values in the prompter and all that...I got to thinking about the response I got back from the challenge when I worked around the null values you kept getting. It kept coming back with no compiler errors, but it did ask you if you'd prompted the user for a new template String.

What if the reason you're getting a null value at the prompter is because he's testing a new string template with a different number of placeholders?

One of the errors you got was that it seemed to keep prompting the "user" (or the test code) for more words, and you got back a null response. This is to be expected if a readLine() is run on a stream that has reached its end.

One test, though, might assert that there are three placeholders to plug into a new template, but the hard-coded template string you have there is going to prompt for four -- every time.

Does your program prompt the user for a new template string so the test can customize it and run a test based on that? Or are you always using the default?

All I'm currently seeing is that you're doing prompter.run() on a single story String.

String story = "Thanks __name__ for helping me out. " +  
                        "You are really a __adjective__ __noun__ and I owe you a __noun__.";
Template tmpl = new Template(story);
    prompter.run(tmpl);

But step one is: The user is prompted for a new string template (the one with the double underscores in it)

Any chance you're not letting the test try out different template strings?

Craig Dennis
STAFF
Craig Dennis
Treehouse Teacher

Also, you might be triggering something weird with the way I am reading your output and providing your program input in the code challenge.

Why don't you try putting the loop in the Prompter.run method and not create another reader object and see if that does it for you.

Sorry for the weird environment :/

Gavin Ralston
Gavin Ralston
28,770 Points

It'd be cool to get an idea of how the input is provided in the test to see if there's a line terminating character (or EOF, since it looks like promptForWord() went through a few placeholders just fine before the trouble) that somehow gets readLine to return null in this test.

Because learning. :)

Patrick Allwood
Patrick Allwood
7,463 Points

Thanks Gavin, Yes you are right. I have deleted that one from Main. Now just using the one in Prompter. Main is currently:

package com.teamtreehouse;

public class Main {

public static void main(String[] args) {
    // write your code here
    Prompter prompter = new Prompter();
    String story = "Thanks __name__ for helping me out.  
                You are really a __adjective__ __noun__ and I owe you a __noun__.";
    Template tmpl = new Template(story);
    prompter.run(tmpl);

}

}

I believe the "no" at the end of: first prompt second prompt PASS_1 PASS_2 no, is the result of missing a null passed to the promptForAWord function:

public String promptForWord(String phrase) throws IOException {

    String response = "";
    do {
        System.out.printf("Please give me a %s:  ", phrase);
        response = mReader.readLine();
        if(response == null || response.isEmpty()){
            response = "noAnswer";
        }

    } while (mCensoredWords.contains(response) || response.compareToIgnoreCase("noAnswer") == 0);

    return response;
}

As such I am trying to write code that fits, although the above attempt throws this:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOf(Arrays.java:3236) at java.io.ByteArrayOutputStream.grow(ByteArrayOutputStream.java:118) at java.io.ByteArrayOutputStream.ensureCapacity(ByteArrayOutputStream.java:93) at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:153) at java.io.PrintStream.write(PrintStream.java:480) at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221) at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291) at sun.nio.cs.StreamEncoder.flushBuffer(StreamEncoder.java:104) at java.io.OutputStreamWriter.flushBuffer(OutputStreamWriter.java:185) at java.io.PrintStream.write(PrintStream.java:527) at java.io.PrintStream.print(PrintStream.java:669) at java.io.PrintStream.append(PrintStream.java:1065) at java.io.PrintStream.append(PrintStream.java:57) at java.util.Formatter$FixedString.print(Formatter.java:2595) at java.util.Formatter.format(Formatter.java:2508) at java.io.PrintStream.format(PrintStream.java:970) at java.io.PrintStream.printf(PrintStream.java:871) at com.teamtreehouse.Prompter.promptForWord(Prompter.java:97) at com.teamtreehouse.Prompter.promptForWords(Prompter.java:80) at com.teamtreehouse.Prompter.run(Prompter.java:44) at com.teamtreehouse.Main.main(Main.java:10) at JavaTester.run(JavaTester.java:77) at JavaTester.main(JavaTester.java:39)

What have I done?????

Gavin Ralston
Gavin Ralston
28,770 Points

What you've done is gone into an infinite loop, because response will eventually just be null when the test gets to the end of its input (seems to be around the fourth or fifth word the test wants to give you)

So the heap got blown out as you just infinitely prompted for more words when the test didn't want to give you any.

I wish I still had my code from the challenge, it passed alright.

I posted another answer to break comment chain up. Hope it helps.

Patrick Allwood
Patrick Allwood
7,463 Points

The pseudo tests do no match what is requested by the challenge:

This is essentially what I am testing

  1. The user is prompted for a new string template (the one with the double underscores in it).

a. The prompter class has a new method that prompts for the story template, and that method is called.

  1. The user is then prompted for each word that has been double underscored.

a. The answer is checked to see if it is contained in the censored words. User is continually prompted until they enter a valid word

  1. The user is presented with the completed story

Not happy!!!!!!

Patrick Allwood
Patrick Allwood
7,463 Points

Thanks for getting back to me Gavin and Craig. I tried changing my code to set the response to "no" if the response = null and that seems to have cleared the null exception.

if (response == null) { response = "no"; }

However, I was then given another fault, or rather was asked:

             "Did you prompt the user for a new story (1)? I see the original prompt".

So I then tried what Craig suggested and placed my loop in the run() function and recieved the same message and the following output:

Please give me a name: Please give me a adjective: Please give me a noun: Please give me a noun: Please give me a noun: Please give me a noun: Your TreeStory:

Thanks Testing first prompt and then second prompt for helping me out. You are really a PASS_1 PASS_2 and I owe you a no.

Would you like to try again?

It looks like the no was passed early? Is that possible?

My changed Main class:

package com.teamtreehouse;

import java.io.BufferedReader; import java.io.InputStreamReader;

public class Main {

public static void main(String[] args) {
    // write your code here
    Prompter prompter = new Prompter();
    BufferedReader yesNoReader = new BufferedReader(new InputStreamReader(System.in));
    String story = "Thanks __name__ for helping me out.  You are really a __adjective__ __noun__ and I owe you a __noun__.";
    Template tmpl = new Template(story);
    prompter.run(tmpl);

}

}

My changed Prompter() class:

package com.teamtreehouse;

import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set;

public class Prompter { private BufferedReader mReader; private Set<String> mCensoredWords;

public Prompter() {
    mReader = new BufferedReader(new InputStreamReader(System.in));
    loadCensoredWords();
}

private void loadCensoredWords() {
    mCensoredWords = new HashSet<String>();
    Path file = Paths.get("resources", "censored_words.txt");
    List<String> words = null;
    try {
        words = Files.readAllLines(file);
    } catch (IOException e) {
        System.out.println("Couldn't load censored words");
        e.printStackTrace();
    }
    mCensoredWords.addAll(words);
}

public void run(Template tmpl) {
    List<String> results = null;
    String response = null;

    do {

        try {
            results = promptForWords(tmpl);
        } catch (IOException e) {
            System.out.println("There was a problem prompting for words");
            e.printStackTrace();
            System.exit(0);
        }
        //Print out the results that were gathered here by rendering the template
        System.out.printf("Your TreeStory:%n%n%s", tmpl.render(results));
        //See if player would like another go
        System.out.println("\n\nWould you like to try again?  ");
        try {
            response = mReader.readLine();
            if (response == null) {
                response = "no";
            }
        } catch (IOException e) {
            System.out.println("There was a problem with your answer.");
            e.printStackTrace();
            System.exit(0);
        }

    } while (response.compareToIgnoreCase("yes") == 0);

}

/**
 * Prompts user for each of the blanks
 *
 * @param tmpl The compiled template
 * @return
 * @throws IOException
 */
public List<String> promptForWords(Template tmpl) throws IOException {
    List<String> words = new ArrayList<String>();
    for (String phrase : tmpl.getPlaceHolders()) {
        String word = promptForWord(phrase);
        words.add(word);
    }
    return words;
}


/**
 * Prompts the user for the answer to the fill in the blank.  Value is guaranteed to be not in the censored words list.
 *
 * @param phrase The word that the user should be prompted.  eg: adjective, proper noun, name
 * @return What the user responded
 */
public String promptForWord(String phrase) throws IOException {

    String response = null;
    do {
        System.out.printf("Please give me a %s:  ", phrase);
        response = mReader.readLine();
        if (response == null) {
            response = "no";
        }
    } while (mCensoredWords.contains(response));

    return response;
}

}

This does work in my IDE :)

Gavin Ralston
Gavin Ralston
28,770 Points

Well one of your readers is being fed some data that is probably meant to be used in another way in the test. Look at the names:

first prompt second prompt PASS_1 PASS_2 no

Craig mentioned just using one BufferedReader instead of two to see if that didn't clear it up.

At this point, since everything's more or less in the Prompter class, and at least in the main method I don't see you using it at all... why not just get rid of the first one that you create in Main altogether?

Patrick Allwood
Patrick Allwood
7,463 Points

Gavin you are the man!!! I don't know how I would have done without you. Thank you, thank you, thank you. I missed the new template thing completely. Just should have read the requirements. Cheers :)

Gavin Ralston
Gavin Ralston
28,770 Points

It happens. Glad we could work it out. :)