Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

prostuff1

macrumors 65816
Original poster
Jul 29, 2005
1,482
18
Don't step into the kawoosh...
I will attach the code I have below. It is almost entirely done but i am getting a NullPointerException that is driving me nuts, and I can't figure out were it is coming from.

Help is greatly appreciated.

First code:
Code:
import java.util.Scanner;
import java.io.*;
import java.util.Random;
import java.util.Collection;

public class DistributionPlagiarist 
{
	public static void main(String[] args) throws IOException
	{
		Scanner keyboard = new Scanner(System.in);
		int keyLength=0, phraseLength=0, numberOfPhrases=0;
		String inputFileName="", keepReadingFromFile="", theFile="";
		FrequencyLibrary text = new DenseFrequencyLibrary();

		if(args.length != 4)
		{
			System.out.println("The command line arguments you entered do not match what is needed.  Please try again.");
			System.exit(0);
		}

		for(int count=0; count<args.length; count++)
		{
			keyLength = Integer.parseInt(args[0]);
			phraseLength = Integer.parseInt(args[1]);
			numberOfPhrases = Integer.parseInt(args[2]);
			inputFileName = args[3];

		}

		if(keyLength < 0)
		{
			while(keyLength < 0)
			{
				System.out.print("The length of the key (" + keyLength + ")" + " you entered is less than zero.\nPlease enter another key length: ");

				keyLength = keyboard.nextInt();
				System.out.println();
			}
		}
		if(phraseLength < 0)
		{
			while(phraseLength < 0)
			{
				System.out.print("The desired length of the phrase (" + phraseLength + ")" + " you entered is less than zero.\nPlease enter another phrase length: ");

				keyLength = keyboard.nextInt();
				System.out.println();
			}
		}
		if(numberOfPhrases <= 0)
		{
			while(numberOfPhrases <= 0)
			{
				System.out.print("The desired number of phrases (" + keyLength + ")" + " you entered is not applicable.\nPlease choose another number: ");

				keyLength = keyboard.nextInt();
				System.out.println();
			}
		}

		File file=new File(inputFileName);
		boolean exists = file.exists();
		if (exists == false) 
		{
			while(exists == false)
			{
				System.out.println("The file you are searching for does not exist.  Please place it in this programs directory.");
				System.out.print("Please re-enter the file name: ");

				inputFileName = keyboard.nextLine();

				file=new File(inputFileName);
				exists = file.exists();

			}
		}
		
		int count=keyLength, start=0, stop=0;
		FileReader freader = new FileReader(inputFileName);
		BufferedReader inputFile = new BufferedReader(freader);
		
		while(keepReadingFromFile != null)
		{
			keepReadingFromFile = inputFile.readLine();
			
			if(keepReadingFromFile == null)
			{
				break;
			}
			else
			{
				theFile = theFile + keepReadingFromFile;
			}			
		}

		while(count < theFile.length())
		{
			String name = theFile.substring(start, keyLength+stop);
			char singleCharacter = theFile.charAt(count);
			
			text.add(name, singleCharacter);
			
			start++;
			stop++;
			count++;
		}
		
		int countNumberOfPhrases=0;
		while(numberOfPhrases > 0)
		{
			countNumberOfPhrases++;
			String phrase = randomphrase(text, phraseLength, keyLength);

			System.out.println("Phrase " + countNumberOfPhrases + ":\n" + phrase);

			numberOfPhrases--;
		}

	}

	private static String randomphrase(FrequencyLibrary textLibrary, int phraseLengthToMake, int startLength)
	{
		String startString="";
		char characterToAdd=' ';
		startLength++;
		Random generator = new Random();
		int sizeOfLibrary=textLibrary.size()/2, randomInt = generator.nextInt(sizeOfLibrary+1), value=0;

		Collection<String> stringNames = textLibrary.makeStringCollection();

		for(String stringFromCollection : stringNames)
		{	        	
			if(randomInt == value)
			{
				startString = stringFromCollection;
			}
			value++;
		}

		String thePhrase = new String(startString);
		System.out.println("INITIAL START:" + startString + "TTTT");
		int substringStart=1;

		while(startLength < phraseLengthToMake)
		{
			characterToAdd = textLibrary.randomUniformChoose(startString);
			thePhrase = thePhrase + characterToAdd;
			System.out.println("CHARACTER:" + characterToAdd + "TTTT");
			System.out.println("PHRASE:" + thePhrase + "TTTT");
			startString = thePhrase.substring(substringStart, thePhrase.length());
			boolean answer = textLibrary.contains(startString);
			System.out.println(answer);
			System.out.println("NEW STRING:" + startString + "TTTT");
			startLength++;
			substringStart++;
		}

		return thePhrase;
	}
}


Second code:
Code:
import java.util.Collection;
import java.util.HashMap;


public class DenseFrequencyLibrary implements FrequencyLibrary
{
	private HashMap<String, MultiSetOfChar> bookTitleAndCharacterAndIntegerHashMap = new HashMap<String, MultiSetOfChar>();
	private MultiSetOfChar keyAndValuePairs = new DenseMultiSetOfChar();
	
	/**
	 * Creates a new DenseFrequencyLibrary with all the essential things clear;
	 */
	DenseFrequencyLibrary()
	{
		bookTitleAndCharacterAndIntegerHashMap.clear();
	}
	
	/**
	 * Input the value from the creation of the DensneMultiSetOfChar into a HashMap.  If the key
	 * already exists then the value associated with it is updated by one.
	 * 
	 * @param character a char to be used in forming the HashMap
	 * @return characterMap
	 */
	private HashMap<String, MultiSetOfChar> inputIntoMap(String name, char character)
	{
		if(!bookTitleAndCharacterAndIntegerHashMap.containsKey(name))
		{
			keyAndValuePairs = new DenseMultiSetOfChar(character);
			
		}
		else
		{
			keyAndValuePairs.add(character);

		}		

		this.bookTitleAndCharacterAndIntegerHashMap.put(name, keyAndValuePairs); //input character and value
		
		return bookTitleAndCharacterAndIntegerHashMap; //return the new HashMap
	}
	
	/**
	 * Returns the number of books in the library.
	 * 
	 * @return |b|, ie the number of books in b
	 */
    public int size()
    {
    	int numberOfBooks=bookTitleAndCharacterAndIntegerHashMap.size();
    	
    	return numberOfBooks;
    }
    
    /**
     * Searches the library for an occurrence of a given book
     * 
     * @param target the name of a book to be searched for in the library
     * @return true if and only if the argument is already a book title in the library.
     */
    public boolean contains(String target)
    {
    	boolean bookIsInLibrary=false;
    	
    	if(bookTitleAndCharacterAndIntegerHashMap.containsKey(target))
    	{
    		bookIsInLibrary = true;
    	}
    	
    	return bookIsInLibrary;
    }
    
    /**
     * Returns the MultiSetOfChar that represents the occurrences of the individual characters 
     * in the text of the book indicated by the argument. 
     * 
     * @param target
     * @return MultiSetOfChar
     */
    public MultiSetOfChar getFrequencies(String target)
    {  
    	MultiSetOfChar frequencyMultiSetOfChar = bookTitleAndCharacterAndIntegerHashMap.get(target);

    	return frequencyMultiSetOfChar;
    }
    /**
     * Modifies the character occurrences associated with name to include one more occurrence of element. 
     * 
     * @param name string of the name of the book
     * @param element character to add to the specified book
     */
    public void add(String name, char element)
    {
    	bookTitleAndCharacterAndIntegerHashMap = inputIntoMap(name, element);
    }
    
    /**
     * Modifies the character occurrences associated with name to include one less occurrence of element. 
     *     
     * @param name string of the name of the book
     * @param element character to be removed from the specified book
     * @return true if and only if the book is modified.
     */
    public boolean remove(String name, char element)
    {
    	boolean characterWasRemovedFromBook=false;


    	//if the target character is in the map then remove it
		if(bookTitleAndCharacterAndIntegerHashMap.containsKey(name))
		{
			MultiSetOfChar keyAndValuePairs = bookTitleAndCharacterAndIntegerHashMap.get(name);
			keyAndValuePairs.remove(element);
			
			characterWasRemovedFromBook = true; //set answer to true because the HashMap was changed
		}
		else //target does not exist in the HashMap
		{
			characterWasRemovedFromBook = false; //set answer to false because the HashMap was not changed
		}

    	return characterWasRemovedFromBook;
    }
    
    /**
     * Returns a random character, chosen from the same distribution as the characters appear in the book. 
     * For example, if 5% of the characters in "Alice in Wonderland" are an 'A', then this method should 
     * return an 'A' about 5% of the time.
     *
     * @param name string of the name of the book to search through and remove a character
     * @return true if and only if the argument is already a book title in the library.
     */
	public char randomUniformChoose(String name)
    {
        MultiSetOfChar keyAndValuePairs = bookTitleAndCharacterAndIntegerHashMap.get(name);
        
        char randomCharacter = keyAndValuePairs.randomUniformChoose();
       		
		return randomCharacter; //return the random character pulled out
    }
	
	public Collection<String> makeStringCollection()
	{
		Collection<String> stringCollection = bookTitleAndCharacterAndIntegerHashMap.keySet();
		
		return stringCollection;
	}
}

Third code:
Code:
import java.util.HashMap;
import java.util.Set;
import java.util.Collection;
import java.util.Random;

/**
 * DenseMultiSetOfChar implements MultiSetOfChar.
 * @mathmodel b is a finite multiset
 * 
 * @mathdef
 *  |b| is the cardinality of b
 *  ||c,b|| is the number of occurrences of element c in b
 *   
 * @author Kyle Hiltner
 *
 */
public class DenseMultiSetOfChar implements MultiSetOfChar
{
	private char characterInput=' ';
	private HashMap<Character, Integer> characterMap = new HashMap<Character, Integer>();
	
	/**
	 * Create a new DenseMultiSetOfChar with zero argument
	 */
	DenseMultiSetOfChar()
	{
		characterMap.clear(); //clear static HashMap
	}
	/**
	 * Create a new DenseMultiSetOfChar with the passed in value.
	 * 
	 * @param newChar character input to be added to the HashMap
	 */
	DenseMultiSetOfChar(char newChar)
	{
		this.characterInput = newChar; //set characterInput to the value passed in
		characterMap = inputIntoMap(this.characterInput); //call private procedure to add characterInput to HashMap
	}
	
	/**
	 * Input the value from the creation of the DensneMultiSetOfChar into a HashMap.  If the key
	 * already exists then the value associated with it is updated by one.
	 * 
	 * @param character a char to be used in forming the HashMap
	 * @return characterMap
	 */
	private HashMap<Character, Integer> inputIntoMap(char character)
	{		
		//if the character is not in the HashMap then add it with the starting value of 1
		if(!characterMap.containsKey(character))
		{
			characterMap.put(character, 1); //input character and value
		}
		else //character does exist
		{
			int value = characterMap.get(character); //get the value for the specified key
			value++; //increase the value so as to show that another character was added
			characterMap.put(character, value); //place the character and new value in the HashMap
		}
		
		return characterMap; //return the new HashMap
	}

	/**
	 * Returns the number of elements in this multiset (ie its cardinality).
	 * Note that since multisets can include duplicates, the cardinality may be
	 * larger than the number of distinct elements. Also, the total number of
	 * items in the multiset is bounded above by Integer.MAX_VALUE.
	 * 
	 * @return |b|, ie the cardinality of b
	 */
	public int getCardinality()
	{
		int totalElementsInMap=0;
		Collection<Integer> integerCollection = characterMap.values(); //create a collection for easy iteration
		
		//iterate through each value in the HashMap and compute the total number of elements in the HashMap
		for(Integer valueFromCollection : integerCollection)
		{
			totalElementsInMap = totalElementsInMap + valueFromCollection; //compute new value of total values
		}

		return totalElementsInMap; //return the final total value
	}
	
	/**
	 * Returns the number of occurrences of a given element in the multiset. A
	 * simple identity relating getElementCount and getCardinality is that the
	 * sum of getElementCount for each char is equal to the cardinality of the
	 * set.
	 * 
	 * @param target
	 *            char to be counted in the multiset
	 * @return ||target,b||, ie the number of occurrences of target in b
	 */
	public int getElementCount(char target)
	{
		int numberOfGivenCharacters=0; //set initial value 
		
		//if the HashMap contains the target character then numberOfGivenCharacters is set to the value
		if(characterMap.containsKey(target))
		{
			numberOfGivenCharacters = characterMap.get(target); //set numberOfGivenCharacters to the value assigned to the target character
		}
		
		return numberOfGivenCharacters; //return the value for the target character
	}
	
	/**
	 * Returns a set such that every element in the multiset is in the set (but
	 * no duplicates). The cardinality of the returned set must be less than or
	 * equal to |b|. The cardinality of the two are equal if and only if b
	 * contains no duplicate elements.
	 * 
	 * @return a set of Character, s, such that: <br />
	 *         (for all (Character)i in s : (char)i in b) and <br />
	 *         (for all (char)i in b : (Character)i in s)
	 */
	public Set<Character> getElementSet()
	{
		Set<Character> characterSet = characterMap.keySet(); //create a Set from the keys of characters in the HashMap	
		
		return characterSet; //return the character Set
	}
	
	/**
	 * Adds a single element to the multiset. This operation always increases
	 * the cardinality of the multiset by 1, assuming that the maximum capacity
	 * of Integer.MAX_VALUE has not been reached.
	 * 
	 * @param item
	 *            the char to be added to b
	 * @requires |b| < Integer.MAX_VALUE
	 * @alters b
	 * @ensures b = #b union {item}
	 */
	public void add(char item)
	{
		characterMap = inputIntoMap(item); //call the private method to add new character (item) to the HashMap
	}
	
	/**
	 * Removes the target, if it is present in the multiset. The method returns
	 * true if and only if it changes the multiset.
	 * 
	 * @param target
	 *            the char to be removed
	 * @alters b
	 * @ensures (target not in #b) ==> (b = #b) <br />
	 *          (target in #b) ==> (b union {target} = #b)
	 * @return target in #b
	 */
	public boolean remove(char target)
	{
		boolean answer=false; //set initial value to false
		
		//if the target character is in the map then remove it
		if(characterMap.containsKey(target))
		{
			int value = characterMap.get(target); //find the value associated with the target character
			
			//if the value is 1 call remove from the HashMap and remove key and value
			if(value == 1)
			{
				characterMap.remove(target); //remove key and value from the HashMap
			}
			else //value is greater than 1
			{
				value--; //decrease value to show removal
				characterMap.put(target, value); //replace target character with new value back into the HashMap
			}
			
			answer = true; //set answer to true because the HashMap was changed
		}
		else //target does not exist in the HashMap
		{
			answer = false; //set answer to false because the HashMap was not changed
		}
	
		return answer; //return answer
	}
	
	/**
	 * Returns a char chosen randomly based on the contents of the multiset.
	 * This operation does not remove the char from the multiset or change the
	 * multiset in any way. In particular, the cardinality of the multiset is
	 * the same before and after this method.
	 * 
	 * <p>
	 * Characters should be returned with a random distribution equal to the
	 * distribution of characters in the multiset. That is, for a character that
	 * appears N times in a multiset of cardinality M, the probability of that
	 * character being returned is N / M. For example, a multiset that contains
	 * only the character 'a', possibly many times, would always result in an
	 * 'a' being generated. On the other hand, a multiset with an equal number
	 * of 'a' and 'b' elements would return an 'a' approximately half the time
	 * and a 'b' the other half.
	 * 
	 * @requires |b| >= 1
	 * @return char c with probability p, where: <br />
	 *         p = ||c,b|| / |b|
	 */
	public char randomUniformChoose()
	{ 
		char randomCharacter=' ';
		Random generator = new Random();
		
		int totalElementsInMap=0;
		Collection<Integer> integerCollection = characterMap.values(); //create a collection for easy iteration
		
		//iterate through each value in the HashMap and compute the total number of elements in the HashMap.  
		//Do this in case a remove call was made
		for(Integer valueFromCollection : integerCollection)
		{
			totalElementsInMap = totalElementsInMap + valueFromCollection; //compute new value of total values
		}
		
		int randomInt = generator.nextInt(totalElementsInMap+1), lowerValue=0, upperValue=0;
		
		Collection<Character> keyCollection = characterMap.keySet();
		
		//iterate through each value in the HashMap and compute the total number of elements in the HashMap
		for(Character keyFromCollection : keyCollection)
        {
        	upperValue = upperValue + characterMap.get(keyFromCollection);
        	
        	if(randomInt == upperValue)
        	{
        		randomCharacter = keyFromCollection;
        	}
        	if(randomInt >= lowerValue && randomInt <= upperValue)
        	{
        		randomCharacter = keyFromCollection;
        	}
        	
        	lowerValue = upperValue + 1;
        }
		
		return randomCharacter; //return the random character pulled out
	}
}


The Error:
Code:
Exception in thread "main" java.lang.NullPointerException
	at DenseFrequencyLibrary.randomUniformChoose(DenseFrequencyLibrary.java:137)
	at DistributionPlagiarist.randomphrase(DistributionPlagiarist.java:146)
	at DistributionPlagiarist.main(DistributionPlagiarist.java:112)



I will attempt to explain what this does in as few words as possible. For a breakdown of the lab go here. If you don't feel like reading that: THe program reads in some command line arguments. From there it reads from the file provided in the command line and creates "keys" from the specified length. From there I need to create a phrase of the specified length. If i am supposed to create more then one then i do. That is pretty much it. I can't figure out where (really why) the NullPointerException error is coming from.

Help is appreciated!!
 

prostuff1

macrumors 65816
Original poster
Jul 29, 2005
1,482
18
Don't step into the kawoosh...
i have narrowed it down...a little

I think my problems is in the third piece of code I put up, specifically in the randomUniformChoose method.

I seem to be creating a string that does not exist and when i try to pull another character is when i get the error message.
 

plinden

macrumors 601
Apr 8, 2004
4,029
142
Well, the answer is in the stack trace, in the line:
Code:
Exception in thread "main" java.lang.NullPointerException
	at DenseFrequencyLibrary.randomUniformChoose(DenseFrequencyLibrary.java:137)
Obviously, you're trying to access something in a object that's null, namely keyAndValuePairs.randomUniformChoose();

You should try to find out why keyAndValuePairs is null.
 

prostuff1

macrumors 65816
Original poster
Jul 29, 2005
1,482
18
Don't step into the kawoosh...
Well, the answer is in the stack trace, in the line:
Code:
Exception in thread "main" java.lang.NullPointerException
	at DenseFrequencyLibrary.randomUniformChoose(DenseFrequencyLibrary.java:137)
Obviously, you're trying to access something in a object that's null, namely keyAndValuePairs.randomUniformChoose();

You should try to find out why keyAndValuePairs is null.

yup, the keyAndValuePairs is a MultiSetOfChar and goes to get a single "random" character from the HashMap.

Basically what is boils down to is that i am creating a string that does not exist and then trying to pull a value for it, which obviously can't happen.
 

RaceTripper

macrumors 68030
May 29, 2007
2,883
191
Consider writing units test for your code, preferably before you write the code itself. That will help avoid gnarly NPE (and many other) problems.
 

RaceTripper

macrumors 68030
May 29, 2007
2,883
191
BTW, if you have
Code:
while (condition) {...}

there is no need to surround it with a simple
Code:
if (condition) {...}
testing the exact same condition. If condition is false, the body of the while doesn't execute, so the if test buys you nothing except to make your code unnecessarily verbose.

For example, you don't need to do

Code:
if (keyLength < 0) {
    while (keyLength < 0) {
       ...
    }
}

Just use the while block by itself.

As for the rest of your problem, I'll just leave it at the suggestion of writing good unit tests. Are you using JUnit? Maybe time to write better tests. It's a good exercise. It helps you to write better (more robust) code.

I know, I'm not being much help, but if I find your problem for you you haven't really learned from it.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.