为什么此代码不能按预期工作



我正在编写一个简单的方法,该方法将分数作为用户的输入,并计算分数点平均值。这是我的代码:

public static double calculateGPA(){
Scanner in = new Scanner(System.in);
double totalGradePoints = 0; // total grade points
int numClasses = 0; // total classes completed
boolean doneInput = false; // returns true when use is done inputting grades
System.out.println("Enter all your grades (A,B,C,D,F) and enter 'done' if you are done entering your grades.");  
while (!doneInput) {     
String grade = in.next();
if (grade == "A") {
totalGradePoints += 4;
numClasses++;
} else if (grade == "B") {
totalGradePoints += 3;
numClasses++;
} else if(grade == "C") {
totalGradePoints += 2;
numClasses++;
} else if(grade == "D") {
totalGradePoints += 1;
numClasses++;
} else if(grade == "F") {
numClasses++;
} else {
doneInput = true;
} //end if - else-if - else statement
}//end while loop
double unwtGPA = (totalGradePoints/numClasses);
return unwtGPA;
}

当我测试这个方法时,我只能输入一个等级,没有一个变量增加,有人能告诉我代码出了什么问题吗?

问题在于使用==而不是equals进行字符串比较。==比较了不太可能相等的参考文献。更改为

if(grade.equals("A")){
totalGradePoints += 4;
numClasses++;
}else if(grade.equals("B")){ ...

它应该起作用。有关详细解释,请参阅此答案。

作为一种好的做法,建议始终使用静态字符串作为调用equals的对象,以防止NPE:

if("A".equals(grade)){
totalGradePoints += 4;
numClasses++;
}else if("B".equals(grade)){ ...

如果你使用的是Java7,你也可以用字符串做一个switch语句(尽管如果等级为null,这个语句会抛出一个NPE):

switch(grade) {
case "A":
totalGradePoints += 2;
numClasses++;
break;
case "B":
...
}

最后,由于您只将一个字母转换为整数,所以最好的解决方案是将它们转换为char,并将AD之间的值转换为totalGradePoints += ('D' - grade.charAt(1)) + 1。因此,按照这些思路阅读IMO最简单:

while (true) {        
final String input = in.next();
if(input == null || input.isEmpty())
break;
final char grade = input.charAt(0);
if(grade >= 'A' && grade <= 'D') {
totalGradePoints += ('D' - grade) + 1;
} else if(grade == 'F') {
// no gradepoints for 'F'
} else {
break;
} //end if - else-if - else statement
++numClasses;
} //end while loop

问题是使用==来比较字符串,而应该使用s.equals("...")==运算符检查标识,字符串不能保证具有相同的标识(可能有几个对象表示完全相同的字符串)。equals()方法比较字符串的内容是否相等,而不是对象的标识。

我会写得更像这样:

Scanner in = new Scanner(System.in);
double totalGradePoints = 0; // total grade points
int numClasses = 0; // total classes completed
System.out.println("Enter all your grades (A,B,C,D,F) and"
+ " write 'done' when you have finished");
while (true) {
String input = in.next();
if (input.equals("done")) {
break;
}
if (input.equals("A")) {
totalGradePoints += 4;
} else if (input.equals("B")) {
totalGradePoints += 3;
} else if (input.equals("C")) {
totalGradePoints += 2;
} else if (input.equals("D")) {
totalGradePoints += 1;
} else if (!input.equals("F")) {
System.err.println("Invalid input: " + input);
continue;
}
numClasses++;
}
double unweightedGPA = (totalGradePoints / numClasses);
System.out.println(unweightedGPA);

带有break(退出循环)和continue(跳回到循环的开始)的while(true)循环是更惯用的Java。我上面版本的主要好处是没有numClasses++行的重复。

您甚至可以通过使用Map使循环更加简洁,并使更改分数变得更简单,Map将返回分数的点值,或返回无效分数的null

Map<String, Integer> gradePoints = new HashMap<String, Integer>() {{
put("A", 4);
put("B", 3);
put("C", 2);
put("D", 1);
put("F", 0);
}};
String input;
while (!(input = in.next()).equals("done")) {
Integer points = gradePoints.get(input);
if (points == null) {
System.err.println("Invalid input: " + input);
continue;
}
totalGradePoints += points;
numClasses++;
}

同样值得指出的是,在你的代码和本页上的所有答案中,如果你不输入任何分数,你将被零除(产生NaN),所以你可能需要考虑优雅地处理这一问题。

您的失败是使用==运算符检查Strings是否相等。字符串是对象,因此在这种情况下,将对对象标识进行检查(默认为引用检查)。

使用equals进行逐字符检查,如下所示:

if(grade.equals("A")){

最新更新