Welcome to the Treehouse Community

The Treehouse Community is a meeting place for developers, designers, and programmers of all backgrounds and skill levels to get support. Collaborate here on code errors or bugs that you need feedback on, or asking for an extra set of eyes on your latest project. Join thousands of Treehouse students and alumni in the community today. (Note: Only Treehouse students can comment or ask questions, but non-students are welcome to browse our conversations.)

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and a supportive community. Start your free trial today.

Java Local Development Environments Advanced Tooling Teamwork

naga bonar
naga bonar
3,338 Points

Please help, I got error like this "Exception in thread "main" java.lang.OutOfMemoryError: Java heap space"

My code runs normally in local (IntelliJ IDE) but when i posted it into the exercise, i got error like this "Exception in thread "main" java.lang.OutOfMemoryError: Java heap space".

I search that error in google, it refer to memory leak. I have no idea how to find the root cause. Anybody knows where the root cause is? Thanks before hand.

Below are my codes: Main.java

package com.teamtreehouse;

import java.util.Arrays;
import java.util.List;

public class Main {

    public static void main(String[] args) {
    // write your code here
        // TODO:csd - Instantiate a new Prompter object and prompt for the story template
        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);
        // TODO:csd - Use the prompter object to have it do the prompting, censoring and outputting.  Call Prompter.run
        prompter.run(tmpl);
        /*List<String> fakeResults = Arrays.asList(
                "friend",
                "talented",
                "java programmer",
                "high five");*/
        // TODO:csd - This should really happen in the Prompter.run method, let's get these implemetation details out of the main method
        /*String results = tmpl.render(fakeResults);
        System.out.printf("Your TreeStory:%n%n%s", results);*/

    }
}

Prompter.java

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);
        }
        // TODO:csd - Print out the results that were gathered here by rendering the template
        System.out.println(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 {
        // TODO:csd - Prompt the user for the response to the phrase, make sure the word is censored, loop until you get a good response.
        String userInput;
        System.out.printf("Please input a %s: %n", phrase);
        userInput = mReader.readLine();

        while(userInput == null || (mCensoredWords.contains(userInput))){
            System.out.printf("Please input a NICE %s: %n", phrase);
            userInput = mReader.readLine();
        }
        return userInput.trim();
    }
}

Template.java

package com.teamtreehouse;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class Template {
    /**
     * The string format that is waiting to receive values
     */
    private String mCompiled;
    private List<String> mPlaceholders;

    /**
     * @param text A template with double underscored surrounded placeholders. eg: Hello __name__!
     */
    public Template(String text) {
        // Match on double underscore surrounded words, like __name__ or __proper noun__
        Pattern pattern = Pattern.compile("__([^__]+)__");
        Matcher matcher = pattern.matcher(text);
        mPlaceholders = new ArrayList<String>();
        while (matcher.find()) {
            String label = matcher.group(1);
            mPlaceholders.add(label);
        }
        mCompiled = matcher.replaceAll("%s");
    }


    /**
     * @return Ordered names of placeholders in the template
     */
    public List<String> getPlaceHolders() {
        return mPlaceholders;
    }


    /**
     * Given a list of values, replaces the fill in the blanks in order.
     *
     * @param values The replacements for the fill in the blank
     * @return The filled out TreeStory
     */
    public String render(List<String> values) {
        // String.format accepts the templates and Object... (a variable amount of objects)
        return String.format(mCompiled, values.toArray());
    }
}

2 Answers

Alexander Nikiforov
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Alexander Nikiforov
Java Web Development Techdegree Graduate 22,161 Points

Hi,

I believe that the error exists, but in order to pass the challenge you have to do all Craigs TODOs properly.

Below I provide you how your Main class should look like, so that you can fill out the missing methods in Prompter your self.

I. You've done // TODO:csd - Print out the results that were gathered here by rendering the template correct, great job!

II. // TODO:csd - Prompt the user for the response to the phrase, make sure the word is censored, loop until you get a good response. is done incorrectly. Why?

Because you return trimmed input: return userInput.trim();

You cannot return trimmed input, because you change your user input, if user types "Alex", your program will return "alex", which is not correct.

III. I will give you sudo code with how your Main class should look like:

public class Main {

    public static void main(String[] args) {
    // write your code here
        // TODO:csd - Instantiate a new Prompter object and prompt for the story template
        Prompter prompter = new Prompter(); // great job ! this is correct

         // This one is wrong, because TODO clearly says, "prompt for story template",
        // which means implement Prompter.promptForStory() method that returns Story
        // String story = "Thanks __name__ for helping me out.  You are really a __adjective__ __noun__ and I owe you a __noun__."; //
        // So it should be like this:
        String story = prompter.promptForStory(); 
       // implement the method in Prompter. All it does - it prompts user for story, very simple, very easy. 
       // I'm sure you can do it. You've got this

        Template tmpl = new Template(story); // correct : will work
        // TODO:csd - Use the prompter object to have it do the prompting, censoring and outputting.  Call Prompter.run
        prompter.run(tmpl); // correct : will work

         // this TODO you've done correctly in Prompter.run() method! Great job! :)
        // TODO:csd - This should really happen in the Prompter.run method, let's get these implemetation details out of the main method
        /*String results = tmpl.render(fakeResults);
        System.out.printf("Your TreeStory:%n%n%s", results);*/


    }
}

Post back the refactored code, so that I can take a look. Good Luck! You've got this :)

naga bonar
naga bonar
3,338 Points

Hi Alexander Nikiforov,

I tried like what you've advised. i change my code into like below: Main.java

package com.teamtreehouse;

import java.util.Arrays;
import java.util.List;

public class Main {

    public static void main(String[] args) {
        Prompter prompter = new Prompter();
        String story = prompter.promptForStory();
        Template tmpl = new Template(story);
        prompter.run(tmpl);
    }
}

Prompter.java

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);
        }
        System.out.println(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 userInput;
        System.out.printf("Please input a %s: %n", phrase);
        userInput = mReader.readLine();

        while(userInput == null || (mCensoredWords.contains(userInput))){
            System.out.printf("Please input a NICE %s: %n", phrase);
            userInput = mReader.readLine();
        }
        return userInput;
    }

    public String promptForStory() {
        String story = "Thanks __name__ for helping me out.  You are really a __adjective__ __noun__ and I owe you a __noun__.";
        return story;
    }
}

and the template.java still the same. But i still got error like below:

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:76)
    at com.teamtreehouse.Prompter.promptForWords(Prompter.java:57)
    at com.teamtreehouse.Prompter.run(Prompter.java:38)
    at com.teamtreehouse.Main.main(Main.java:12)
    at JavaTester.run(JavaTester.java:77)
    at JavaTester.main(JavaTester.java:39)

Please help me find out again. thanks a lot for your support.

Alexander Nikiforov
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Alexander Nikiforov
Java Web Development Techdegree Graduate 22,161 Points

Yeah well. Code looks good except for that method promptForStory. I guess I'll just write how it should look like. You've spent enough with that problem.

In your method all you do is to define String and print it on your own.

However what you have to do is to actually prompt user for input

Here is code:

    public String promptForStory() {
        // define empty Story string so that it will be available
        // inside and outside try...catch block
        String story = ""; 

        // make try ... catch block, because mReader.readline() 
        // throws IOException
        try {
          // prompt user for input and 
          // set String story to user input
          story = mReader.readLine();

        } catch (IOException ioe) {
            // just print exception and exit
            ioe.printStackTrace();
            System.exit(0);
        }
        // return user story: "My name is __name__"
        return story;
    }

Should work. I pasted your code, changed only this method of yours and it worked.

Let me know if it worked for you, and if you understand what is going on in this promptForStory method

Jose Aguirre
Jose Aguirre
8,145 Points

I just ran into the same problem. Thank you Alexander.

Doli Harahap
Doli Harahap
6,246 Points

I have same problem. It can be run correctly in Intellij, but got OOM in the challenge.