I'm making a simple program that is a guessing game all you need to do is guess the random number. As long as your not getting the correct answer it will keep asking for input.
I created two exceptions which is thrown if the input value is high or low which works.
I also needed to use another exception which is InputMismatchException but when its used its giving me an infinite loop. Instead of asking the user for input it just skips directly to the InputMismatchException. How do I get it to work with my custom exceptions?
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
final int min = 1, max = 50;
final int random = (int) Math.floor(Math.random() * (max - min + 1) + min);
boolean status = false;
int count = 0;
while (status != true) {
try {
System.out.println("Guess a number from 1 to 50: ");
int answer = scan.nextInt();
if (answer < random) {
throw new InputTooLowException("");
} else if (answer > random) {
throw new InputTooHighException("");
} else if (answer == random) {
System.out.println("\n" + "Congratulations! You got it in " + count + " attempt/s");
status = true;
}
} catch (InputTooLowException e) {
System.out.println("Too low. Try again.");
status = false;
count = count + 1;
} catch (InputTooHighException e) {
System.out.println("Too high. Try again.");
status = false;
count = count + 1;
} catch (InputMismatchException e) {
System.out.println("Invalid Input");
status = false;
}
}
}
}
This program works for me.
Again, I want to highlight that this is a bad/non-idiomatic use of Exceptions.
I highly recommend Joshua Blochs famous Book "Effective Java". Chapter 10, Item 69 is about this: "Use exceptions only for exceptional conditions".
The Carnegie Mellon University Software Engineering Institute also has this in their coding guidelines.
Now regarding the infinite loop: I didn't realize that InvalidInputException is not one of your custom Exceptions, but from java.util and thrown by scan.nextInt.
The documentation of Scanner says:
When a scanner throws an InputMismatchException, the scanner will not pass the token that caused the exception, so that it may be retrieved or skipped via some other method.
That means, if you type in text, not a number, Scanner will let you know, but not simply throw away the input. You have to handle it yourself. E.g., by calling next. I have added a check hasNext here. A user could press Ctrl+d which means something like "End of File" (EOF). This closes the input stream. My check prevents an error here, but your call to nextInt may then throw a NoSuchElementException. This should be handled in real code, but I doubt your professor will notice.
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
final int min = 1, max = 50;
final int random = (int) Math.floor(Math.random() * (max - min + 1) + min);
boolean status = false;
int count = 0;
while (status != true) {
try {
System.out.println("Guess a number from 1 to 50: ");
int answer = scan.nextInt();
// Note that this is a _terrible_ use of Exceptions
// and _bad practice_.
if (answer < random) {
throw new InputTooLowException("");
} else if (answer > random) {
throw new InputTooHighException("");
} else if (answer == random) {
System.out.println("\n" + "Congratulations! You got it in " + count + " attempt/s");
status = true;
}
} catch (InputTooLowException e) {
System.out.println("Too low. Try again.");
count = count + 1;
} catch (InputTooHighException e) {
System.out.println("Too high. Try again.");
count = count + 1;
} catch (InputMismatchException e) {
System.out.println("Invalid Input");
// Check if there actually is an invalid token
if (scan.hasNext()) {
// Discard invalid token
scan.next();
}
}
}
}
// Defining Exceptions here, but could do it in their own files.
private static class InputTooHighException extends Exception {
public InputTooHighException(String msg) { super(msg); }
}
private static class InputTooLowException extends Exception {
public InputTooLowException(String msg) { super(msg); }
}
}
Related
I am trying to make a Guessing Game for a Java assignment, I have everything I need except exception handling, you see I'm trying to make it display an error message instead of displaying Exception in thread "main" java.util.InputMismatchException when someone tries to enter a numerical number in alphabetical form. The code I have is followed.
(I know I need a try and catch but I don't know what to put exactly.)
package guessNumber;
import java.util.Scanner;
public class GuessNumberApp {
public static void main(String[] args) {
final int LIMIT = 10;
System.out.println("Guess the number!");
System.out.println("I'm thinking of a number from 1 to " + LIMIT);
System.out.println();
// get a random number between 1 and the limit
double d = Math.random() * LIMIT; // d is >= 0.0 and < limit
int number = (int) d; // convert double to int
number++; // int is >= 1 and <= limit
// prepare to read input from the user
Scanner sc = new Scanner(System.in);
int count = 1;
while (true) {
int guess = sc.nextInt();
System.out.println("You guessed: " + guess);
if (guess < 1 || guess > LIMIT) {
System.out.println("Your Guess is Invalid.");
continue;
}
if (guess < number) {
System.out.println("Too Low.");
} else if (guess > number) {
System.out.println("Too High.");
} else {
System.out.println("You guessed it in " + count + " tries.\n");
break;
}
count++;
}
System.out.println("Bye!");
}
}
try something like that:
try {
int guess = sc.nextInt();
} catch(InputMismatchException e) {
System.out.println("some nice error message");
continue;
}
This would replace
int guess = sc.nextInt();
In a guessing game I have to make, I need to include a try-catch block with two catch clauses (one multi catch block for my two custom exceptions: BadGuessException and TooManyGuessesException, and one block for NumberFormatException).
I tried creating conditions in my program to throw my custom exceptions, because I don't know the logic behind how else they would work properly. I am having compilation errors, and would like help re-working my program so that it implements the try-catch-catch block properly.
My custom exception classes:
public class BadGuessException extends Exception
{
/**
* no-arg constructor
*/
public BadGuessException()
{
super("Sorry, that was an invalid guess!");
}
/**
* parametrized constructor
* #param message String message passed to super class's constructor
*/
public BadGuessException(String message)
{
super(message);
}
}
public class TooManyGuessesException extends Exception
{
/**
* no-arg constructor
*/
public TooManyGuessesException()
{
super("Sorry, too many guesses!");
}
/**
* parametrized constructor
* #param guess integer value representing amount of guesses (turns)
*/
public TooManyGuessesException(int guess)
{
super("Sorry, you guessed " + guess + " times!");
}
}
My program, which is having compilation errors:
import java.util.Random;
import java.util.*;
public class GuessingGame throws NumberFormatException
{
public static void main(String[] args)
{
//Scanner object to receive user input
Scanner keyboard = new Scanner(System.in);
//Create Random class object & random variable
Random rng = new Random();
int n = rng.nextInt(10 - 1 + 1) + 1;
//Initialize incrementor for guessing turns
int turn = 1;
//Create variable for user input (guess)
int guess;
try
{
while(guess != n)
{
//Exception handling for more than five turns
if(turn > 5)
throw new TooManyGuessesException();
//Prompt user to enter their guess
System.out.println("Guess a number between 1 and 10 inclusive.");
System.out.println("Hint: the answer is " + n);
//Receive user input (their guess)
guess = keyboard.nextInt();
//Increment turn variable
turn++;
if(guess < 1 || guess > 10)
throw new BadGuessException();
else if(guess == n)
System.out.println("YOU WIN!\nIt took you " + turn + " attempts.");
}
}
catch(BadGuessException e | TooManyGuessesException e)
{
e.getMessage();
}
catch(NumberFormatException e)
{
System.out.println("Sorry, you entered an invalid number format.");
}
}
}
Make the changes in the GuessingGame class Remove e after BadGuessException in multiple try block. and initialize guess with 0 and remove the NumberformatException from your class declartion;
import java.util.Random;
import java.util.*;
public class GuessingGame
{
public static void main(String[] args)
{
//Scanner object to receive user input
Scanner keyboard = new Scanner(System.in);
//Create Random class object & random variable
Random rng = new Random();
int n = rng.nextInt(10 - 1 + 1) + 1;
//Initialize incrementor for guessing turns
int turn = 1;
//Create variable for user input (guess)
int guess = 0 ;
try
{
while(guess != n)
{
//Exception handling for more than five turns
if(turn > 5)
throw new TooManyGuessesException();
//Prompt user to enter their guess
System.out.println("Guess a number between 1 and 10 inclusive.");
System.out.println("Hint: the answer is " + n);
//Receive user input (their guess)
guess = keyboard.nextInt();
//Increment turn variable
turn++;
if(guess < 1 || guess > 10)
throw new BadGuessException();
else if(guess == n)
System.out.println("YOU WIN!\nIt took you " + turn + " attempts.");
}
}
catch(BadGuessException | TooManyGuessesException e)
{
e.getMessage();
}
catch(NumberFormatException e)
{
System.out.println("Sorry, you entered an invalid number format.");
}
}
}
This question already has answers here:
What is a NumberFormatException and how can I fix it?
(9 answers)
Closed 6 years ago.
I'm not sure how to set it up, but my method has a user input a number between a minimum and maximum, although I have no idea how to handle the NumberFormatException with a try-catch block. Are there any suggestions in regards to how this can be fixed?
static int promptForInt(String prompt, int min, int max){
System.out.println(prompt);
String input = in.readLine();
int parsedInt = Integer.parseInt(input);
while(!(parsedInt > min && parsedInt < max)){
System.out.println("Your input is invalid. " + prompt);
input = in.readLine();
parsedInt = Integer.parseInt(input);
}
return parsedInt;
}
static int promptForInt(String prompt, int min, int max){
System.out.println(prompt);
String input = in.readLine();
int parsedInt;
boolean exceptionThrown = false;
do {
try {
parsedInt = Integer.parseInt(input);
} catch(NumberFormatException e) {
exceptionThrown = true;
}
if (exceptionThrown || (!(parsedInt > min && parsedInt < max)) {
System.out.println("Your input is invalid. " + prompt);
input = in.readLine();
parsedInt = Integer.parseInt(input);
} else {
return parsedInt;
}
} while(true)
}
From my post about NumberFormatException:
Ad. 4.
Finally we come to the place in which we agree, that we can't avoid situations when it's user typing "abc" as a numeric string. Why? Because he can. In a lucky case, it's because he's a tester or simply a geek. In a bad case it's the attacker.
What can I do now? Well, Java gives us try-catch you can do the following:
try {
i = Integer.parseInt(myString);
} catch (NumberFormatException e) {
e.printStackTrace();
//somehow workout the issue with an improper input. It's up to your business logic.
}
Exceptions
In Java Exceptions are used for marking unexpected situations. For example parsing non-numeric String to a number (NumberFormatException) or calling a method on a null reference (NullPointerException). You can catch them in many ways.
try{
//some code
} catch (NumberFormatException e1) {
e.printStackTrace() //very important - handles the Exception but prints the information!
} catch (NullPointerException e2) {
e.printStackTrace();
}
or using the fact, that they all extend Exception:
try {
//somecode
} catch (Exception e) {
e.printStackTrace;
};
or since Java 7:
try {
//somecode
} catch (NullPointerException | NumberFormatException e) {
e.printStackTrace;
};
Exceptions can be easier to deal with if you think of them as the method "Trying to do something, but it couldn't because of X". X is the exception.
The below code could be one way you modify your code to handle the exception:
static int promptForInt(String prompt, int min, int max) {
Integer parsedInt = null; // use an Integer so null can be used to mean an invalid value
while (parsedInt == null) {
System.out.println(prompt);
String input = in.readLine();
int temp;
try {
temp = Integer.parseInt(input);
} catch(NumberFormatException e) {
System.out.print(input+" is not a number. ");
continue;
}
if (temp < min || temp > max) {
System.out.print("Your number must be between "+min+" and "+max+" (inclusive). ");
} else {
parsedInt = temp;
}
}
return parsedInt;
}
Some things you should notice: Firstly, you have not defined in. You could do that like so:
BufferedReader in = new BufferedReader(new InputStreamReader(System.in, "UTF-8"));
If you do that, you'll soon see that you have another Exception to deal with: this can throw UnsupportedEncodingException, and also readLine can throw IOException.
Your method must return a valid integer or it will not exit (you really should supply the user some means of exiting the loop without entering a valid number). Since that's not going to be possible if, for instance, you couldn't read anything from System.in your method needs a reasonable way of telling the caller: "I tried to get an int from the user, except I was stopped by X".
You may actually end up doing something more like:
static int promptForInt(String prompt, int min, int max) throws UserInputException {
BufferedReader in;
try {
in = new BufferedReader(new InputStreamReader(System.in, "UTF-8"));
} catch(UnsupportedEncodingException unsupported) {
// create a new exception and supply the cause as an inner exception
throw new UserInputException("Could not open a reader for System.in", unsupported);
}
Integer parsedInt = null; // use an Integer so null can be used to mean an invalid value
while (parsedInt == null) {
System.out.println(prompt);
String input;
try {
input = in.readLine();
} catch (IOException ioException) {
throw new UserInputException("Could not read a line", ioException);
}
if (input.length() == 0) {
throw new UserInputException("User aborted input");
}
int temp;
try {
temp = Integer.parseInt(input);
} catch(NumberFormatException e) {
System.out.print(input+" is not a number. ");
continue;
}
if (temp < min || temp > max) {
System.out.print("Your number must be between "+min+" and "+max+" (inclusive). ");
} else {
parsedInt = temp;
}
}
return parsedInt;
}
I'm new to Java, and I'm working on a method in my program that checks the users input to be within bounds, not a null value (zero), not a letter, and a positive number. So originally I incorporated two while loops within this method to check for the validity of these inputs, but I would like to simplify it in one loop. I'm getting an error when I input a letter (ex. a) after a few inputs, and I believe it is due to the two different while loops making it more complicated. Can someone help me with this please?
public static void valid(String s, int max)
{
while(sc.hasNextInt() == false) {
System.out.println("That is not correct. Try again:");
sc.nextLine();
}
int value;
while((value= sc.nextInt()) > max || (value= sc.nextInt()) <= 0){
System.out.println("That is not correct. Try again: ");
sc.nextLine();
}
sc.nextLine();
return;
}
You have:
int value;
while((value= sc.nextInt()) > max || (value= sc.nextInt()) <= 0){
System.out.println("That is not correct. Try again: ");
sc.nextLine();
}
Which is doing sc.nextInt() twice, so value does not necessarily have the same value in these two cases and it is also asking you for a number twice.
A fix would be something like this:
int value;
while((value = sc.nextInt()) > max || value <= 0) {
System.out.println("That is not correct. Try again: ");
sc.nextLine();
}
which would make it better but you still have issues. If value is bigger than max, then the loop will iterate again calling nextInt() but this time you have not checked for hasNextInt(). This is why you'd better have everything in one loop. Something like this:
public static void valid(String s, int max) {
while(true) {
if(!sc.hasNextInt()) { //this is the same as sc.hasNextInt() == false
System.out.println("That is not correct. Try again:");
sc.nextLine();
continue; //restart the loop again
} else {
int value = sc.nextInt();
if(value > max || value <= 0) {
System.out.println("That is not correct. Try again:");
sc.nextLine();
continue; //restart the loop from the top - important!
} else {
extendedValidation(value, s);
return;
}
}
}
}
Try something more like (pseudo code):
while valid input not yet received:
if input is an integer:
get integer
if in range:
set valid input received
skip rest of line
extended validation
With a little thought, you should be able use one "print error message" statement. But using two could be arguably better; it can tell the user what they did wrong.
What is the purpose of the String s parameter? Should you be checking that instead of a Scanner input?
Also, don't be surprised by mixing nextInt() and nextLine(). -- Source
I prefer using do-while loops for input before validation.
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int max = 1000;
int val = -1;
String in;
do {
// Read a string
System.out.print("Enter a number: ");
in = input.nextLine();
// check for a number
try {
val = Integer.parseInt(in);
} catch (NumberFormatException ex) {
// ex.printStackTrace();
System.out.println("That is not correct. Try again.");
continue;
}
// check your bounds
if (val <= 0 || val > max) {
System.out.println("That is not correct. Try again.");
continue;
} else {
break; // exit loop when valid input
}
} while (true);
System.out.println("You entered " + val);
// extendedValidation(value, in);
}
I would say that this is a lot closer to what you're looking for, in simple terms...
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
final int MIN = 0;
final int MAX = 10;
Scanner sc = new Scanner(System.in);
int value = -1;
boolean valid;
do {
valid = sc.hasNextInt();
if (valid) {
value = sc.nextInt();
valid = value > MIN && value < MAX;
}
if (!valid) {
System.out.println("Invalid!");
sc.nextLine();
}
} while (!valid);
System.out.println("Valid Value: " + value);
}
}
You should be able to abstract this code to suit your requirements.
The program will ask for an integer as an input. I've set an error message in the catch method in case the input is a character or anything aside from an integer. However, I am not seeing the error message when I try to input a letter. I've also tried different Exception type and the corresponding imports, but there's no difference. Here's the code:
public class Random1 {
public static void main(String[] args){
int g;
Scanner input = new Scanner(System.in);
System.out.print("Enter your guess: ");
g = input.nextInt();
Random r = new Random();
int a = r.nextInt(10) + 1;
try {
if (g == a) {
System.out.println("**************");
System.out.println("* YOU WON! *");
System.out.println("**************");
System.out.println("Thank you for playing!");
} else if (g != a) {
System.out.println("Sorry, better luck next time!");
}
} catch (Exception e) {
System.err.println("Not a valid input. Error :" + e.getMessage());
}
The code that throws the exception must go in the try block