0

I currently have this program read the contents of a text file and calculate the averages and amount of test scores taken and print them out neatly in a small data table. These are the names, amount of quizes taken and average of each student:

James Tiberius Kirk              8                         91.63 
Buffy Summers                    7                         83.14 
Tom Baker                       15                        100.00 
Malcolm Reynolds                 9                         84.22 
Elizabeth Bennet                 9                         93.33 
John Blutarsky                   9                          0.00 
Dorthy Gale                      6                         85.83 

All of these Students are stored within the Array named Anames[]. I was wondering if it was at all possible to sort these students alphabetically by last name using the code that I have now. When I run the program it gives me the error:

Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: -1

at java.lang.String.substring(String.java:1927)
at text.reader.TextReader.compareLastNames(TextReader.java:117)
at text.reader.TextReader.main(TextReader.java:94)

Here is the code of my main class:

public static void main(String[] args)throws IOException{

    Double score=0.0;
    int b,j;
    String tempfirst = "";
    String templast = "";
    Student Anames[] = new Student[30];
    Student Temp[] = new Student [1];
    int Stucount = 0;
    Scanner reader = new Scanner(new File("quizScores.txt"));
    boolean runProgram = true;
    PrintWriter writer = new PrintWriter(new File("scoreReport.txt"));
    //prints header for report
    System.out.println("Name                        Number Quizes             Quiz Socres");
    writer.println("Name                        Number Quizes             Quiz Socres");

    //check to see if end of file string
    while (!reader.hasNext("-10")){
        String name="", first="", last="";

        //gets the name from file
        while(!reader.hasNextDouble()){
            last = reader.next();

            while (!reader.hasNextDouble()){
                first = first+reader.next()+" ";
            }
            name=first+last;
        }

        //creates new student with given name
        Student newStudent = new Student(first, last);
        Anames[Stucount] = newStudent;
        Stucount++;

        //gets the quiz scores and makes sure does not averge in the end of file string.
        while (reader.hasNextDouble()&& !reader.hasNext("-10")){
           newStudent.addQuiz(reader.nextDouble());
        }

        //Prints out the formated data
        System.out.printf("%-30s%4.0f%30.2f \n",newStudent.getName(), newStudent.getQuizNumber(), newStudent.getAverage());
        writer.printf("%-30s%4.0f%30.2f",newStudent.getName(), newStudent.getQuizNumber(), newStudent.getAverage());

        writer.println();
    }
    System.out.println("\n");

    for (b = 0; b < Stucount; b++){
        int INTEGERTEMP = b;
        for (j= b+1; j < Stucount; j++){
            int INTEGERTEMP2 = j;
            if ((compareLastNames(Anames[INTEGERTEMP].getLAST(), Anames[INTEGERTEMP2].getLAST()))>0){
                Temp[0] = Anames[b];
                Anames[b] = Anames[j];
                Anames[j] = Temp[0];
            }
        }
    }

    System.out.println("Name                        Number Quizes             Quiz Socres");
    for (int i = 0; i < Stucount; i++) {

            System.out.printf("%-30s%4.0f%30.2f \n", Anames[i].getName(), Anames[i].getQuizNumber(), Anames[i].getAverage());

    }

    writer.close();
}

private static int compareLastNames(String a, String b){
    int index_a = a.lastIndexOf(" ");
    String surname_a = a.substring(index_a);
    int index_b = b.lastIndexOf(" ");
    String surname_b = b.substring(index_b);
    int lastNameCmp = surname_a.compareToIgnoreCase(surname_b);
    return lastNameCmp;
}

Here is the Student.java which contains most of the methods used:

public Student (String inName, String inLast){
    studentName=inName;
    studentLast = inLast;
    quizAverage = 0;
    quizScore=0;
    numberQuizes=0;
}

public void addQuiz(double inQuiz){
    quizScore += inQuiz;
    numberQuizes++;
}

public double getAverage(){
    quizAverage = quizScore/numberQuizes;
    return quizAverage;
}

public String getName(){
    return studentName+studentLast;
}

public double getQuizNumber(){
    return numberQuizes;
}

public String getLAST(){
    return studentLast;
}
11
  • It appears that your program will think the last names are James, Buffy, Tom, Malcolm, Elizabeth, John, and Dorthy. (Or maybe I got confused. It doesn't look like you're actually using last and first variables to mean the last and first names. But that part of your code is pretty confusing.) Commented Nov 3, 2015 at 3:56
  • 1
    why not use a custom comparator? that way you dont need to create your own compareLastnames method Commented Nov 3, 2015 at 4:01
  • What is the exact format of your file? Also, why not make Student implement Comparable<Student>? Commented Nov 3, 2015 at 4:02
  • lastIndexOf(" ") returns -1 when you give it a string with no space in it. That's why Java is complaining; you then use that -1 when calling substring() and it's out of bounds. I'd suggest you either use a debugger or put in System.out.println("a = " + a); and similarly for b in that method, to see what a and b are. One of them doesn't have a space. That will probably help you narrow down where, in the rest of the program, your problem is. Commented Nov 3, 2015 at 4:02
  • @AbtPst, @ElliottFrisch Those are good suggestions. But if he can't get the comparison method right in compareLastNames, he's not going to get it right in a comparator either. First things first. Commented Nov 3, 2015 at 4:05

2 Answers 2

1

You can use java.util.Arrays.sort(Student [] arr, Comparator<Student> comp) instead of your own compare code. In single line you can achieve it like this:

Student arr[];//considering this array you will populate
Arrays.sort(arr,new java.util.Comparator<Student>(){

            public int compare(Student o1, Student o2) {

                return o1.studentLast.compareTo(o2.studentLast);
            }

        });
//then the arr will be sorted with studentLast name
Sign up to request clarification or add additional context in comments.

9 Comments

Thank you Tom. I tried inputting your code into my main class and the only problem that I am facing is that it tells me that it requires a value when it requires a .class? Am I inserting it into the wrong area?
@J.Z what is your actual exception you are receiving?
@ptierno Exception in thread "main" java.lang.RuntimeException: Uncompilable source code - Erroneous tree type: <any> at text.reader.TextReader.main(TextReader.java:88)
@J.Z I guess what i should have asked is how did you implement the code that this answer is supposed to fix. the exception you just gave sounds to me like a serious one.
@J.Z docs.oracle.com/javase/7/docs/api/java/util/…, first argument is the array to be sorted. second the comparator. it is a void function so i'm guessing it modifies the array in place.
|
0

Let's work our way back from your exception to figure out where the problem is. First, it tells us we've got a StringIndexOutOfBoundsException on line 117; that is, the line (it might actually be the surname_b line, you've removed code from the class that means I can't match up the lines properly)

String surname_a = a.substring(index_a);

You'll notice the message from the exception helpfully tells us that the index used was -1. Let's take a look at why a.lastIndexOf(" "); would return -1. We see in the documentation for String that it returns -1 when the character does not occur in the String.

Now, let's work another step back in the Exception's stack trace to figure out why there's no space in that String. The Exception tells us to check line 94, where we see

if ((compareLastNames(Anames[INTEGERTEMP].getLAST(), Anames[INTEGERTEMP2].getLAST()))>0){

So, what's going on here? We're passing in the last names (and just the last names) from each of the students into our comparison function. The last names, for the most part, have no spaces in them.

So, how do we fix this? Well, you'll have to change your function to only take substrings of the surname if there actually is a space in them, i.e. if the index returned isn't -1.

Once you've got the comparison function done, I recommend looking at how to write an Object that implements the Comparable interface. This will allow you to use library sorting functions, which will be faster and less buggy than your own sorting functions (most likely!).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.