3
\$\begingroup\$

This is a rather simple grade calculating application. Typical assignment or text book project. I've recently finished an introductory course to java, and have been continuously practicing by picking up random projects to see what I can do. I just recently made this Grade calculating project that I'm sure everyone is familiar with. I did this without looking up any help, and although the project is working, I'm looking to see how I can make this more efficient. Perhaps take out some lines of code. Any comments or suggestions will be greatly appreciated.

 /* A PROGRAM THAT CALCULATES THE GRADE AVERAGE FROM AN ARRAY OF GRADES
 * ENTERED BY THE USER, AND PRINTS WEATHER STUDENT PASSED OR FAILED AND 
 * THEIR RESPECTIVE GRADE.  
 * 
 * 1. ASK USER FOR THE NUMBER OF GRADES THEY WISH TO ENTER
 * 2. CREATE AN ARRAY THE SIZE OF NUMOFGRADES ENTERED.
 * 3. CREATE A DASH LINE AFTER NUMBERS HAVE BEEN ENTERED
 * 4. CALCULATE THE SUM AND PRINT
 * 5. CALCULATE THE AVERAGE AND PRINT
 * 6. DETERMINE WHAT LETTER GRADE WAS ACHIEVED
 * 7. PRINT WEATHER STUDENT PASSED OR NOT
 * 8. PROMT USER IF THEY WANT TO ENTER MORE GRADES.
 */

import java.util.*;

public class GradeAverage {

    public static Scanner kbd = new Scanner(System.in);

    //Method that will calculate the sum
    public static int sum( int[] gradeArray, int size){
        int sum = 0;
        int [] temp = gradeArray;//tem array is set equal to original array
        for (int i = 0; i<gradeArray.length; i++){
            sum +=temp[i];//array numbers are added to calculate sum
        }
        return sum;//calculated sum is returned
    }

    //method that will calculate the average by receiving array and size
    //method will return average.
    public static double average(int[] gradeArray, int size){
        double average;
        int[] temp = gradeArray;
        int sum = 0;
        for (int i = 0; i<gradeArray.length; i++){
            sum +=temp[i];
        }
        //System.out.println("The sum is: " + sum);

        average = (double)sum/(double)size;
        return average;
    }

    //letterGrade method will determine what letter grade will be returned.
    public static String letterGrade(double gradeAverage){
        String lettrGrade = "";

        int quotient = (int)gradeAverage/10; //quotient will deterimine LetterGrade
        int remainder = (int)gradeAverage%10; // remainder will determine if a "+ or -"

        switch(quotient){//switch statement for cases if grade is A, B, C, D, F
        case 10://100% so just return A+;
            return "A+";
        case 9: //90-89 is a A
            lettrGrade="A";
            break;
        case 8: //80-89 is a B
            lettrGrade = "C";
            break;
        case 7: //70-79 is a C
            lettrGrade="C";
            break;
        case 6: //60-69 is a D :
            lettrGrade = "D";
            break;
        default:
            return "F";

        }

        switch (remainder){ //remainder switch statement will be used to 
        //determine if a + or a - is added to the letter grade. 
        //these are the cases that will receive "+"
        case 0: case 1: case 2: case 3: case 4:
            lettrGrade+="-";
            break;
        case 7: case 8: case 9: 
            lettrGrade +="+";
        }

        return lettrGrade;//letter grade with final + or _
    }

    //DashLine method will print out a dash line for better readability.
    public static void DashLine(){
        for(int i = 0; i<20; i++){
            System.out.print("-");
        }
    }

    public static void main(String[] args) {
        int[] grades;//array where grades will be stored
        int numGrades;//will determine the size of the array.
        double gradeAverage; //will be set equal to the average method.
        int total;//will be set equal to the sum method.

        String cont = "";//empty string

        do{//loop will run as long as 'y' is entered

        System.out.print("HOW MANY GRADES DO YOU WISH TO ENTER?: ");

        numGrades = kbd.nextInt();
        grades = new int[numGrades];
        System.out.print("\n\nPLEASE ENTER " + numGrades + " GRADES:\n");


        for(int i = 0; i<grades.length; i++){

            grades[i]=kbd.nextInt();
            if(grades[i]>100 || grades[i]<0){
                System.out.println("GRADES CAN NOT EXCEED 100 or BE LESS THAN 1");
                i--;
            }               

        }

        total = sum(grades, numGrades);//calls on sum method
        gradeAverage = average(grades,numGrades);//calls on average method


        DashLine();//prints dashlines

        System.out.print("\nThe Total Sum is: " + total + "\n");

        System.out.printf("The Average is: %.2f \n",  gradeAverage);

        String ltrGrade;

        ltrGrade= letterGrade(gradeAverage);

        if(!(ltrGrade.equalsIgnoreCase("F"))){//test if ltr grade is F, 
            //if its not F, print the following
            System.out.println("\nYour Final Letter Grade is a: "+ ltrGrade
                    +"\nYOU PASS!!");

        }
        else{//failing grade prints this.
            System.out.println("\nYour Final Letter Grade is a: "+ ltrGrade
                    +"\nYOUR PRETTY DUMB!!");           
        }

        DashLine();//prints dash lines

        System.out.println("\n\nDO YOU WANT TO ENTER MORE GRADES? Y or N");
        cont = kbd.next();
        for(int j = 0; j< 80; j++){//simulates clear screen.
            System.out.println();
        }

        }while(cont.equalsIgnoreCase("y"));

        kbd.close();
    }

        }

The output:

HOW MANY GRADES DO YOU WISH TO ENTER?: 5


PLEASE ENTER 5 GRADES:
100
55
56
77
89
--------------------
The Total Sum is: 377
The Average is: 75.40 

Your Final Letter Grade is a: C
YOU PASS!!
--------------------

DO YOU WANT TO ENTER MORE GRADES? Y or N
\$\endgroup\$
  • \$\begingroup\$ Are you on Java 8? \$\endgroup\$ – h.j.k. Dec 24 '15 at 2:24
  • \$\begingroup\$ yes i am. I have the latest version \$\endgroup\$ – mlopman Dec 24 '15 at 2:30
3
\$\begingroup\$

try-with-resources

Since Java 7, using try-with-resources is recommended to safely and efficiently handle the underlying I/O resource for Scanner:

public static void main(String[] args) {
    try (Scanner scanner = new Scanner(System.in)) {
        // pass the scanner around where user input is required
    }
}

UX

In my opinion, your prompts shouldn't be SHOUTING AT the user. Also, you shouldn't be enforcing negativity by suggesting YOUR [sic] PRETTY DUMB. I will suggest something more encouraging like "Please try harder the next time".

Java 8

In Java 8, getting statistics for a set of integers can be easily done via IntStream.summaryStatistics(). Hence, instead of looping through your inputs twice to perform the calculations manually, you can have something similar to:

// getInteger(String, Scanner) and getInteger(String, Scanner, int) 
// validates and gets positive integers from the user after prompting,
// with the optional int as the inclusive limit
int[] grades = new int[getInteger("Number of grades: ", scanner)];
for (int i = 0; i < grades.length; i++) {
    grades[i] = getInteger("Enter grade: ", scanner, 100);
}
IntSummaryStatistics summary = IntStream.of(grades).summaryStatistics();
System.out.println("Sum: " + summary.getSum());
System.out.println("Average: " + summary.getAverage());
|improve this answer|||||
\$\endgroup\$
3
\$\begingroup\$

Didn't test any of the code.

Before you think about efficiency, think of writing readable, maintainable, etc. code. A typical start of main is:

public static void main(String[] args) {
    final Application app = new Application();
    app.run();
}

That shows everyone, that your application does not use any application arguments. Then create your Application and try to write code which is readable.

Try to divide your code into meaningful pieces: - read grades - calculate and display average - ask for quit

run()

public void run() {
    boolean shouldQuit = false;
    while(!shouldQuit) {
        final List<Integer> grades = readGrades();
        displayAverage(grades);
        shouldQuit = askForQuit();
    }
}

readGrades()

HOW MANY GRADES DO YOU WISH TO ENTER?:

What if I type 4 but then realize, that I actually wanted to write 5 grades? What about a comma/whitespace separated list of grades?

100, 50, 70, 20

Just read the line, split it and create a List of it.

displayAverage()

private void displayAverage(List<Integer> grades) {
    if(!grades.isEmpty()) {
        float average = avg(grades);
        // println ...
    } else {
        // println: no grades entered
    }
}

private float avg(List<Integer> grades) {
    float sum = 0;
    for(int grade : grades) {
        sum += (float)grade;
    }

    return sum / (float)grades.size();
}

Of course there are other approaches, too, like using Java 8 to calculate the average (https://stackoverflow.com/a/10791579/4469738) or creating more classes to do the job.

I think static main-class and one Application class should be enough for that easy program.

|improve this answer|||||
\$\endgroup\$
3
\$\begingroup\$

A few comments:

  • PLEASE DON'T SHOUT! Upper case comments and prompts make me think you are an escapee from 1970s mainframe programming, and I suspect that is not the case :)
  • Get into the practice of writing Javadoc by habit. Your IDE will be able to create Javadoc so generate the doc and take a look at it - you just need to use /** This is a comment **/ syntax and @param comments for public method parameters.
  • You are nicely sizing your grades array, but then carrying numGrades into the sum() and average() methods where it is unused. In more complex programs this can become the cause of subtle bugs. Much better to use grades.length to get the size.
  • Try to write DRY (don't repeat yourself) code. Your average() method can become a one-liner, as you can call sum() to to do the summation.
  • I much prefer comments in the active voice - e.g. Calculate the sum of all elements. There is room for personal preferences here...
  • I don't think you need the temp array variables at all. Just iterate over the passed grades array.
  • Don't declare variables until they are needed. The Scanner can go inside main(); the average() method has a result variable that can be declared where it is calculated, or even deleted completely (return (double) sum(grades)/(double) grades.length;)
  • The DashLine() method is poorly named. It should start with a lower case letter. Why not call it printDashedLine() and dispense with the comment?
  • Rather too much is public. The Scanner definitely should not be public and you might want to consider renaming the gradeArray parameter passed to sum() and average if they are public. These methods will work for an array of ages or carrots or whatever, so the passed parameter should have a neutral name.
  • There are some quite minor formatting issues - spaces round operators; else should be on the same line etc. I suggest asking your IDE to format the code, then compare it against the original.

I hope my answer does not come across as negative. It is meant to be supportive, so good luck!

|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ @Bill Woodger Sorry I upset you - on second thoughts, the use of upper case may have come from various sources; COBOL and other languages had keywords that had to be upper case; the hierarchical databases of the day may have not supported mixed case queries. I still work with a mainframe that insists on shouting. I'll modify my answer to exonerate COBOL. \$\endgroup\$ – kiwiron Dec 26 '15 at 5:57
-1
\$\begingroup\$

Relevant to efficiency is validation of input. If a near maximum integer is input, then tally of the very numerous grade values into another integer is overflow vulnerability. Can instead use ranges to only support reasonable values.

|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ Could you be more specific about how you would recommend improving the code? I see grades[i]=kbd.nextInt(); if(grades[i]>100 || grades[i]<0){ System.out.println("GRADES CAN NOT EXCEED 100 or BE LESS THAN 1"); i--; } — how is that not sufficient? \$\endgroup\$ – 200_success Dec 26 '15 at 6:49
  • \$\begingroup\$ numGrades Max integer is input, then what happens? Array of subsequent integer, then finally a tally of those... Validation of every input, prevent application from ending ungracefully. \$\endgroup\$ – kph0x1 Dec 26 '15 at 16:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.