Search code examples
javachardouble

How can I efficiently convert a user-input char into a numerical value (double) in Java?


I'm new to programming, especially in Java, so please bear with what may be a very noob-ish question. My main goal here is to create a simple program that calculates the user's GPA by taking three character inputs and displaying the result as a double. For this program I was only required to represent basic letter grades (no A+ or A- or anything like that, just A-F) with their corresponding numerical value (4.0-0.0).

I was able to get the program to work however my question lies in the way that I had to convert, or more so associate, the user's input into/with a decimal.

My approach to this, as you can see in the code below, was to have a user input their letter grade, create a separate variable that would hold the numerical value of each character for each class and use if statements in order to associate that value with it's corresponding character in it's corresponding class. Although it seems to work okay, is there a more efficient way of doing this? I found the if statements sort of inefficient as it seems like a lot of code for what I'm trying to accomplish.

Also, on a side note, I'm using Eclipse as my main IDE for Java and I keep on getting the yellow warning squiggly line message under the first "in" when I type "Scanner in = new Scanner(System.in);" It says "Resource leak: 'in' is never closed" and I have no idea what that means. My programs always run but I hate seeing the warning sign on my files in the package explorer :/

* Lab9.java
package labs;
import java.util.Scanner;

public class Lab9 {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        System.out.print("Please input 3 letter grades: ");
        @SuppressWarnings("resource")
        Scanner in = new Scanner(System.in);
        char class1 = in.next() .charAt(0);
        char class2 = in.next() .charAt(0);
        char class3 = in.next() .charAt(0);
    
        double g1 = 0, g2 = 0, g3 = 0;
    
        if (class1 == 'A') {
            g1 = 4.0;
        }
        if (class1 == 'B') {
            g1 = 3.0;
        }
        if (class1 == 'C') {
            g1 = 2.0;
        }
        if (class1 == 'D') {
            g1 = 1.0;
        }
        if (class1 == 'F') {
            g1 = 0.0;
        }
    
        if (class2 == 'A') {
            g2 = 4.0;
        }
        if (class2 == 'B') {
            g2 = 3.0;
        }
        if (class2 == 'C') {
            g2 = 2.0;
        }
        if (class2 == 'D') {
            g2 = 1.0;
        }
        if (class2 == 'F') {
            g2 = 0.0;
        }
    
        if (class3 == 'A') {
            g3 = 4.0;
        }
        if (class3 == 'B') {
            g3 = 3.0;
        }
        if (class3 == 'C') {
            g3 = 2.0;
        }
        if (class3 == 'D') {
            g3 = 1.0;
        }
        if (class3 == 'F') {
            g3 = 0.0;
        }
    
        System.out.print("Your GPA is a "+((g1 + g2 + g3)/3));
    }
}

Here is the output of a test run:

Please input 3 letter grades: A C B
Your GPA is a 3.0

Thank you for the help!


Solution

  • While if statements work just fine, there are some slightly more java like implementations, mainly using the switch ... case statements in Java (more can be read about them on Oracle's Page).

    Essentially though, the if statements could be replaced with

    ...
    switch(class1) {
                     case 'A':       g1 = 4.0;
                                     break;
                     case 'B':       g1 = 3.0;
                                     break;
                     case 'C':       g1 = 2.0;
                                     break;
                     case 'D':       g1 = 1.0;
                                     break;
                     default:        g1 = 0.0;
                                     break;
             }
    
             switch(class2) {
                     case 'A':       g2 = 4.0;
                                     break;
                     case 'B':       g2 = 3.0;
                                     break;
                     case 'C':       g2 = 2.0;
                                     break;
                     case 'D':       g2 = 1.0;
                                     break;
                     default:        g2 = 0.0;
                                     break;
            }
              switch(class3) {
                     case 'A':       g3 = 4.0;
                                     break;
                     case 'B':       g3 = 3.0;
                                     break;
                     case 'C':       g3 = 2.0;
                                     break;
                     case 'D':       g3 = 1.0;
                                     break;
                     default:        g3 = 0.0;
                                     break;
             }
    ...
    

    The default statement would also serve as some error handling, taking in any rogue values and assigning them 0.0. break is a more complex term, but it is needed in the switch case statement.

    Beyond this, you could create a method to reduce duplicate code.

    public class Lab9 {
         /**
          * @param letter
          */
          private static double letterValue(char letter) {
             double value = 0.0;
             switch(letter) {
                     case 'A':       value = 4.0;
                                     break;
                     case 'B':       value = 3.0;
                                     break;
                     case 'C':       value = 2.0;
                                     break;
                     case 'D':       value = 1.0;
                                     break;
                     default:        value = 0.0;
                                     break;
             }
             return(value);
         }
         /**
          * @param args
          */
         public static void main(String[] args) {
             // TODO Auto-generated method stub
             System.out.print("Please input 3 letter grades: ");
             @SuppressWarnings("resource")
             Scanner in = new Scanner(System.in);
             char class1 = in.next() .charAt(0);
             char class2 = in.next() .charAt(0);
             char class3 = in.next() .charAt(0);
             double g1 = 0, g2 = 0, g3 = 0;
             g1 = Lab9.letterValue(class1);
             g2 = Lab9.letterValue(class2);
             g3 = Lab9.letterValue(class3);
             System.out.print("Your GPA is a "+((g1 + g2 + g3)/3));
         }
     }
    

    To do it with minimal code, you could actually leverage the fact that characters have numeric representations (normally using the ASCII Enconding framework). This would allow you to simplify the method. This uses some more advanced topics such as type casting, so be wary.

         private static double letterValue(char letter) {
             double value = 0.0;
             if((int)letter < 70) {
                     value = (((int)letter) - 69) * -1;
             }
             return(value);
         }
    

    Essentially this takes the numeric values of the letter (A: 65, B: 66, ...) and subtracts 69 to make them the correlated negative values, and then flips them to be positive. It assigns anything out of the range a value of 0.0 (including Es, which is a strange edge case). This is not an intuitive representation of what the code is doing, so I would not recommend it.

    All that being said, none of these are significantly more efficient than any other. They all function reasonably similarly (ignoring the last numeric operations), and therefore runtime wouldn't be significantly impacted. Some look cleaner than others, and that is worth something.