【问题标题】:Issue with redundant if statements that can have multiple answers可能有多个答案的冗余 if 语句的问题
【发布时间】:2020-01-19 19:19:46
【问题描述】:

我必须编写一个程序,该程序利用方法重载来计算圆柱体、球体、圆锥体和三棱柱的表面积和体积。我需要接受用户的输入,然后显示正确的表面积和体积。

程序应该做的一个例子是:

Input your shape’s “a” value: none
Input your shape’s “b” value: none
Input your shape’s “c” value: none
Input your shape’s “h” value: none
Input your shape’s “l” value: none
Input your shape’s “r” value: 5
Input your shape’s “s” value: none
Would you like your answer rounded?: yes
To what decimal place?: 0
---------------------------------------------------------------------
Your shape is a sphere!
It’s volume is 524 units cubed.
It’s surface area is 314 units squared.

我已经编写了程序的大部分代码,但是我现在遇到的问题是,每当我完成输入数据时,都会收到错误消息:“线程中的异常”main“java.util.NoSuchElementException:找不到行”。我怀疑问题出在我用来过滤用户给我的内容的 if 语句上,因为每个语句都可以多次出现相同的异常。因此,如果我想计算球体的体积,我需要的唯一输入是半径 r 的输入,而其他所有输入都没有。但是对于圆柱体,除了半径 r 和高度 h 之外,所有其他的都不是。任何帮助将不胜感激。

这是我目前的代码:

import java.util.*;

class Main {

 String a = "none"; String b = "none"; String c = "none"; String h = "none"; String r = "none"; String s = "none"; String l = "none";
 String round;
 double aP; double bP; double cP; double hP; double rP; double sP; double lP;

 public static void main(String[] args) throws Exception{
   new Main();
 }//end main

 public Main() throws Exception{
   input();
   surfaceAreaPrint();
   volumePrint();

 }//end Main

 /**
  *
  */
 public void input() throws Exception{
   Scanner sc = new Scanner(System.in);
   System.out.print("");
   System.out.print("Input your shape’s “a” value: ");
   a = sc.nextLine();
   System.out.print("Input your shape’s “b” value: ");
   b = sc.nextLine();
   System.out.print("Input your shape’s “c” value: ");
   c = sc.nextLine();
   System.out.print("Input your shape’s “h” value: ");
   h = sc.nextLine();
   System.out.print("Input your shape’s “r” value: ");
   r = sc.nextLine();
   System.out.print("Input your shape’s “s” value: ");
   s = sc.nextLine();
   System.out.print("Input your shape’s “l” value: ");
   l = sc.nextLine();
   System.out.print("Would you like your answer rounded?: ");

   round = sc.nextLine();

   System.out.print("");
   System.out.print("");

   sc.close();
   parse();

 }//end input

  public void parse() throws Exception{
    System.out.println(a);
   aP = Double.parseDouble(a);
   bP = Double.parseDouble(b);
   cP = Double.parseDouble(c);
   hP = Double.parseDouble(h);
   rP = Double.parseDouble(r);
   sP = Double.parseDouble(s);
   lP = Double.parseDouble(l);

//cylinder
  if(a == "none" && b == "none" && c == "none" && s == "none" && l != "none") {
      surfaceAreaPrint();
      return;
    }

   //sphere
   else if (a.equalsIgnoreCase("none") && b.equalsIgnoreCase("none") && c.equalsIgnoreCase("none") && s.equalsIgnoreCase("none") && h.equalsIgnoreCase("none") && s.equalsIgnoreCase("none") && l.equalsIgnoreCase("none")){
surfaceAreaPrint();
return;

  }

  //cone
  else if (a.equalsIgnoreCase("none") && b.equalsIgnoreCase("none") && c.equalsIgnoreCase("none") && s.equalsIgnoreCase("none") && h.equalsIgnoreCase("none") && l.equalsIgnoreCase("none")){
     surfaceAreaPrint();
     return;
  }
  //traingular prism
  else if (r.equalsIgnoreCase("none") && s.equalsIgnoreCase("none")){
surfaceAreaPrint();
return;
   }


 }//end parse

 public void surfaceAreaPrint() throws Exception{
   Main s = new Main(); 
   System.out.println(s.surfaceArea(hP, rP));
   System.out.println(s.surfaceArea(rP));
   System.out.println(s.surfaceArea(hP, rP, sP));
   System.out.println(s.surfaceArea(aP, bP, cP, lP, hP));

 }//end surfaceAreaPrint

  public void volumePrint() throws Exception{
   Main s = new Main(); 
   System.out.println(s.surfaceArea(hP, rP));
   System.out.println(s.surfaceArea(rP));
   System.out.println(s.surfaceArea(hP, rP)); 
   System.out.println(s.surfaceArea(bP, lP, hP)); 

 }//end volumePrint

 //surface area for cylinder
 public double surfaceArea(double hP, double rP){
   return (2.0 * Math.PI * Math.pow(rP, 2.0)) + (2.0 * Math.PI * rP * hP);

 }//end surfaceArea

 //surface area for sphere
 public double surfaceArea(double rP){
   return (4.0 * Math.PI * Math.pow(rP, 2.0));

 }//end surfaceArea

 //surface area for cone
 public double surfaceArea(double hP, double rP, double sP){
   return (Math.PI * Math.pow(rP, 2.0)) + (Math.PI * rP * sP);

 }//end surfaceArea

   //surface area for traingular prism
 public double surfaceArea(double aP, double bP, double cP, double lP, double hp){
   return (bP * lP) + (aP * hP) + (bP * hP) + (cP* hP);

 }//end surfaceArea


 //volume for cylinder
 public double volume(double hP, double rP){
   return (Math.PI * Math.pow(rP, 2.0) * hP);

 }//end volume
 //volume for sphere
 public double volume(double rP){
   return ( 4.0 / 3.0 ) * Math.PI * Math.pow(rP, 3.0);

 }//end volume

 //volume for cone
 public double volume(double hP, double rP, double sP){
   return (1.0 / 3.0 ) * Math.PI * Math.pow(rP, 2.0) * hP;

 }//end volume

   //volume for traingular prism
  /**
   * calculates volume for traingular prism
   * @param times The number of times the die is to be rolled.
   * @return The results of rolling a 6-sided die.
   */
 public double volume(double aP, double bP, double cP, double lP, double hp){
   return (1.0 / 2.0 ) * bP * lP * hP;

 }//end volume

}//end Main

【问题讨论】:

    标签: java if-statement exception overloading calculator


    【解决方案1】:

    TL;DR

    • 在多个 if else 块中调用相同的方法是多余的(直到它们没有返回,所以仍然可以调用所需的方法)
    • 很多时候,长 if 条件可以简化,如果不是,最好将条件移动到附加方法 boolean isAThingIWant(..params) 以保持可读性
    • 不应在构造函数中调用“业务逻辑”方法
    • 在成员方法中创建相同类的新对象可能会导致不必要的递归调用
    • 使用System.in InputStream 关​​闭 Scanner 对象会禁止以后从该流中读取(请参阅this
    • 尝试将Double.parseDouble 与任何不是数字的字符串一起使用将导致NumberFormatException,即使对于工程符号也是如此
    • OP 示例是一个单独的问题,但在设计类时,应使用适当的封装
    • 通常的做法是使用特定语言的编码标准(参见this
    • 解决此问题的 OOP 方法是使用形状接口和实现它的其他类 - 这将允许利用继承和多态性的优势

    原文:
    最简单的解决方法是从下面的方法中删除Main s = new Main();,并为当前创建的对象使用this 引用,如下所示:

        public void surfaceAreaPrint() throws Exception{
    //        Main s = new Main();
            System.out.println(this.surfaceArea(hP, rP));
            System.out.println(this.surfaceArea(rP));
            System.out.println(this.surfaceArea(hP, rP, sP));
            System.out.println(this.surfaceArea(aP, bP, cP, lP, hP));
    
        }//end surfaceAreaPrint
    
        public void volumePrint() throws Exception{
    //        Main s = new Main();
            System.out.println(this.surfaceArea(hP, rP));
            System.out.println(this.surfaceArea(rP));
            System.out.println(this.surfaceArea(hP, rP));
            System.out.println(this.surfaceArea(bP, lP, hP));
    
        }//end volumePrint
    

    实际上,您的示例中有几个问题和代码异味。

    另一件事是,您仍在使用parse 方法中的if 语句将字符串与== 进行比较 - 使用euqals or equalsIgnoreCase

    如果您的尝试实际上是在上述方法中从用户那里获取新输入,那么您将无法关闭扫描仪,因为使用 System.in 关闭它会关闭它后面的 InputStream,因此它不再接受任何内容。我认为删除 sc.close() 可能会导致您遇到不同的异常和问题(例如,程序无法按您的意愿运行)。

    任何else if 中的每条指令都使用相同的方法。因此整个if else if 是多余的。

    编辑:
    刚刚检查了删除sc.close() 并保持其余部分在您的示例中将导致无限获取用户输入,因为在surfaceAreaPrint 中创建了新的 Main 对象并且输入是从 Main 的构造函数调用的,所以它变成递归调用。

    对于重载方法的使用,你可以这样简单:

    //cylinder
    if(a.equalsIgnoreCase ("none") && b.equalsIg... rest of your if) {
        System.out.println(this.surfaceArea(hP, rP));
    }
    

    但请注意,当您在输入值并使用sc.nextLine() 读取它们时只需按Enter 键,分配的值不会保持为none,而是会变成像"" 这样的空字符串,这将抛出NumberFormatException稍后在Double.parseDouble 中的任何一个。

    编辑2:
    现在,我看到您希望在不使用该特定变量时严格输入“none”,因此为避免NumerFormatException,您必须在检查字符串是否不是“none”后将值解析为 double。

    您可以通过更改检查是否等于“无”来简化 if 语句:

    //for cylinder
    if(!h.equalsIgnoreCase("none") && !r.equalsIgnoreCase("none") {
    //....
    

    对于实际几何对象的表面/体积的计算,您可以假设定义其大小的值应为>=0,因此为了更简单的解析可以使用这种方法:

    public double inputParser(String s) {
        try {
            return Double.parseDouble(s);
        } catch (NumberFormatException e) {
            return -1;
        }
    }
    //and used instead of straight `Double.parseDouble`:
    aP = inputParser(a);
    bP = inputParser(b);
    //which simplifies the `if` even more to:
    if(hP != -1 && rP != -1) { //cylinder
        System.out.println(this.surfaceArea(hP, rP));
    }
    
    

    编辑3:
    经过几分钟的讨论并发现了 OP 代码中的一些其他缺陷,我提出了一个解决方案:

    import java.util.*;
    class Main {
    
        String a, b, c, h, r, s, l;
        String round;
        double aP; double bP; double cP; double hP; double rP; double sP; double lP;
    
        public static void main(String[] args) {
            Main m = new Main();
            m.input();
            m.parse();
            m.calculate();
        }
    
        public void input() {
            Scanner sc = new Scanner(System.in);
            System.out.print("");
            System.out.print("Input your shape’s “a” value: ");
            a = sc.nextLine();
            System.out.print("Input your shape’s “b” value: ");
            b = sc.nextLine();
            System.out.print("Input your shape’s “c” value: ");
            c = sc.nextLine();
            System.out.print("Input your shape’s “h” value: ");
            h = sc.nextLine();
            System.out.print("Input your shape’s “r” value: ");
            r = sc.nextLine();
            System.out.print("Input your shape’s “s” value: ");
            s = sc.nextLine();
            System.out.print("Input your shape’s “l” value: ");
            l = sc.nextLine();
            System.out.print("Would you like your answer rounded?: ");
    
            round = sc.nextLine();
            System.out.println("");
    
            sc.close();
        }
    
        public void parse() {
            System.out.println(a);
            aP = inputParser(a);
            bP = inputParser(b);
            cP = inputParser(c);
            hP = inputParser(h);
            rP = inputParser(r);
            sP = inputParser(s);
            lP = inputParser(l);
        }
    
        public void calculate() {
            if(hP != -1 && rP != -1) {
                System.out.println("Cylinder");
                System.out.println(this.rounding(this.surfaceArea(hP, rP)));
                System.out.println(this.rounding(this.volume(hP, rP)));
            }
            if (rP != -1){
                System.out.println("Sphere");
                System.out.println(this.surfaceArea(rP));
                System.out.println(this.volume(rP));
            }
            if (hP != -1 && rP != -1 && sP != -1){
                System.out.println("Cone");
                System.out.println(this.surfaceArea(hP, rP, sP));
                System.out.println(this.volume(hP, rP, sP));
            }
            if (aP != -1 &&  bP != -1 &&  cP != -1 &&  lP != -1 &&  hP != -1){
                System.out.println("Triangular prism");
                System.out.println(this.surfaceArea(aP, bP, cP, lP, hP));
                System.out.println(this.volume(aP, bP, cP, lP, hP));
            }
        }
        public double rounding(double value) {
            if ("yes".equalsIgnoreCase(round)) {
                return Math.round(value);
            }
            return value;
        }
        public double inputParser(String s) {
            try {
                return Double.parseDouble(s);
            } catch (NumberFormatException e) {
                return -1;
            }
        }
        //surface area for cylinder
        public double surfaceArea(double hP, double rP){
            return (2.0 * Math.PI * Math.pow(rP, 2.0)) + (2.0 * Math.PI * rP * hP);
    
        }//end surfaceArea
    
        //surface area for sphere
        public double surfaceArea(double rP){
            return (4.0 * Math.PI * Math.pow(rP, 2.0));
    
        }//end surfaceArea
    
        //surface area for cone
        public double surfaceArea(double hP, double rP, double sP){
            return (Math.PI * Math.pow(rP, 2.0)) + (Math.PI * rP * sP);
    
        }//end surfaceArea
    
        //surface area for traingular prism
        public double surfaceArea(double aP, double bP, double cP, double lP, double hp){
            return (bP * lP) + (aP * hP) + (bP * hP) + (cP* hP);
    
        }//end surfaceArea
    
    
        //volume for cylinder
        public double volume(double hP, double rP){
            return (Math.PI * Math.pow(rP, 2.0) * hP);
    
        }//end volume
        //volume for sphere
        public double volume(double rP){
            return ( 4.0 / 3.0 ) * Math.PI * Math.pow(rP, 3.0);
    
        }//end volume
    
        //volume for cone
        public double volume(double hP, double rP, double sP){
            return (1.0 / 3.0 ) * Math.PI * Math.pow(rP, 2.0) * hP;
    
        }//end volume
    
        //volume for traingular prism
        public double volume(double aP, double bP, double cP, double lP, double hp){
            return (1.0 / 2.0 ) * bP * lP * hP;
    
        }//end volume
    
    }//end Main
    

    仍然不是最好的,有封装、变量命名等问题,但很好地涵盖了问题。

    【讨论】:

    • 感谢您的回复,我已经实施了您提供的建议,并且还尝试使用 sc.hasNextLine(),但不幸的是仍然遇到相同的错误。我想我现在明白所有 else if 语句都是多余的,所以我现在的问题是如何调用正确的重载方法来计算正确的表面积和体积?任何更多的帮助将是巨大的。
    • @mrgasmaskdude 在将 surfaceAreaPrintvolumePrint 更改为我提供的之后,您是否收到 NoSuchElementException?
    • 我已经进行了指定的更改,但不幸的是代码仍然无法正常工作。对于我所做的几乎所有其他方法分配,这都有效,但由于某种原因,这仍然无效。
    • @mrgasmaskdude ehh, k,我可以看一下,把它贴在某种 pastebin 上
    • 是否可以只给你一个代码本身的链接?
    猜你喜欢
    • 2014-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-21
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    相关资源
    最近更新 更多