1

I have a program here that accepts a numeric value (stored as a BigDecimal) and the currency (USD or CNY) stored as a String. With the help of user dimo414, I was able to account for blank inputs and non-numeric inputs, while also allowing the user to retry until a valid input is read.

Here is the code:

public static void main(String[] args) {
    Scanner input = new Scanner(System.in);
    System.out.print("Enter the amount of money and specify" 
        + " currency (USD or CNY): ");
    Boolean invalidInput;  // breaks out of do-while loop after successful outcome

    do {
        invalidInput = false;
        try {
            String line = input.nextLine();
            Scanner lineScan = new Scanner(line);
            BigDecimal moneyInput = lineScan.nextBigDecimal();
            String currency = lineScan.next();

            if (currency.equals("USD")) {
                // convert USD to CNY
            } else if (currency.equals("CNY")) {
                // convert CNY to USD
            } else {
                /*
                reprompt user for currency,
                but retain the value of moneyInput;
                repeat process until valid currency
                 */
            }
        } catch (NoSuchElementException | IllegalStateException e) {
            // deals with errors:
            // non-numeric moneyInput or blank input
        }
    } while (invalidInput);
}

Now I'm having trouble dealing with when moneyInput is valid, but currency is not, e.g. 100.00 abc. In this case, I'd like to prompt the user to re-enter a value for currency while retaining the value of money.

I tried using a similar do-while loop around the section that prompted for currency and continued onto the if-else block like so:

do {
    String currency = lineScan.next();

    if (currency.equals("USD")) {
        // convert USD to CNY
    } else if (currency.equals("CNY")) {
        // convert CNY to USD
    } else {
        invalidInput = true;
        System.out.print("Please enter a valid currency: ");
        // since invalidInput == true,
        // jump back up to the top of the do block
        // reprompt for currency 
    }
} while (invalidInput);

But this solution was ineffective because it would display the exception error message from the outer catch block, so I'd actually have to implement a do-while loop inside a try-catch block inside a try-catch block, and that got messy really fast.

I also tried defining a new function outside of main called readCurrency that I could invoke in the else block, but I ran into issues of variable scopes. I am still a beginner in Java so I didn't know how to properly define a function and pass the necessary info to it.

What other ways are there to loop back up to the top of that try block and allow the user to re-enter the currency only?

Thanks so much for reading and providing feedback.

Community
  • 1
  • 1
  • Can't you ask for the input in two steps: - Insert the amount //Deal with the amount - Insert the currency //Deal with it Each "Deal" will be a different method, which can ask for re-entering the input or whatever it needs – SCouto Jul 20 '16 at 09:59
  • If the first time the user inserted `100.00 abc` what would the program ask from the user? – nick zoum Jul 20 '16 at 10:01
  • @nickzoum the error message from the `catch` block is displayed, followed by the print message I had temporarily placed in the `else` block. Then the user can re-input. Here's a screenshot in case (http://imgur.com/a/Z2PRc). Note how, for the re-input, the program requires both `money` and `currency` to continue. – A is for Ambition Jul 20 '16 at 10:05
  • @SCouto Since the part that deals with `moneyInput` is inside a do-while loop, `moneyInput` has a scope inside the `do` block so I was unable to deal with `currency` separately – A is for Ambition Jul 20 '16 at 10:10
  • I'll write an answer – SCouto Jul 20 '16 at 10:24

4 Answers4

1

Ok, so some restructuring was required to get the code working.

The input object is used to fetch values from console.

The currency value is fetched inside a loop (do-while), where the loop condition is that currency should not be equal to 'USD' or 'CNY'. This eliminates the need for invalidInput loop variable.

    public static void main(String[] args) {
           try {
            Scanner input = new Scanner(System.in);
            System.out.print("Enter the amount of money and specify" 
                + " currency (USD or CNY): ");

            //Boolean invalidInput;  // Not required
            //String line = input.nextLine();
            //Scanner lineScan = new Scanner(line);

            String currency =null;

            BigDecimal moneyInput = input.nextBigDecimal();

            do{     
                if(currency!=null){
                  System.out.print("Please enter a valid currency: ");
                }
                currency = input.next();
            }while(!currency.equals("USD")&&!currency.equals("CNY"));

            if (currency.equals("USD")) {
                // convert USD to CNY
            } else if (currency.equals("CNY")) {
                // convert CNY to USD
            }
            } catch (NoSuchElementException | IllegalStateException e) {
                // deals with errors:
                // non-numeric moneyInput or blank input
            }
    }
boxed__l
  • 1,334
  • 1
  • 10
  • 24
  • 1
    @AisforAmbition Can you try my code. I don't see how it can throw any error...since we are dealing with it silently... – boxed__l Jul 20 '16 at 10:30
  • My mistake, I've deleted my previous comment. Thank you for your help and feedback :) – A is for Ambition Jul 20 '16 at 10:51
  • Although, one thing I wanted to retain from the original code was to make the program repeatedly prompt the user each time until a valid input is entered in the case of a blank input, kind of like how you did with the "Please enter a valid currency". This was the original intent of the `invalidInput` boolean from the do-while loop. I am now trying to see if I can re-implement this since you've given me a great starting point. – A is for Ambition Jul 20 '16 at 10:57
1

You are mixing input validation with processing. Do one thing at a time, first validate, then process. With a little bit of code modularization using helpers, this becomes simple enough.

String amountString;
String currencyString;
do {
 System.out.println("Please insert a valid amount and currency");
 String line = input.readLine();
 String[] values = line.split("\\s"); //split on the space
 amountString = values[0];
 currencyString = values[1];

}
while (!isValidAmount(amountString));
while (!isValidCurrencyString(currencyString) {
  System.out.println("Amount accepted but unsupported currency. Please input only the correct currency now");
  currencyString = input.nextLine();
}

Now what you need are the helpers method:

  • boolean isValidAmount(String amountString)
  • boolean isValidCurrency(String currencyString)

Once you have them, and have completed the validation, you can actually insert the processing logic:

BigDecimal amount = BigDecimal.parse(amountString); //this may be the wrong name of the parse function, don't remember but something like that;
switch(currencyString) {
  case "USD": //...
}

Can you write the helper methods yourself? They should be easy :)

Diego Martinoia
  • 4,592
  • 1
  • 17
  • 36
  • +1 for being helpful without giving too much away. your answer helped guide me in the right direction regarding the order in which I should think about things, thanks :) – A is for Ambition Jul 20 '16 at 10:52
1

What i was suggesting in the comment is to split the retrieval of the amount and the one for the currency, so you can develop different solutions, and different loops to each of them. I made a quick example. Hope it helps:

Main method

 public static void main(String[] args) {

    Scanner input = new Scanner(System.in);

    BigDecimal moneyInput = getMoneyInput(input);
    String currencyInput = getCurrency(input);

    System.out.println(moneyInput.toString() + " " + currencyInput);
}

GetCurency function

public static String getCurrency(Scanner input) {
    System.out.print("Enter the currency: ");

    String currency = null;
    boolean invalidInput = true;
    try {

        do {
            String line = input.nextLine();
            if ("USD".equals(line) || "CNY".equals(line)) {
                invalidInput = false;
                currency = line;
            } else {
                System.out.print("Invalid currency, enter it again please");
            }
        } while (invalidInput);


    } catch (Exception e) {
        System.out.println(e.getMessage());
        System.out.print("Invalid currency, enter it again please");

    }
    return currency;


}

GetAmount function

public static BigDecimal getMoneyInput(Scanner input) {
    System.out.print("Enter the amount of money without the currency: ");

    BigDecimal moneyInput = BigDecimal.ZERO;
    boolean invalidInput = true;
    try {

        do {
            String line = input.nextLine();
            moneyInput = new BigDecimal(line);
            invalidInput = false;

        } while (invalidInput);


    } catch (Exception e) {
        System.out.println(e.getMessage());
        System.out.print("Invalid input, enter it again please");

    }
    return moneyInput;

}
SCouto
  • 7,808
  • 5
  • 32
  • 49
  • Hi, I really like your solution because it introduced me to the proper way of defining multiple functions and using them together, but a main functionality I wanted to maintain was to allow the user to input both the money and currency in one go – A is for Ambition Jul 20 '16 at 10:48
0

Here you go:

public void main(String[] args){
    Scanner input = new Scanner(System.in);
    String message = "Enter the amount of money and specify currency (USD or CNY)";
    System.out.println(message);
    boolean invalidInput = true;
    BigDecimal moneyInput = null;
    String currency = null;
    do{
        try{
            String line = input.nextLine();
            Scanner lineScan = new Scanner(line);
            BigDecimal temp = lineScan.nextBigDecimal();
            if(temp == null){
                if(moneyInput == null){
                    System.out.println(message);
                    continue;
                }
            }else{
                    moneyInput = temp;
            }
            String tempCurrency = lineScan.next().toUpperCase();
            if(!temp.isValid()){
                if(currency == null){
                    System.out.println("Reenter currency:");
                    continue;
                }
            }else{
                currency = tempCurrency;
            }
            if (currency.equals("USD")) {
                // convert USD to CNY
            } else {
                // convert CNY to USD
            }
            invalidInput = false;
        }catch(Exception e){
            System.out.println(message);
            moneyInput = null;
        }
    }while(invalidInput);
}

You also need to add this method:

public boolean isValid(String currency){
    return currency.equals("USD") || currency.equals("CNY");
}

This will go on until both values are valid and will not force the user re-enter another BigDecimal if a valid one has already been supplied, but it will allow the user to change the BigDecimal every time the currency is invalid.

nick zoum
  • 7,216
  • 7
  • 36
  • 80