简体   繁体   中英

Why am I throwing a NullPointerException

So it's winter break for colleges, and I'm trying to stay sharp on my coding, so I'm just writing code for programs and algorithms we only talked about but never coded in class. Anyway, one I'm working on today is a program where you give the computer a scrambled word, and it outputs all the words (from the EnglishWordList file we are given) that can be made from those letters.

Anyway, here is the code I have so far for it:

import java.io.*;
import java.util.*;

public class ProdFinder {
    private HashMap<Character, Integer> prodFinder = new HashMap<Character, Integer>();
    private HashMap<Integer, LinkedList<String>> findWord = new HashMap<Integer,     LinkedList<String>>();

    private static final char[] letters =     {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r',
            's','t','u','v','w','x','y','z'};
    private static final int[] primes =     {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101}; 

    public ProdFinder() throws FileNotFoundException {
        for (int i = 0; i < letters.length; i++) {
            prodFinder.put(letters[i], primes[i]);
        }

        Scanner sc = new Scanner(new File("EnglishWordList.txt"));


        while (sc.hasNextLine()) {
            String str = sc.nextLine();
            int strProd = findProduct(str);

            if (findWord.containsKey(strProd)) {
                LinkedList<String> wordList = findWord.get(strProd);
                wordList.add(str);
                findWord.put(strProd, wordList);
            }
            else {
            LinkedList<String> wordList = new LinkedList<String>();
            wordList.add(str);
            findWord.put(strProd, wordList);
        }
    }

    sc.close();
}

public int findProduct(String x) {
    int product = 1;
    char[] str = x.toCharArray();

    for (Character val: str) {
        product = product*prodFinder.get(val);
    }

    return product;
}

public void descramble(String x) {
    int prod = findProduct(x);

    if (findWord.containsKey(prod)) {
        System.out.println("The words that can be formed from the letters in " + x + " are: " +
                            findWord.get(prod));
    }
    else {
        System.out.println("No words can be formed from the letters in " + x + ".");
    }
}

}

Now, the error originates at the line where I start putting all of the prime products of numbers into my HashMap (trying to map each prime product to a LinkedList of words whose letters multiply into that number.) Somehow this is throwing the exception, as when I comment out that section of code and just run the findProduct method, it works fine on any word I give it to output the product of the lettesr in prime form.

Any ideas on where the exception is coming from?

EDIT: Sorry, the stacktrace is as follows:

Exception in thread "main" java.lang.NullPointerException
at ProdFinder.findProduct(ProdFinder.java:44)
at ProdFinder.<init>(ProdFinder.java:22)
at Descramble.main(Descramble.java:7)

From what I can tell, the error originates when I try to call findProd on the str, at this line:

int strProd = findProduct(str);

The problem is ProdFinder.java:44 as the stack trace indicates which is

product = product*prodFinder.get(val);

The null pointer exception is the prodFinder does not have a product/value for val so it returns null which the program then attempts to multiply by product.

(anything * null) results in NullPointerException

The reason the prodFinder map does not have a value is probably because the word has some capital letter, special character or number when all that has been added to the map is lower case alphabetic characters

Java debugger is a great resource in problems like this. Use an IDE such as eclipse or netbeans and just place a breakpoint at line 44 to quickly find the culprit use case.

You're currently unboxing null values from your Map . This is why you result in a NullPointerException .

A brief primer on autoboxing : There are a set of objects which represent primitives; these are called "wrapper classes" or "boxed classes". They include every primitive with an associated class.

This allows you to use a primitive value inside of a generic collection, as generics will not work without objects.

An autoboxing conversion occurs when Java encounters an operation that would require the primitive value - namely, some form of arithmetic or unary operator ( +, -, *, /, ++, --, +, - ).

Boxing and unboxing conversion happens according to the specification . I would encourage you to read up on that, since there's a lot there to list, and I'd be repeating what's already been said.

The caveat to autoboxing is null . Remember that primitives have a fixed, finite value, and objects can either exist (with infinitely many values depending on the number of fields), or not exist, or is null . If you attempt to unbox a value that is null , then a NullPointerException occurs.

Now, as to why you're pulling back null from your Map : char[] str = x.toCharArray(); turns whatever x is into a character array, and you then look in your mapping for all lower case characters, and map them to a given prime value.

What happens if a character in x is upper case? What if it's a number? What if it's a special character? A space? A tab? Something that isn't a lowercase az letter? You don't find a value in the mapping, and it would return null .

This also serves as a bit of a warning - when dealing with boxed primitives, one must take great care that, when relying on autoboxing conversions, that they are not dealing with any null values or instances. This will lead to confusing NPEs (like this one) which may be tougher to track.

The only way I can imagine the following line is throwing an exception is that if val is not in prodFinder

product = product*prodFinder.get(val);

you might want to check the result of prodFinder.Get before you use it

Integer value = prodFinder.get(val);

if(val == null)
    //indicate that you have an error state?
else
    product *= val;

First of all you should learn how to use a debuger. If you cant you could help yourself with some System.out's

public int findProduct(String x) {
    int product = 1;
    char[] str = x.toCharArray();
    System.out.println("str " + str);
    for (Character val: str) {
        System.out.println("prodFinder " + prodFinder);
        System.out.println("val " + val);
        System.out.println("prodFinder.get(val) " + prodFinder.get(val));
        product = product*prodFinder.get(val);
    }
    return product;
}

For a File content like this:

Hello
World

The output is:

Cmd-$> java Descramble
str Hello
str [C@e80842
prodFinder {f=13, g=17, d=7, e=11, b=3, c=5, a=2, n=43, o=47, l=37 ...
val H
prodFinder.get(val) null
Exception in thread "main" java.lang.NullPointerException
        at ProdFinder.findProduct(Descramble.java:48)
        at ProdFinder.<init>(Descramble.java:23)
        at Descramble.main(Descramble.java:70)

as you can see, for the letter H the return value is null

There are no capital letters in your array letters , thus none in the Map!

The Exception happens on the line

product = product*prodFinder.get(val);

Here the jvm is trying to unbox the Integer returned by the map into a primitive int to perform the multiplication. But it is not possible because the map returns null

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM