首页 > 解决方案 > 如何在循环循环后获取用户输入以允许另一个输入?

问题描述

我对Java相当陌生。我已经完成了一些 C++,所以我理解了很多概念。我一直在研究这段代码,它允许我在小费计算器上要求输入。我知道有些代码不一致,但这是因为我一直在尝试各种方法来显示它。

一旦要求用户输入,我就可以通过该程序。但是,当我再次遍历它时,它只会显示我之前输入的相同输入。我试图让它显示然后循环,接受新的输入并显示它。我一直在自学这一点,所以这对我来说是一次学习经历,但是我很困惑,不知道从哪里开始。任何帮助表示赞赏。

import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.InputMismatchException;
import java.util.Scanner;

public class TipApp {

    public static void main(String[] args) {
        calculateTips();
    }

    public static void calculateTips () {
        Scanner input = new Scanner(System.in);
        Scanner scan = new Scanner(System.in);
        String pattern = "$##,###,###.00;"; // Pattern string for the decimal format
        DecimalFormat moneyFormat = new DecimalFormat(pattern); // Decimal Money format
        NumberFormat defaultFormat = NumberFormat.getPercentInstance();
        defaultFormat.setMinimumFractionDigits(1);
        String choice;
        double theBill;
        int theTip;
        int thePartySize;
        boolean isBillValid = true;
        boolean isTipValid = true;
        boolean isPartySizeValid = true;
        TipCalculator tipCalculator1 = new TipCalculator();
        System.out.println("*** Tip Calculator ***");

        do {
            System.out.print("\nEnter the bill amount: ");
            while (isBillValid) {
                try {
                    if (input.hasNextDouble()) {
                        theBill = input.nextDouble();
                        isBillValid = false;
                        tipCalculator1.setBillAmount(theBill);
                    }
                } catch (InputMismatchException e) {
                    System.out.println(input.next() + " is not a valid number");
                }
                input.nextLine();
            }

            System.out.print("Enter your desired tip percentage (20 equals 20%): ");
            while (isTipValid) {
                if (input.hasNextInt()) {
                    theTip = input.nextInt();
                    isTipValid = false;
                    tipCalculator1.setTipPercentage(theTip);
                } else {
                    System.out.println("Please enter a valid tip percentage.");
                    isTipValid = true;
                }
                input.nextLine();
            }

            System.out.print("Enter the size of your party: ");
            while (isPartySizeValid) {
                if (input.hasNextInt()) {
                    thePartySize = input.nextInt();
                    isPartySizeValid = false;
                    tipCalculator1.setPartyAmount(thePartySize);
                } else {
                    System.out.println("Please enter a valid party size.");
                    isPartySizeValid = true;
                }
                input.nextLine();
            }

            System.out.println("*** Your Bill ***");
            System.out.print("\nBill Amount: ");
            System.out.println(moneyFormat.format(tipCalculator1.getBillAmount()));
            System.out.print("Tip Percentage: ");
            System.out.println(defaultFormat.format(tipCalculator1.getTipPercentage()));
            System.out.print("Party Size: ");
            System.out.println(tipCalculator1.getPartyAmount());
            System.out.print("\nTotal Bill (with Tip): ");
            System.out.print(moneyFormat.format(tipCalculator1.getTotalAmount()));
            System.out.print("\nShare for Each Individual: ");
            System.out.print(moneyFormat.format(tipCalculator1.getIndividualShare()));
            System.out.print("\nAnother Bill? (y/n): ");
            choice = scan.nextLine();

        } while (choice.equalsIgnoreCase("y")) ;
        System.out.println("\nGoodbye!");
    }
}

public class TipCalculator {
    private double billAmount;
    private int tipPercentage;
    private int partyAmount;


    // Constructor that holds 3 arguments
    public TipCalculator() {
        setBillAmount(billAmount);
        setTipPercentage(tipPercentage);
        setPartyAmount(partyAmount);
    }

    public double getBillAmount() {
        return billAmount;
    }

    public void setBillAmount(double billAmount) {
        this.billAmount = billAmount;
    }

    public double getTipPercentage() {
        return tipPercentage / 100f;
    }

    public void setTipPercentage(int tipPercentage) {
        this.tipPercentage = tipPercentage;
    }

    public int getPartyAmount() {
        return partyAmount;
    }

    public void setPartyAmount(int partyAmount) {
        this.partyAmount = partyAmount;
    }

    public double getIndividualShare() {
        return (getTotalAmount() / partyAmount);
    }

    public double getTotalAmount() {
        return (billAmount * getTipPercentage()) + billAmount;
    }
}

  [1]: https://i.stack.imgur.com/5tHIs.png

标签: javaloopsjava.util.scanneruser-input

解决方案


首先,只使用一个 Scanner 对象,您不需要更多。也许名字是userInput

您遇到的问题是因为您没有为下一个要计算的账单重置一些关键变量,特别是那些在循环条件中使用的变量。

取以下变量:

boolean isBillValid = true;
boolean isTipValid = true;
boolean isPartySizeValid = true;
double theBill;
int theTip;
int thePartySize;

并将它们移动到您的do循环(主外循环)的顶部并初始化 String 变量选择以保存空字符串(“”),例如:

do {
    choice = "";
    boolean isBillValid = false;
    boolean isTipValid = false;
    boolean isPartySizeValid = false;
    double theBill = 0.0d;
    int theTip = 0;
    int thePartySize = 0;
    System.out.print("\nEnter the bill amount: ");
    while (isBillValid) {
        try {
            //..... The rest of your code ....

这样,如果用户输入“y”来处理另一个帐单,则不会从前一个帐单中设置循环的条件。

在我看来,每个需要用户输入某种形式的提示都应确保有效输入,这将包括Another Bill? (y/n):提示,例如:

while (choice.isEmpty()) {
    System.out.print("\nAnother Bill? (y/n): ");
    choice = userInput.nextLine();
    // Is only a 'y' or a 'n' supplied (regardless of letter case) 
    if (!choice.matches("(?i)[yn]")) {
        // No...inform User and have him her try again.
        System.out.println("Invalid input - 'y' or 'n' only! Try again...");
        choice = "";  // Reset the 'choice' variable to null string.
    }
}

上述代码中的 if 语句条件使用了String # matches()方法以及一个小的正则表达式(RegEx)。在正则表达式字符串中,(?i)表示“忽略字母大小写”,表示:[yn]匹配“y”或“n”字符。因此,如果提供的选项不匹配, , ,或则条件为trueyYnN

这种验证应该适用于您对用户的所有提示,以确保用户的无故障体验,毕竟,错字确实会发生。以小费百分比条目为例,如果用户输入-10? 会发生什么。如果您正在申请折扣券或其他东西,这将是可以的,但对于小费来说不是那么多。我认为用户最好输入一个特定范围内的值,例如 0 到 100(或您喜欢的任何值):

while (!isTipValid) {
    System.out.print("Enter your desired tip percentage (0 to 100): --> ");
    try {
        theTip = userInput.nextInt();
        // Is the tip percentage inclusively between 0 and 100?
        if (theTip < 0 || theTip > 100) {
             // No...
             throw new java.util.InputMismatchException();
        }
        isTipValid = true;
        tipCalculator1.setTipPercentage(theTip);
    } 
    catch (java.util.InputMismatchException ex) {
        System.out.println("Invalid tip percentage supplied (" + theTip + ")! Try again...");
    }
    userInput.nextLine();
}

在上面的示例循环代码中,您很可能会注意到这里做了一些不同的事情。

首先,while循环的条件更好地表示布尔变量的名称isTipValid。变量名在某种意义上更像是一个问题:提示有效吗?. 默认情况下,您将此变量初始化为true,这基本上就像说"Yes, the Tip is Valid!"实际上尚未建立时一样。为了更清楚起见,我认为这个变量(和其他类似的变量)应该初始化为布尔值false,然后只有在确定提供的值确实有效后才更改为布尔值true

您可能已经注意到的另一个变化是控制台窗口的显示提示字符串被放置在while循环内而不是在其上方。这确保了如果出现无效情况并且提示需要进一步输入,那么用户肯定会知道所请求的内容。最好将所有提示机制包含在与其相关的while循环中。提示字符串也进行了修改,以向用户指示需要 0 到 100 范围内的值。

您可能已经注意到的另一个变化是该if (input.hasNextInt()) {行已被替换为Try/Catch机制。这实际上提供了一种更明确的方法来确保正确的数据输入,因为Scanner#hasNextInt()方法(和其他 hasNext...() 方法)更适合标记化输入,而分隔的整数系列可能包含或组合在其中那个输入。它当然可以在这个用例中使用,但需要额外的处理以适应所有可能的无效情况。

您还将看到一个额外的if语句,用于检查提供的值是否在所描述的 0 到 100 范围内。如果不是,则抛出InputMismatchException强制代码流立即落入最终向用户指示问题并重新提示另一个值的catch子句。

与其他提示类似地执行上述操作将产生更好的结果,并且您将知道提供的值将是有效的,但 Bil Amount 提示除外:

while (!isBillValid) {
    System.out.print("Enter the bill amount: --> ");
    try {
        theBill = userInput.nextDouble();
        if (theBill < 0) {
            throw new java.util.InputMismatchException();
        }
        isBillValid = true;
        tipCalculator1.setBillAmount(theBill);
    } catch (java.util.InputMismatchException e) {
       System.out.println("Invalid Bill amount supplied (" + theBill + ")! Try again...");
    }
    userInput.nextLine();
}

这适用于几乎所有无效的可能性,除了这个简单的错字:3e4示例。Scanner#nextDouble() 方法认为这是一个有效的双精度值。提供的值中的eor被认为是科学 E 表示法中的值,并且在其绘制状态下与30000.0的双精度值相同。因此,最终不是预期的 34 美元钞票,而是一张真正健康的 30,000.00 美元钞票。为了解决这种情况,需要使用稍微不同的方法。在下面的代码中,您不仅会看到账单金额提示代码是如何使用这种不同的方法完成的,还会看到所有其他提示:E3e4

public void calculateTips() {
    Scanner userInput = new Scanner(System.in);
    String pattern = "$##,###,###.00;"; // Pattern string for the decimal format
    java.text.DecimalFormat moneyFormat = new java.text.DecimalFormat(pattern); // Decimal Money format
    java.text.NumberFormat defaultFormat = java.text.NumberFormat.getPercentInstance();
    defaultFormat.setMinimumFractionDigits(1);
    String choice;

    TipCalculator tipCalculator1 = new TipCalculator();
    System.out.println("*** Tip Calculator ***");

    do {
        choice = "";
        boolean isBillValid = false;
        boolean isTipValid = false;
        boolean isPartySizeValid = false;
        double theBill = 0.0d;
        int theTip = 0;
        int thePartySize = 0;
        boolean breakAll = false;

        while (!isBillValid) {
            System.out.print("Enter the bill amount: --> ");
            String theBillStrg = userInput.nextLine().trim();
            // Is 'c' or 'C' for CANCEL entered?
            if (theBillStrg.equalsIgnoreCase("c")) {
                // Set breakAll to true break out of this loop.
                breakAll = true;
                break;
            }
            // If the value starts with a decimal point then  
            // prefix it with a 0.
            if (theBillStrg.startsWith(".")) {
                theBillStrg = "0" + theBillStrg;
            }
            // If the value ends with a decimal point then  
            // postfix it with a 0.
            else if (theBillStrg.endsWith(".")) {
                theBillStrg += "0";
            }
            // Is the supplied value a string representation of a 
            // Integer or double type value?
            if (theBillStrg.matches("\\d+(\\.\\d+)?")) {
                // Yes it is...
                // Parse the string value to a double type
                theBill = Double.parseDouble(theBillStrg);
                isBillValid = true;
                tipCalculator1.setBillAmount(theBill);
            }
            else {
                System.out.println("Invalid Bill amount supplied (" + theBillStrg + ")! Try again...");
            }
        }

        while (!isTipValid && !breakAll) {
            System.out.print("Enter your desired tip percentage (0 to 100): --> ");
            String theTipStrg = userInput.nextLine();
            // Is 'c' or 'C' for CANCEL entered?
            if (theTipStrg.equalsIgnoreCase("c")) {
                // Set breakAll to true break out of this loop.
                breakAll = true;
                break;
            }
            // Is a string representation of a Integer value supplied?
            if (theTipStrg.matches("\\d+")) {
                // Yes...Convert the string value to Integer
                theTip = Integer.parseInt(theTipStrg);
                // Is the tip percentage inclusively between 0 and 100?
                if (theTip < 0 || theTip > 100) {
                    // No...
                    System.out.println("Out of Range tip percentage supplied (" + theTip + ")! Try again...");
                    continue;
                }
                isTipValid = true;
                tipCalculator1.setTipPercentage(theTip);
            }
            else {
                System.out.println("Invalid tip percentage supplied (" + theTipStrg + ")! Try again...");
            }
        }

        while (!isPartySizeValid && !breakAll) {
            System.out.print("Enter the size of your party: ");
            String partySizeStrg = userInput.nextLine();
            // Is 'c' or 'C' for CANCEL entered?
            if (partySizeStrg.equalsIgnoreCase("c")) {
                // Set breakAll to true break out of this loop.
                breakAll = true;
                break;
            }
            else if (partySizeStrg.matches("\\d+")) {
                thePartySize = Integer.parseInt(partySizeStrg);
                isPartySizeValid = true;
                tipCalculator1.setPartyAmount(thePartySize);
            }
            else {
                System.out.println("Invalid party size supplied (" + partySizeStrg + ")! Try again...");
            }
        }

        if (!breakAll) {
            System.out.println();
            System.out.println("======================================");
            System.out.println("*** Your Bill ***");
            System.out.println();
            System.out.print("Bill Amount: ");
            System.out.println(moneyFormat.format(tipCalculator1.getBillAmount()));
            System.out.print("Tip Percentage: ");
            System.out.println(defaultFormat.format(tipCalculator1.getTipPercentage()));
            System.out.print("Party Size: ");
            System.out.println(tipCalculator1.getPartyAmount());
            System.out.print("\nTotal Bill (with Tip): ");
            System.out.println(moneyFormat.format(tipCalculator1.getTotalAmount()));
            System.out.print("\nShare for Each Individual: ");
            System.out.println(moneyFormat.format(tipCalculator1.getIndividualShare()));
            System.out.println("======================================");
        }
        
        while (choice.isEmpty()) {
            System.out.print("\nAnother Bill? (y/n): ");
            choice = userInput.nextLine();
            if (!choice.matches("(?i)[yn]")) {
                System.out.println("Invalid input - 'y' or 'n' only! Try again...");
                choice = "";
            }
        }
        System.out.println();

    } while (choice.equalsIgnoreCase("y"));
    System.out.println("\nGoodbye!");
}

推荐阅读