-2

I keep getting a null pointer exception and I can't seem to figure out why. I'm running some tests and that is when I get the null pointer exception, however, when I run it from Pangrams main(), I get no problems whatsoever. I've included the code, tests and stack trace below. Any help would be greatly appreciated and thanks in advance!

import java.util.Map;
import java.util.TreeMap;

public class Pangrams {
    private static TreeMap<Character, Integer> letterCount;

    public static void main(String[] args) {
        Pangrams pan = new Pangrams();
        System.out.println(pan.isPangram("the quick brown fox jumps over the lazy dog"));
        pan.getLetterCount();
    }

    public Pangrams() {
        letterCount = new TreeMap<>();
        populateMap();
    }

    public static boolean isPangram(String text) {

        if(text.length() < 26) return false;

        addToMap(text);

        for(Map.Entry<Character, Integer> entry : letterCount.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
            if(!(entry.getValue() >= 1)) {
                return false;
            }
        }

        return true;
    }

    public static void populateMap() {
        for(char x = 'a'; x <= 'z'; x++) {
            letterCount.put(Character.valueOf(x), 0);
        }
    }

    public static void addToMap(String text) {
        char[] textArray = text.toLowerCase().replace(" ", "").toCharArray();
        // System.out.println(textArray.length);

        for(char letter : textArray) {
            if(letterCount.containsKey(letter)) {
                int count = letterCount.get(letter);

                letterCount.put(letter, ++count);
                System.out.println(letterCount.get(letter));
            }
            else if(!Character.isWhitespace(letter)) {
                letterCount.put(letter, 1);
            }
        }
    }

    public static void getLetterCount() {
        for(Map.Entry<Character, Integer> entry : letterCount.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
    }
}

Here are the tests:

import org.junit.Test;

import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;

public class PangramTest {

    @Test
    public void emptySentence() {
        assertFalse(Pangrams.isPangram(""));
    }

    @Test
    public void testLowercasePangram() {
        assertTrue(Pangrams.isPangram("the quick brown fox jumps over the lazy dog"));
    }

    @Test
    public void missingCharacterX() {
        assertFalse(Pangrams.isPangram("a quick movement of the enemy will jeopardize five gunboats"));
    }

    @Test
    public void mixedCaseAndPunctuation() {
        assertTrue(Pangrams.isPangram("\"Five quacking Zephyrs jolt my wax bed.\""));
    }

    @Test
    public void nonAsciiCharacters() {
        assertTrue(Pangrams.isPangram("Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich."));
    }

}

Here is the full stack trace:

java.lang.NullPointerException
    at Pangrams.addToMap(Pangrams.java:47)
    at Pangrams.isPangram(Pangrams.java:24)
    at PangramTest.testLowercasePangram(PangramTest.java:15)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:117)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:253)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
  • 3
    The `Pangrams` constructor is never called, thus `letterCount` is never instantiated. – Jonny Henly Aug 03 '16 at 18:39
  • 1
    Side note: you only make your **core** methods public; those that you you want to be called from the outside. But well, now that most of your methods are public: consider writing tests for them, too. You see, if your "whole" logic is so complicated that even your tests don't help you figuring bugs ... then test smaller units (like your other methods) and see how well they work. The other thing: you are mixing static and non-static stuff. Avoid doing that. You rarely want a static field to be manipulated by non-static methods! – GhostCat Aug 03 '16 at 18:40
  • 1
    Pangrams.isPangram you are calling it as static , so @JonnyHenly said the TreeMap letterCount is not instantiated – Gowrav Aug 03 '16 at 18:40
  • 2
    More importantly, you're ignoring all the previous similar NPE posts, the ones that show you how to debug this sort of thing yourself. The heuristic for NullPointerExceptions is almost always the same: You should critically read your exception's stacktrace to find the line of code at fault, the line that throws the exception, and then inspect that line carefully, find out which variable is null, and then trace back into your code to see why. You will run into these again and again, trust me. – Hovercraft Full Of Eels Aug 03 '16 at 18:42
  • You don't even indicate to us which line is the one that is failing. If you had read the previous canonical questions/answers you'd have known to at least post this with your question. – Hovercraft Full Of Eels Aug 03 '16 at 18:44
  • Right on, thanks for the help guys. I was able to get the tests to pass. – Piara Sandhu Aug 03 '16 at 19:10

1 Answers1

-1

Ok maybe I didnt explain myself clearly on this answer. The thing you were doing wrong was calling a static method on your class. Calling static methods doesn't instantiate your constructor, thats where you were initializing your map.

So the NULL pointer exception was throwing because you were accessing a map which had never been instantiated at all.

Looking further I dont think you need your map to be static in this context, so my code below holds the map in the object's state and refactored your test case to use the object state to call you methods, since your methods are no longer static and they are tied to your object state.

import java.util.Map; import java.util.TreeMap;

public class Pangrams
{
    private final TreeMap<Character, Integer> letterCount;

    public static void main(String[] args)
    {
        Pangrams pan = new Pangrams();
        System.out.println(pan.isPangram("the quick brown fox jumps over the lazy dog"));
        pan.getLetterCount();
    }

    public Pangrams()
    {
        letterCount = new TreeMap<Character, Integer>();
        populateMap();
    }

    public boolean isPangram(String text)
    {

        if(text.length() < 26)
        {
            return false;
        }

        addToMap(text);

        for(Map.Entry<Character, Integer> entry : letterCount.entrySet())
        {
            System.out.println(entry.getKey() + ": " + entry.getValue());
            if(!(entry.getValue() >= 1))
            {
                return false;
            }
        }

        return true;
    }

    public void populateMap()
    {
        for(char x = 'a'; x <= 'z'; x++)
        {
            letterCount.put(Character.valueOf(x), 0);
        }
    }

    public void addToMap(String text)
    {
        char[] textArray = text.toLowerCase().replace(" ", "").toCharArray();
        // System.out.println(textArray.length);

        for(char letter : textArray)
        {
            if(letterCount.containsKey(letter))
            {
                int count = letterCount.get(letter);

                letterCount.put(letter, ++count);
                System.out.println(letterCount.get(letter));
            }
            else if(!Character.isWhitespace(letter))
            {
                letterCount.put(letter, 1);
            }
        }
    }

    public void getLetterCount()
    {
        for(Map.Entry<Character, Integer> entry : letterCount.entrySet())
        {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
    }
}

Test:

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import org.junit.Test;

public class PangramTest
{
    Pangrams pan = new Pangrams();

    @Test
    public void emptySentence()
    {
        assertFalse(pan.isPangram(""));
    }

    @Test
    public void testLowercasePangram()
    {
        assertTrue(pan.isPangram("the quick brown fox jumps over the lazy dog"));
    }

    @Test
    public void missingCharacterX()
    {
        assertFalse(pan.isPangram("a quick movement of the enemy will jeopardize five gunboats"));
    }

    @Test
    public void mixedCaseAndPunctuation()
    {
        assertTrue(pan.isPangram("\"Five quacking Zephyrs jolt my wax bed.\""));
    }

    @Test
    public void nonAsciiCharacters()
    {
        assertTrue(pan.isPangram("Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich."));
    }

}
Gowrav
  • 289
  • 1
  • 4
  • 20
  • Superbad: just a truck load of code, and no explanations at all. Seriously: thats **bad**. – GhostCat Aug 03 '16 at 19:11
  • @GhostCat i explained myself in the comments sections, I thought the user understood by now. I explained what is wrong and the way of using static doesnt instantiate the constructor and I gave the fixed code here in the aswers section – Gowrav Aug 03 '16 at 19:13
  • Answers always stand for themselves. You **never** expect people to first read all the comments to then figure how your answer relates to that. So: take the content of your comments; and put them into the answer; then delete the comments. It is as easy as that. – GhostCat Aug 03 '16 at 19:20
  • @GhostCat : true, learnt my mistake. thanks for pointing it out – Gowrav Aug 03 '16 at 19:22