0

First, for quick context, here's my post from yesterday:

How to work around a NullPointerException in Java?

So I'm getting this NullPointerException, which I now believe is occurring before I try to find the index of the first duplicate in the array of strings. Before I search for the index of the first duplicate, I double the size of the string array using this method:

static String[] upSizeArr( String[] fullArr )
{

    int size = fullArr.length; 
    String[] newSizeArr = new String[(2 * size)]; 
    for (int a = 0; a < size; a++) {
        newSizeArr[a] = fullArr[a];
    }
    return newSizeArr;
}

and I then use that method in the context of this while loop:

static final int CAPACITY = 10;
int wordCount = 0;

BufferedReader wordFile = new BufferedReader( new FileReader(args[1]) );
String[] wordList = new String[CAPACITY];

while ( wordFile.ready() ) 
    {   if ( wordCount == wordList.length ) 
            wordList = upSizeArr( wordList );
        wordList[wordCount++] = wordFile.readLine();
    } 
wordFile.close();

Is there any possible work around for this using the upSizeArr method? I would prefer the solution be basic and using only arrays with no other data structures. I am new to programming and am really trying to get a grasp of the fundamentals...been looking for a solution to this NullPointException for about a week or so now.

Here is the code in it's entirety:

import java.io.*;
import java.util.*;
public class Practice
{
    static final int CAPACITY = 10;
    static final int NOT_FOUND = -1;
    public static void main (String[] args) throws Exception
    {
        if (args.length < 1 )
        {
            System.out.println("\nusage: C:\\> java Practice <words filename>\n\n"); // i.e. C:\> java Lab2 10Kints.txt 172822words.txt
            System.exit(0);
        }


    String[] wordList = new String[CAPACITY];
    int wordCount = 0;
    BufferedReader wordFile = new BufferedReader( new FileReader(args[0]) );

    while ( wordFile.ready() ) // i.e. while there is another line (word) in the file
    {   if ( wordCount == wordList.length ) 
            wordList = upSizeArr( wordList );
        wordList[wordCount++] = wordFile.readLine();
    } //END WHILE wordFile
    wordFile.close(); 
    System.out.format( "%s loaded into word array. size=%d, count=%d\n",args[0],wordList.length,wordCount );
    int dupeIndex = indexOfFirstDupe( wordList, wordCount );
    if ( dupeIndex == NOT_FOUND )
        System.out.format("No duplicate values found in wordList\n");
    else
        System.out.format("First duplicate value in wordList found at index %d\n",dupeIndex);

} // END OF MAIN

// TWO METHODS 

static String[] upSizeArr( String[] fullArr )
{

    int size = fullArr.length; //find the length of the arrays
    String[] newSizeArr = new String[(2 * size)]; // creates new array, doubled in size
    for (int a = 0; a < size; a++) {
        newSizeArr[a] = fullArr[a];
    }
    return newSizeArr;

}
static int indexOfFirstDupe( String[] arr, int count )
{       
    Arrays.sort(arr);
    int size = arr.length;
    int index = NOT_FOUND;

    for (int x = 0; x < size; x++) {
        for (int y = x + 1; y < size; y++) {
            if (arr[x].equals(arr[y])) {
                index = x;
                break;
            }
        }
    }
    return index;
    }
} // END OF PROGRAM

Also, the file that's being used as the argument is a txt file of strings.

noob4lyfe
  • 53
  • 4
  • 1
    I don't see anything the code you provided that would be dereferencing null. Can you provide more context/code? Where exactly is the exception thrown? In your original post that you linked to, the exception is due to half of the array (the "new" half after resizing) containing `null`s, which `Arrays.sort` will throw an exception attempting to compare `null`s. This can be resolved by creating a Comparator that handles `null`, like here: https://stackoverflow.com/questions/14514467/sorting-array-with-null-values – John Oct 06 '18 at 22:32
  • I'd recommend `ArrayList` or [`System.arraycopy`](https://docs.oracle.com/javase/10/docs/api/java/lang/System.html#arraycopy(java.lang.Object,int,java.lang.Object,int,int)) – MadProgrammer Oct 06 '18 at 22:34
  • 1
    `wordFile.ready()` doesn't do what you think it does – MadProgrammer Oct 06 '18 at 22:38
  • 1
    Which line is actually throwing the exception? – KellyM Oct 06 '18 at 22:40
  • 1
    So I did a really quick hack of your code, without trying to read a file, and it doesn't generate a NPE. I suspect the combination of `wordFile.ready()` and `wordList[wordCount++] = wordFile.readLine()` will put `null` values into the array (`wordFile.readLine()` will return `null` when it reaches the end of the file). – MadProgrammer Oct 06 '18 at 22:47
  • John, the exception is the same as it was in the last post, so I rewrote the Arrays.sort(arr) to Arrays.sort(arr, Comparator.nullsLast(Comparator.naturalOrder())); and the program keeps continually running now without finishing. Am I missing another component? I know it pushes the nulls to the back of the array, but do I have to take it a step further? – noob4lyfe Oct 06 '18 at 23:47
  • Post the exception along with your stack trace so we can see what's happening. – Mad Physicist Oct 07 '18 at 14:47

1 Answers1

2

I'm not sure if it's the cause of your problem, but it is very suspicious...

while ( wordFile.ready() ) {
    //...
}

is not how you should be reading the file. Instead, you should be checking the return result of readLine, which will return null when it reaches the end of the file.

Maybe something more like....

try (BufferedReader wordFile = new BufferedReader(new FileReader(args[1]))) {
    String[] wordList = new String[CAPACITY];

    String text = null;
    while ((text = wordFile.readLine()) != null) {
        if (wordCount == wordList.length) {
            wordList = upSizeArr(wordList);
        }
        wordList[wordCount++] = text;
    }
} catch (IOException ex) {
    ex.printStackTrace();
}

Your code also runs the risk of leaving the file resource open. The above example makes use of the try-with-resources statement to ensure that it is closed properly, regardless of the success of the operation.

Take a look at The try-with-resources Statement for more details.

Unless it's a specific requirement, I would also recommend using an ArrayList or System.arraycopy over rolling your own solution like this.

Maybe have a look at List Implementations for some more details

Update from runnable example...

After having a play without a runnable example of the code, when upSizeArr creates a new array, it's defaulting the new elements to null, which is expected, I'm surprised that Arrays.sort can't handle this.

"A" solution is to fill the unused space with a different non-default value...

static String[] upSizeArr(String[] fullArr) {

    int size = fullArr.length; //find the length of the arrays
    String[] newSizeArr = new String[(2 * size)]; // creates new array, doubled in size
    for (int a = 0; a < size; a++) {
        newSizeArr[a] = fullArr[a];
    }
    for (int a = size; a < newSizeArr.length; a++) {
        newSizeArr[a] = "";
    }
    return newSizeArr;

}

"Another" solution might be to "downsize" the array to fit the available data...

static String[] downsizeToCapacity(String[] fullArr) {
    int lastIndex = 0;
    while (lastIndex < fullArr.length && fullArr[lastIndex] != null) {
        lastIndex++;
    }
    if (lastIndex >= fullArr.length) {
        return fullArr;
    }
    String[] downSized = new String[lastIndex];
    System.arraycopy(fullArr, 0, downSized, 0, lastIndex);

    return downSized;
}

All this tries to do is create a new array whose size is only large enough to contain all the none-null values and return that.

You could then use to something like...

System.out.format("%s loaded into word array. size=%d, count=%d\n", "words.txt", wordList.length, wordCount);
wordList = downsizeToCapacity(wordList);
System.out.format("%s loaded into word array. size=%d, count=%d\n", "words.txt", wordList.length, wordCount);

int dupeIndex = indexOfFirstDupe(wordList, wordCount);

Which, in my testing, outputs

words.txt loaded into word array. size=160, count=99
words.txt loaded into word array. size=99, count=99
No duplicate values found in wordList
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • Hey, appreciate the help! Unfortunately the array is a specific requirement and I need to use Arrays.sort() as per the professor's request. Is there anyway I could rewrite the method instead of the while( wordFile() ), as that is code I am not allowed to modify? I was tasked with merely making the method. I tried putting Arrays.sort(arr, Comparator.nullsLast(Comparator.naturalOrder())); to put the null values in the back of the array and the program just keeps running...am I making progress? I really appreciate your help! – noob4lyfe Oct 06 '18 at 23:40
  • *"the while( wordFile() ), as that is code I am not allowed to modify?"* ... ... but that's the code that is wrong and is likely the source of your problem. I've tested the array resizing and it seems to work fine for me, although I might use `arraycopy` instead – MadProgrammer Oct 06 '18 at 23:46
  • Ugh, sorry about that man! Is there anyway in which I can rewrite my methods so the code will at least run? I tried the arraycopy way too :( My professor is not looking for efficiency or elaborate code (as he himself seems to not have the most "efficient" code xD) – noob4lyfe Oct 06 '18 at 23:52
  • Put in checks for `null` values and default them to something not `null` – MadProgrammer Oct 06 '18 at 23:58
  • Okay, so both my upSizeArr method and my indexOfFirstDupe method in my original post look good? I tried: String[] cleanedArray = Arrays.stream(arr).filter(Objects::nonNull).toArray(String[]::new); to clean up the arr array but now my program won't finish running... – noob4lyfe Oct 07 '18 at 00:21
  • Don't know about `indexOfFirstDupe`, but the resizing seems to work. I would look at `wordFile.readLine()`, if it returns `null`, then ignore the value ... or have another method which takes the results and removes `null` values – MadProgrammer Oct 07 '18 at 00:22
  • So I tried: String[] cleanedArray = Arrays.stream(arr).filter(Objects::nonNull).toArray(String[]::new); to clean up the arr array but now my program won't finish running... – noob4lyfe Oct 07 '18 at 00:31
  • Okay, it's probably time you provided a [complete, runnable example]9(https://stackoverflow.com/help/mcve) which demonstrates your problem, including the data you're using – MadProgrammer Oct 07 '18 at 00:46
  • See my original post above with the edited full code! – noob4lyfe Oct 07 '18 at 01:22