【问题标题】:Using nested if statements in Java to calculate letter grade from numeric input在 Java 中使用嵌套 if 语句从数字输入中计算字母等级
【发布时间】:2020-09-12 20:47:57
【问题描述】:

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

我收到的输出从 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);        
    }
}

【问题讨论】:

  • 为什么grade1note 的类型是byte 而不是char
  • byte 是整数类型,即表示整数。因此,如果我们打印一个byte,它就会被打印为一个数字。您可能想要的是char 而不是byte。旁注:我们也可以使用chars 作为数字,然后我们得到字符的unicode UTF-8 数值。

标签: java nested-if


【解决方案1】:

else if ( grade &lt;= 80 &amp;&amp; grade &gt;= 89 ) {

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

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

翻转你的&lt;&gt; 标志:)

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

【讨论】:

  • 非常感谢。这是我的第一堂编程课,到目前为止,在我们完成的几乎所有程序中,我们只使用了 int、byte 和 double。我确信在一开始的某个时候提到过那些只返回数字,但我不记得有具体说过,而且我的任何课堂幻灯片或笔记中都没有。数学 只是纯粹的疏忽,经过数小时的研究,我什至没有注意到。非常感谢您的反馈!
【解决方案2】:

我觉得这有点乱。

是的,条件语句往往会产生这种效果。对于具有许多分支的代码,术语是“高cyclomatic complexity”,对于具有大量重复的代码,术语是WET(请注意其中有许多带有note = '-';note = '+'; 的分支——这些大部分可以移出一个分行,确定字母等级后追加)。

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

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

还要注意,代码已从 main 移出到一个可重用的函数中,我们可以根据需要多次调用。用户输入/交互是一个完全独立的模块,最好尽可能将decoupled 与程序逻辑分开。

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

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+

【讨论】:

    【解决方案3】:

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

    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),那么在在这种特殊情况下,检查

    当然,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 方法来获取密钥的适当等级。它通过返回与大于或等于给定键的最小键关联的键值映射来工作,如果没有这样的键,则返回 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-
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多