-1

The user is allowed to play with an array of strings. They can add strings to the array, remove strings from the array, search for strings in the array, and eventually they will be able to sort the array. The sorting is what is messing me up. I've tried a few different approaches. The first approach was to convert the array into an ArrayList and use Collections to sort the ArrayList, which would be converted back into the static class array. It doesn't work. The second approach I tried was to iterate through the array and try to sort only the strings added by the user instead of everything in the array (since there are some null values in the array). Perhaps I should iterate through the array and then store the non-null values into a new array that I can then sort? But what if I want to add more strings after sorting the new array? That's why I stopped with the second solution. The third attempt was to use Arrays.sort() on my array but for some reason it does not work.

Here is the exception:

 Exception in thread "main" java.lang.NullPointerException 
    at java.util.ComparableTimSort.countRunAndMakeAscending(ComparableTimSort.java:290) 
    at java.util.ComparableTimSort.sort(ComparableTimSort.java:157) 
    at java.util.ComparableTimSort.sort(ComparableTimSort.java:146) 
    at java.util.Arrays.sort(Arrays.java:472) 
    at java.util.Collections.sort(Collections.java:155) 
    at testingSearch.sortArray(testingSearch.java:93) 
    at testingSearch.main(testingSearch.java:42) 

Here is my code:

import java.util.Scanner;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


public class testingSearch {

    static String[] strArray;
    static {
        strArray = new String[5];
    }
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        while(true){
            System.out.println("1. Add string to the string array.");
            System.out.println("2. Remove string from the string array.");
            System.out.println("3. Display strings in string array.");
            System.out.println("4. Search the string array for a string.");
            System.out.println("5. Sort the strings in the string array.");

            int userChoice = 0;
            userChoice = input.nextInt();

            switch(userChoice) {
            case 1:
                addString();
                break;
            case 2:
                removeString();
                break;
            case 3:
                displayStrings();
                break;
            case 4:
                searchArray();
                break;
            case 5:
                sortArray();
                break;
            }
        }

    }

    public static void addString(){
        Scanner input = new Scanner(System.in);
        System.out.println("What string do you want to add?");
        String userInput;
        userInput = input.nextLine();
                ArrayList<String> stringList = new ArrayList<String> (Arrays.asList(strArray));
        stringList.add(userInput);
        strArray = stringList.toArray(strArray);
    }

    public static void removeString(){
        Scanner input = new Scanner(System.in);
        System.out.println("What string do you want to remove?");
        String userInput;
        userInput = input.nextLine();
        ArrayList<String> stringList = new ArrayList<String>    (Arrays.asList(strArray));
        stringList.remove(userInput);
        strArray = stringList.toArray(strArray);
    }

    public static void displayStrings(){
        for (String s: strArray){
            if (!(s == null)){
                System.out.println(s);
            }
        }
    }

    public static void searchArray(){
        Scanner input = new Scanner(System.in);
        System.out.println("What string do you want to search the array for?");
        String userInput;
        userInput = input.nextLine();
        ArrayList<String> stringList = new ArrayList<String>(Arrays.asList(strArray));
        if (stringList.contains(userInput)){
            System.out.println("The string array contains that string!");
        }
        else {
            System.out.println("The string array does not contain that string...");
        }
    }

    public static void sortArray(){
        /*ArrayList<String> stringList = new ArrayList<String> (Arrays.asList(strArray));
        Collections.sort(stringList);
        strArray = stringList.toArray(strArray);*/

        /*for (String s: strArray) {
            if (!(s == null)){
                Arrays.sort(strArray);
            }
        }*/

        List<String> stringList = new ArrayList<String>(Arrays.asList(strArray));
        Collections.sort(stringList);
        strArray = stringList.toArray(strArray);

        //Arrays.sort(strArray);

    }

}
Jim Garrison
  • 85,615
  • 20
  • 155
  • 190
HandleThatError
  • 598
  • 7
  • 29
  • 1
    "The first approach was to convert the array into an ArrayList and use Collections to sort the ArrayList, which would be converted back into the static class array. It doesn't work. ... The third attempt was to use Arrays.sort() on my array but for some reason it does not work." You've *got* to be more specific than that. – awksp Jun 12 '14 at 01:29
  • Perhaps a `TreeMap` would be better for your use case? Unless you *have* to use an array? – awksp Jun 12 '14 at 01:30
  • Instead of sorting the array for me, it generates the following errors: Exception in thread "main" java.lang.NullPointerException at java.util.ComparableTimSort.countRunAndMakeAscending(ComparableTimSort.java:290) at java.util.ComparableTimSort.sort(ComparableTimSort.java:157) at java.util.ComparableTimSort.sort(ComparableTimSort.java:146) at java.util.Arrays.sort(Arrays.java:472) at java.util.Collections.sort(Collections.java:155) at testingSearch.sortArray(testingSearch.java:93) at testingSearch.main(testingSearch.java:42) – HandleThatError Jun 12 '14 at 01:31
  • user3580294, a TreeMap would be better but I am playing with this string array because there will be a few assignments that will require this kind of array manipulation, including sorting arrays of strings. So yes, I have to use the array. I got this far, sorting the array is the last thing I need to figure out. – HandleThatError Jun 12 '14 at 01:32
  • Do you have `null` elements in your array? `Arrays.sort()` will only accept elements that implement `Comparable`, and `null` references definitely don't fit that. If all your `null` elements are gathered together and not mixed in with other elements, you can use the other overload of `Arrays.sort()` that sorts a section of the array. – awksp Jun 12 '14 at 01:34
  • Yes, there are null elements in the array. But that is okay because when I display the contents of the array, I've made sure that only non-null elements are displayed. So even if null elements are mixed in during the sorting, I'd still be able to display the sorted non-null elements if I could just get the Arrays.sort() to work. Perhaps I'm doing something wrong in the implementation itself? Not too familiar with Java. I'm going to keep searching around but if you get any ideas, I'd be glad to try them. – HandleThatError Jun 12 '14 at 01:36
  • Just updated my comment. Are `null` elements mixed in with other elements, or are they all grouped together? If they are grouped, check [this](http://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html#sort-java.lang.Object:A-int-int-) out. – awksp Jun 12 '14 at 01:37
  • If the array contains ANY null elements then the `sort()` method will throw NPE regardless of whether or not YOUR code deals with them when printing. – Jim Garrison Jun 12 '14 at 02:16
  • Can I get rid of the null elements? Just in case the nulls are going to be a problem, I'm redoing the entire program with an ArrayList instead of an array. This should be a lot easier than using the array. Thanks for your help. – HandleThatError Jun 12 '14 at 02:18
  • You can always use `""` instead of `null` as an option. `ArrayList` would certainly make things easier. – awksp Jun 12 '14 at 02:20
  • So far, ArrayList is definitely making things easier. Thanks user3580294. Can you explain more what you mean by using "" instead of null as an option? – HandleThatError Jun 12 '14 at 02:22
  • Uh, given the code you have it seems that it wouldn't really work too well, so I guess scratch that. I didn't realize you used temporary `ArrayList`s to do your work. Sorry... But the idea was when you removed things (and when you initialized the array) to replace them with `""` instead of `null`, but as you never did that work yourself, that's a moot point. – awksp Jun 12 '14 at 02:30
  • Just use a _Comparator_... That way you can deal with `null` however you want. [Here](http://stackoverflow.com/a/14863539/778118) is an answer that shows how to use a Comparator. Both Arrays and Collections can be sorted by using a Comparator. – jahroy Jun 12 '14 at 02:32
  • user3580294, you're a genius! I just replaced all the nulls with "" and now the array version of the program works perfectly. I love you. I'm still going to keep on working on an ArrayList version of the program though, because it's cleaner. Please post your most recent comment as an answer so I can select it as the accepted answer. :) – HandleThatError Jun 12 '14 at 02:36
  • Oh, uh, OK. Just a warning, I can't promise that that fix would perform particularly well; I just know it'll prevent `NullPointerException`s. – awksp Jun 12 '14 at 02:40

3 Answers3

5

The reason you're getting NullPointerExceptions can be explained by the javadoc for Arrays#sort() (emphasis mine):

Sorts the specified array of objects into ascending order, according to the natural ordering of its elements. All elements in the array must implement the Comparable interface.

Because Arrays.sort() expects Comparable elements and not null values, you end up with a NullPointerException when the method tries to call compareTo().

The fix-this-now way of solving this would be to simply make sure all null elements in your array are replaced with something non-null, such as "". So loop through your array at creation and after removing a String and set null elements to "". However, this solution probably wouldn't perform too well for your code, as it requires another loop after every String is removed, which could grow onerous. At least it won't require you to create a bunch of objects, due to the magic of the String pool, so it's a bit better than what you might do with a different object.

A better solution would be to simply use ArrayList<String> instead of a raw array; after all, you're already using one to manage addString() and removeString(), so you would have less converting from array to ArrayList and back to do. In addition, you wouldn't need to worry about NPEs when sorting (at least for your use case; adding null to a Collection would still result in NPEs when sorting).

You can also just use a raw array, but managing that would get kind of annoying, so I wouldn't recommend that. If you do it right you won't have to worry about NPEs though.

awksp
  • 11,764
  • 4
  • 37
  • 44
  • Slow down there. It's not because `null` doesn't implement `Comparable`, since `null` is an instance-time value and could be assigned to any object that is assignable from `Comparable`. It's because the value itself is `null` that this failure occurs. Further, you can add null elements to a list, and still have a similar problem. – Makoto Jun 12 '14 at 03:07
  • @Makoto Reworded some things based on what you said. Better? I can't really complain about anything you said, as my initial understanding was clearly wrong. – awksp Jun 12 '14 at 03:28
0

No problem! Here you go:

 1. Create a new array
 2. Insert items to that array, in the right order

public class sorter {

public static void main(String[] args){
    String[] array = new String[]{"HI", "BYE", null, "SUP", ":)"};

    //Sort:

    String[] newArray = new String[array.length];
    int index = 0;


    for(int m = 0 ; m < newArray.length; m++){
        String leastString = null;
        int i = 0;
        for(i = 0; i < array.length; i++){
            if(leastString==null&&array[i]!=null){
                leastString = array[i];
                break;
            }
        }

        for(int j = i+1; j < newArray.length; j++){
            if(array[j]!=null){
                if(array[j].compareTo(array[i])<0){
                    leastString = array[j];
                    i = j;
                }
            }
        }
        if(i==newArray.length)break;
        newArray[m] = leastString;
        array[i] = null;
    }   


    for(String s : newArray){
        System.out.println(s);
    }
}

}

This prints:

:)
BYE
HI
SUP
null

EDIT: Another very simple way to solve this in a very effiecient manner, is to use ArrayList:

public class AClass {



public static void main(String[] args){
    String[] array = new String[]{"HI", "BYE", null, "SUP", ":)"};

    //Sort:

    ArrayList<String> newArray = new ArrayList<String>();
    for(String s : array){
        if(s!=null){
            newArray.add(s);
        }
    }
    Collections.sort(newArray);
    String[] retval = new String[newArray.size()];
    retval = newArray.toArray(retval);

    for(String s : retval){
        System.out.println(s);
    }

} }

Dean Leitersdorf
  • 1,303
  • 1
  • 11
  • 22
  • Especially considering the fact that this isn't an in-place sort... Seems rather suboptimal for a selection sort. – awksp Jun 12 '14 at 05:30
  • Yes it is weird, I agree. I would have done it much differently differently were it ArrayLists instead! However, it seems like he wanted Arrays to be used -- anyhow, this works (even though relatively low efficiency) – Dean Leitersdorf Jun 12 '14 at 05:32
  • Perhaps consider shuffling all the `null`s off to one side and performing a regular sort on the rest? O(n lg n) instead of O(n^2), and it'd be in-place too. – awksp Jun 12 '14 at 05:34
  • That would be possible! I just thought of something new, let me try it. – Dean Leitersdorf Jun 12 '14 at 05:35
  • ^^ Exactly what I was thinking --- The first one was even more than O(n^2)... Posting new one. Posted. – Dean Leitersdorf Jun 12 '14 at 05:40
  • One last suggestion -- You can use `toArray()` to avoid copying things yourself. – awksp Jun 12 '14 at 05:45
  • Yes, problem is it gives Object[] instead of String[] -- did that so it doesn't ruin rest of code (b/c rest of code uses a String[]) – Dean Leitersdorf Jun 12 '14 at 05:46
  • There's an overload that takes a `T[]` argument – awksp Jun 12 '14 at 05:46
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/55478/discussion-between-dean-leitersdorf-and-user3580294). – Dean Leitersdorf Jun 12 '14 at 05:46
0

I guess the simple way of doing things really would be:

static String[] strArray;
static {
    strArray = new String[5];
    for(int i = 0, i < strArray.length; i++)
    {
        strArray[i] = "";
    }
}

And then just call

Arrays.sort(strArray);

When you want to sort it. If that doesn't work, although I think it should; your initial approach would have been the following:

    List<String> stringList = new ArrayList<String>();
    for(int i = 0; i < strArray.length; i++)
    {
       stringList.add(strArray[i]);
    }
    Collections.sort(stringList);
    strArray = stringList.toArray(new String[stringList.size()]);

Although it clearly doesn't seem very memory-friendly.

EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428