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);
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 a-z 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 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With