使用 Java 中的嵌套 if 语句根据数字输入计算字母等级

Using nested if statements in Java to calculate letter grade from numeric input

我的家庭作业是创建一个程序,该程序接受 0-100 和 return 之间的数字输入一个字母和 +/-(如果合适)。我们将使用嵌套的 if 语句来完成此操作。我试图创建一个外部 if 语句,该语句将 return 一个字母等级,然后是嵌套的 if 语句,该语句将 return +/- 部分。

我收到的输出从 6543 到 00 不等。我已经在下面复制了我的代码。谁能指出我正确的方向?我觉得这有点乱。

import java.util.Scanner;
import java.lang.Math;

public class Grade {
    public static void main (String [] args) {

        Scanner scan = new Scanner (System.in);

//Prompt user to enter grade

        System.out.println("Please enter your grade ");
        int grade = scan.nextInt();
        byte grade1 = (0);
        byte note = (0);

//Determine letter and +/-

        if ( grade <= 100 && grade >= 90 ) {
            grade1 = 'A';
            if (grade <= 100 && grade >= 96) {
                note = '+';
            }
            else if (grade <= 94 && grade >= 90) {
                note = '-';
            }
        }

        else if ( grade <= 80 && grade >= 89 ) {
            grade1 = 'B';
            if (grade <= 89 && grade >= 86) {
                note = '+';
            }
            else if (grade <= 84 && grade >= 80) {
                note = '-';
            }
        }

        else if ( grade <= 70 && grade >= 79 ) {
            grade1 = 'C';
            if (grade <= 79 && grade >= 76) {
                note = '+';
            }
            else if (grade <= 74 && grade >= 70) {
                note = '-';
            }
        }        

        else if ( grade <= 60 && grade >= 69 ) {
            grade1 = 'D';
            if (grade <= 69 && grade >= 66) {
                note = '+';
            }
            else if (grade <= 64 && grade >= 60) {
                note = '-';
            }
        }

        else if ( grade <= 59 ) {
            grade1 = 'F';
        }

//Print out grade

        System.out.println("You have a " + grade1 + note + " in the class.");

// End program
        scan.close();
        System.exit(0);        
    }
}

else if ( grade <= 80 && grade >= 89 ) {

花点时间想一想。我想你打算例如85导致这个if触发,对。

85是否小于或等于80?我不认为是。它也不是89或更高。事实上,没有数字会满足这个条件

翻转你的 <> 标志 :)

第二个问题是 grade1 和 note 是字节,它们是数字,所以“你有一个”+(一些数字)+(一些其他数字)+“在 class”总是会打印“您在 class 中有一个 12345677”,也就是说,这些东西是数字。我不知道你为什么认为 byte 会在这里锻炼。再试一次char

这是另一个可以让您降低代码复杂性的建议。只要您按升序评估数字等级,就不需要低和高范围。

if (grade >= 90) {
    // you know it's an A so decide what type
    grade1 = 'A';
    if (grade >= 96) {
        note = '+';
    } else if (grade <= 94) {
      // note that here it can'be less than 90 since you're
      // already in the >= 90 conditional block
        note = '-';
    }
// it wasn't an A so continue on
} else if (grade >= 80) {
   // must be a B so determine what type
    grade1 = 'B';

    // Can't be >= 90 since you already processed that case.
    // Had it succeeded, you wouldn't be here.
    if (grade >= 86) {
        note = '+';
    } else if (grade <= 84) {
    // can't be less than 80 since you are in 
    // the >= 80 conditional block.
        note = '-';
    }
    // so continue on in that manner.

} else if (grade >= 70) {
...
...

由于您是编程新手,上述内容可能有点难以理解。但最终会清楚它为什么有效。

注意:在上面的第一种情况下,当检查 A 时,它不会检查上限,因为它假定任何大于 90 的都是 A。如果您需要检查错误输入(例如 2973)那么在那种特殊情况下,检查 <= 100.

可能是合适的

当然,Java 中还有其他工具可以简化这一过程。这是一个使用 TreeMap 的示例。映射只是通过 key 将一个值与另一个值相关联。 TreeMaps 有额外的方法来访问相对于给定键或键本身的值。

TreeMap<Integer,String> map = new TreeMap<>();
String grades = "DCBA";

使用键作为阈值并使用值作为等级输入成绩。明确添加最终成绩。其他人被添加到他们范围的顶部。选择的等级是索引 i/10-6 处的字符,并为给定范围附加了适当的后缀。

map.put(100,"A+");
map.put(59, "F");
for (int i = 65; i <= 100; i+= 10) {
    String grade = grades.charAt(i/10-6)+"";
    map.put(i+4, grade+"+");
    map.put(i, grade);
    map.put(i-1,grade+"-");
}

困难的部分已经完成。现在您可以使用 TreeMap#ceilingEntry 方法为密钥获取适当的等级。它的工作原理是返回与大于或等于给定键的最小键关联的 key-value 映射,如果没有这样的键,则返回 null。

以下打印从 100 到 80(含)的数字分数的等级。

for (int i = 100; i >= 80; i--) {
    System.out.println( i + " " + map.ceilingEntry(i).getValue());
}

版画

100 A+
99 A+
98 A+
97 A+
96 A+
95 A
94 A-
93 A-
92 A-
91 A-
90 A-
89 B+
88 B+
87 B+
86 B+
85 B
84 B-
83 B-
82 B-
81 B-
80 B-

I feel like this is a bit of a mess.

是的,条件语句往往会产生这种效果。对于重复次数多的代码,这些术语是“高cyclomatic complexity" for code with many branches and WET”(请注意其中有多少分支带有note = '-';note = '+';——这些大部分可以移出到一个分支中并附加在后面确定字母等级)。

虽然最初编写这样的代码很有启发性(在本例中是必需的),但很高兴看到有更好的方法来实现该结果。讨厌的分支逻辑的典型解决方案是找到一个模式并使用某种查找 table。在这种情况下,字符串 "FFFFFFDCBAA" 让我们通过将分数除以 10 并索引到字符串中来枚举 5 个可能的成绩桶。我们可以确定 +/-,方法是将分数的模数乘以可用等级桶的数量,以查看它落在 0-10 范围内的哪个位置。

这是一个包含一些测试的完整示例。它并非完美无缺,并且有一些烦人的边缘情况需要为其编写明确的条件,但我们已经设法将十几个嵌套的 error-prone 分支减少到 2 个(添加了第三个分支来测试先决条件)。

另请注意,代码已从 main 移出到一个可重复使用的函数中,我们可以根据需要多次调用。用户 input/interaction 是一个完全独立的模块,最好尽可能 decoupled 与程序逻辑保持独立。

我还努力将 magic numbers 尽可能地排除在代码之外,将它们降级为函数顶部的常量。在某些用例中,这些可能是使我们的功能更适应的参数table,但似乎可以肯定的是,分级系统在此应用程序的生命周期内是固定的。

class Grader {
    public static String getGrade(int score) {
        final int MAX_SCORE = 100;
        final int MIN_SCORE = 0;
        final var GRADES = "FFFFFFDCBAA";
        final int BUCKETS = GRADES.length() - 1;

        if (score < MIN_SCORE || score > MAX_SCORE) {
            var msg = "score must be between " + MIN_SCORE + 
                      " and " + MAX_SCORE + " inclusive";
            throw new IllegalArgumentException(msg);
        }

        final char letter = GRADES.charAt(score / BUCKETS);
        final int adjustment = score % BUCKETS - BUCKETS / 2;

        if (adjustment == 0 || letter == GRADES.charAt(0)) {
            return "" + letter;
        }

        return letter + (adjustment < 0 && score != MAX_SCORE ? "-" : "+");
    }

    public static void main(String[] args) {
        var tests = new int[] {
            0, 16, 59, 60, 72, 75, 89, 90, 93, 95, 96, 100
        };

        for (int test : tests) {
            System.out.println(test + " => " + getGrade(test));
        }
    }
}

输出:

0 => F
16 => F
59 => F
60 => D-
72 => C-
75 => C
89 => B+
90 => A-
93 => A-
95 => A
96 => A+
100 => A+