Solutions and Method

Question in the book:

Write a program that translates a letter class into an evaluation class. The meanings of the words A , B , C , D and F are possibly accompanied by + or – . Their numerical values ​​are 4 , 3 , 2 , 1 and 0 . No F+ or F– . A + increases the numerical value by 0.3 , a – decreases it by 0.3 . However, A+ has a value of 4.0 .

Enter the letter class: B- Numeric value 2.7 . Use the class class using the getNumericGrade method.

So my question is: I know that my code is right, I can run it. But I was curious if there is a shortcut or a better version of this code, which makes it more professional and easier to read. Any suggestions or examples would be greatly appreciated.

the code:

 import java.util.Scanner; public class grade { private double numericValue = 0; private String grade = ""; public grade() { Scanner in = new Scanner(System. in ); System.out.print("Enter Grade: "); grade = in .nextLine(); } public double getNumericGrade() { if (grade.equals("A+") || grade.equals("A")) { numericValue = 4.0; } else if (grade.equals("A-")) { numericValue = 3.7; } else if (grade.equals("B+")) { numericValue = 3.3; } else if (grade.equals("B")) { numericValue = 3.0; } else if (grade.equals("B-")) { numericValue = 2.7; } else if (grade.equals("C+")) { numericValue = 2.3; } else if (grade.equals("C")) { numericValue = 2.0; } else if (grade.equals("C-")) { numericValue = 1.7; } else if (grade.equals("D+")) { numericValue = 1.3; } else if (grade.equals("D")) { numericValue = 1.0; } else if (grade.equals("F")) { numericValue = 0; } else { System.out.println("Letter not in grading system"); } return numericValue; } } 
+4
source share
6 answers

You can define mappings and rules separately:

 public static enum Grade { // Letter grades are A, B, C, D, and F // Their numeric values are 4, 3, 2, 1, and 0 A(4),B(3),C(2),D(1),F(0); public final double score; private Grade(double d) { this.score = d; } // Grades are possibly followed by + or – // There is no F+ or F– // a + increases the numeric value by 0.3, a – decreases it by 0.3 // However, an A+ has value 4.0 public double getModifiedScore(char sign) { switch (sign) { case '+': return score + (score < 4 && score > 0 ? 0.3 : 0); case '-': return score + (score > 0 ? -0.3 : 0); default: throw new IllegalArgumentException("Invalid sign"); } } } 

Then just use them (the example assumes you have confirmed the input):

 public static double getNumericGrade(String s){ Grade g = Grade.valueOf(s.substring(0, 1)); if(s.length() > 1){ return g.getModifiedScore(s.charAt(1)); }else { return g.score; } } 
+6
source

I would use a lookup table:

 private final static Map<String,Double> gradeLookup = new HashMap<String, Double>(); gradeLookup.put("A-", 3.7); numericValue = gradeLookup.get(grade); 

Another good option is the switch statement, which since Java 7 finally works with strings.

Both options provide built-in input validation, so the user cannot enter things like β€œG” or β€œF +” or β€œfoo”.

+5
source

Use a Map that maps characters (in this case A .. D , F ) to the appropriate values ​​( 4 .. 0 ).

When processing input:

  • If it is longer than just one character, just find the character on the map.
  • if at the end there is + or - , find the first character and process the second one accordingly (in accordance with the rules you published, remembering to handle special cases such as A+ ).

You can try something like this:

 private static final Map<Character, Double> grades = new HashMap<>(); static { grades.put('A', 4.0); grades.put('B', 3.0); grades.put('C', 2.0); grades.put('D', 1.0); grades.put('F', 0.0); } public static double getNumericGrade(String input) { if (input == null || input.isEmpty() || input.length() > 2 || input.matches("F[+-]") || !grades.containsKey(input.charAt(0))) // validate input throw new IllegalArgumentException(); double val = grades.get(input.charAt(0)); if (input.length() == 1) { return val; } else if (input.charAt(1) == '+') { return (input.charAt(0) == 'A') ? val : val + 0.3; } else if (input.charAt(1) == '-') { return val - 0.3; } else { throw new IllegalArgumentException(); } } 
+1
source

One approach is to use a switch - which works with String in Java 7.

 // Yes, I'm passing grade and shadowing numericValue, since those properties // aren't used anywhere else in the class. public double getNumericGrade(String grade) { double numericValue = 0; switch (grade) { case "A+": case "A": numericValue = 4.0; break; case "A-": numericValue = 3.7; break; case "B+": numericValue = 3.3; break; case "B": numericValue = 3.0; break; case "B-": numericValue = 2.7; break; case "C+": numericValue = 2.3; break; case "C": numericValue = 2.0; break; case "C-": numericValue = 1.7; break; case "D+": numericValue = 1.3; break; case "D": numericValue = 1.0; break; case "F": numericValue = 0; break; default: System.out.println("Letter not in grading system"); break; } return numericValue; } 

... but it reads pretty well.

Another alternative approach is to take the rules that we have about numerical estimates and write something a bit more concise.

  • If the score is some letter point, it is an integer (A = 4, B = 3, C = 2, D = 1, F = 0).
  • If the class has a minus attached to it, the value is the difference of the whole number and 0.3.
  • If a class has a plus attached to it, the value is the sum of the whole number and 0.3.

Here is a solution that uses these rules. It may read a little more verbose and perhaps not everything that differs from the switch, but this is another way to write it.

 public double getNumericGradeRefactored(String grade) { Map<Character, Double> gradeMap = new HashMap<Character, Double>(){{ put('A', 4.0); put('B', 3.0); put('C', 2.0); put('D', 1.0); put('F', 0.0); }}; // split result char[] gradeParts = grade.toCharArray(); double result = gradeMap.get(gradeParts[0]); if(gradeParts.length > 1) { switch(gradeParts[1]) { case '+': result += 0.3; break; case '-': result -= 0.3; break; } } return result; } 
+1
source

I dealt with a "+" or "-" separately.

Check the letter, then add or subtract the rating value accordingly if it contains the characters "+" or "-".

EDIT: Personally, I prefer switch-case for long if-elseif statements, but one of them will work quite well.

0
source

In addition to @Thilos suggestion on how to store actual data, I would like to add that in such cases you do not want to store in this case versions of String and int data, if performance is not extremely critical.

While this does not look great now, in many cases you run the risk of losing synchronization between them, that is, String says one thing and int says another, and you encounter errors because of this.

And your constructor should not ask for input unless it becomes very common. Cleanly take String .

0
source

Source: https://habr.com/ru/post/1498790/


All Articles