I wrote a name checker that uses a for loop to check if each individual character in the string is a letter, and I wrote an if statement within the for loop stating that if the if statement conditions are met, print "Your name is valid!" and break. But if the conditions are not met, rerun the loop.
public static void nameValid() {
Scanner in = new Scanner(System.in);
System.out.println("Enter your name");
String name = in.nextLine();
int q = name.length();
for (int i = 0; i < name.length(); i++) {
if (Character.isLetter(name.charAt(i)) && q >= 2) {
System.out.println("Your name is valid!");
break;
} else {
System.out.println("Your name is invalid! Please enter a valid name!");
nameValid();
}
}
}
If I enter a valid string the first time around, everything is fine, and it moves on to the second method. If I enter an invalid String, it gives me the expected error message and reruns the loop. But then when I enter a valid string after that, it continuously runs the loop. The output I get is this:
Enter your name
123
Your name is invalid! Please enter a valid name!
Enter your name
fred
Your name is valid!
Your name is invalid! Please enter a valid name!
Enter your name
It's not re-running the loop... it's entering a recursive function call.
(Use a debugger next time please.)
In your else block, you're calling the nameValid function recursively within a loop. Thus, when you finally do enter a valid name and hit the break line, the loop that originally called the function continues.
Related
So I'm currently working on a school assignment which is to design a program that allows the user to enter some text, and then the program checks:
The first letter of the first word is a capital letter (it needs to be lowercase)
That there are only letters and numbers in the entire user input
That there are no spaces in the user input
So the program does work but the issue I'm having is with the print statements, I'll post my code below and explain:
public static void main(String[] args) {
try (Scanner stdln = new Scanner(System.in)) {
String userInput;
boolean legal = true;
boolean style = true;
char input; //Checks the userInput variable to be sure that boolean is false if there's no lowercase letter at char0 + if there are no letters
char loop;
System.out.println("The program checks the properness of a proposed Java variable name.");
System.out.println("\nPlease enter a variable name (q to quit): ");
userInput = stdln.nextLine();
input = userInput.charAt(0);
do
{
if (!(Character.isLetter(input)))
{
legal = false;
}
if (userInput.contains(" "))
{
legal = false;
}
if (!(Character.isLowerCase(input)))
{
style = false;
}
for (int i = 1; i < userInput.length() &&legal; i++)
{
loop = userInput.charAt(i);
if (!(Character.isLetterOrDigit(loop)))
{
style = false;
}
}
if (!(legal) && !(style))
{
System.out.println("Illegal.");
}
else if (legal && !(style))
{
System.out.println("Legal, but uses poor style.");
}
else
{
System.out.println("Good.");
}
System.out.println("\nPlease enter a variable name (q to quit): ");
userInput = stdln.nextLine();
input = userInput.charAt(0);
} while (!(userInput.equalsIgnoreCase("q")));
}
}
}
So the code works and the first input I test comes out as it should, however, once I get a response that isn't "Good.", then the same response will print for every entry, here's a sample from a session I just did:
The program checks the properness of a proposed Java variable name.
Please enter a variable name (q to quit):
streetAddress2
Good.
Please enter a variable name (q to quit):
StreetAddress2
Legal, but uses poor style.
Please enter a variable name (q to quit):
streetAddress2
Legal, but uses poor style.
Please enter a variable name (q to quit):
Street Address2
Illegal.
Please enter a variable name (q to quit):
streetAddress2
Illegal.
In that sample session, 3 and 5 should return the statement "Good." but for some reason, it just prints the statement from the previous entry. I'm still fairly new to Java so I'm a little stumped. Any ideas?
You have to reset legal and style to true at the start of each iteration. However, it is not the only problem with your code. The logic is not correct.
Right now in the for loop you check all the characters being letters or digits. If this condition fails you set style to false. However, you should set legal to false instead, because such identifiers are not allowed.
Also, when you print the result you don't check the conditions correctly. For example, if legal is false, but style is true your code will print Good.
You forgot to reset to true your legal and style boolean variables.
At every iteration, the legal and style variables will keep containing the result of the previous input. For example, if on your first input you immediately write a variable name with an illegal syntax and poor style, you'll see that any following name will show the same result. Even though those names are good or they only lack in style, the output will still be the same (wrong) because both variables have been left to false and nothing sets them back to true.
Besides, the logic to print the output messages didn't account for all combinations correctly.
Both variable logic and output printing could be re-written as follows:
do {
//forgotten reset
legal = true;
style = true;
//excat same implementation of yours
if (!(Character.isLetter(input))) {
legal = false;
}
if (userInput.contains(" ")) {
legal = false;
}
if (!(Character.isLowerCase(input))) {
style = false;
}
for (int i = 1; i < userInput.length() && legal; i++) {
loop = userInput.charAt(i);
if (!(Character.isLetterOrDigit(loop))) {
style = false;
}
}
//If it's illegal it does not matter whether the variable name has a poor or good style, it's illegal anyway
if (!legal) {
System.out.println("Illegal.");
//If we're in this else branch then the variable name is legal, but we have to check its style.
//If it has poor style then we print the "poor style" message.
} else if (!style) {
System.out.println("Legal, but uses poor style.");
} else {
//Last case where the variable name is legal and has a good style
System.out.println("Good.");
}
System.out.println("\nPlease enter a variable name (q to quit): ");
userInput = stdln.nextLine();
input = userInput.charAt(0);
} while (!(userInput.equalsIgnoreCase("q")));
This question already has answers here:
Loop user input until conditions met
(3 answers)
Closed 7 years ago.
I'm currently working my way through a Udemy Java course and am practicing what i have learnt thus far.
I have the following simple program which i am planning on using to get the user to input his name.
import java.util.Scanner;
public class Adventure {
public static final int menuStars = 65;
private static Scanner input = new Scanner(System.in);
public static void main(String[] args) {
String firstName = "";
String lastName = "";
boolean validName = false;
while(!validName){
//Entering first name
System.out.println("Please enter your first name.");
try {
firstName = input.nextLine();
if(firstName.length() == 0){
throw new Exception("Please enter a first name of at least 1 character.");
}else{
//Entering last name
System.out.println("Please enter your last name.");
lastName = input.nextLine();
if(lastName.length() == 0){
throw new Exception("Please enter a last name of at least 1 character");
}else{
System.out.println("You have entered " + firstName +" " + lastName);
}
}
} catch (Exception e) {
System.out.println(e.getMessage());
continue;
}
//Used to terminate loop when both first & last names are valid
validName = true;
}
}
}
I want to make the program repeat the error message when the user inputs a blank name instead of restarting the entire program from the beginning.
E.g When the user enters a blank first name, i want the program to keep repeating "Please enter a first name of at least 1 character" and when the user enters a blank last name, for it to keep repeating "Please enter a last name of at least 1 character" until the user enters a valid name.
However, currently when the user enters a blank first name or last name, my program will repeat itself from the very beginning instead of repeating just the error message.
How would i go about making the program repeat just the error message?
Use a boolean variable that stores true when "Please enter your first name." is printed. Check before printing this string each time if this variable is false or not. Also, initialize it to false before the loop. Same idea goes for last name.
if(!printed)
{
System.out.println("Please enter your first name.");
printed=true;
}
havent tested that but i am guessing it can be like that, with out try/catch though, it just makes no sense to me using it in the way you have it on your code
String firstName = "";
String lastName = "";
System.out.println("Please enter your first name.");
firstName = input.nextLine();
while(firstName.length<1){
System.out.println("Please enter a first name of at least 1 character.");
firstName = input.nextLine();
}
lastName=input.nextLine();
while(firstName.length<1){
System.out.println("Please enter a last name of at least 1 character.");
lastName = input.nextLine();
}
System.out.println("You have entered " + firstName +" " + lastName);
Edit, some basic info about exceptions
try catch is used when something unexpected happens and you try to find a way round it. for example if an array of 10 positions is expected at some point and a smaller array (lets say 4 positions) is being used. Then this would cause an exception causing the program to terminate with no further information.
With try catch you can check what the problem is, and try to either inform the user to do something(if they can) or close the program in a better way, using System.exit() for example and saving all the work that was done till that point
An other example is that if you ask for 2 numbers to do an addition. if the user enters letters instead of number the int sum=numbA+numbB; would throw and exception. This of course could be handled using an if. but even better would be something like this
A whitespace is actually considered a character, so the check of (length == 0) doesn't work for your purposes.
Although the following code below is incomplete (ex: handles the potentially undesirable case of firstname=" foo", (see function .contains()), it does what the original post asks - when the user enters a blank first/last name, it keeps repeating "Please enter a first/last name of at least 1 character" until the user enters a valid first/last name.
import java.util.Scanner;
public class Adventure {
public static final int menuStars = 65;
private static Scanner input = new Scanner(System.in);
public static void main(String[] args) {
String firstName = "";
String lastName = "";
boolean firstNameLegal = false;
boolean lastNameLegal = false;
// Entering first name
while (!firstNameLegal) {
System.out.println("Please enter your first name.");
firstName = input.nextLine();
if (!firstName.equals(" "))
firstNameLegal = true;
else
System.out.println("Please enter a first name of at least 1 character.");
}
// Entering last name
while(!lastNameLegal){
System.out.println("Please enter your last name.");
lastName = input.nextLine();
if(!lastName.equals(" "))
lastNameLegal = true;
else
System.out.println("Please enter a last name of at least 1 character.");
}
System.out.println("You have entered " + firstName +" " + lastName);
}
}
Essentially the idea of this program is to test user input and throw exceptions that I've created when invalid data is entered. For example: name cannot be empty and must be all alpha characters (no special or numeric). I have embedded this in a do-while loop that will continue so long as q is not entered to quit. I'm reading in the user input via scanner line and then sending the string inputted to a function that validates whether it meets the criteria. If it does not, then the function throws my custom exceptions. It all works fine EXCEPT when the exception is thrown it still takes that string and puts it in the new Person object.
How do I throw the exception to the user but THEN require them to re-enter the name or age until it's entered correctly?
do{
Scanner input = new Scanner(System.in);
System.out.println("Enter person info or q to quit.");
System.out.print("Please enter the name of this person:");
String name = input.nextLine();
if(name.equalsIgnoreCase("q"))
{
break;
}
try{
isName(name);
}catch (InvalidNameException n){
System.out.println(n);
}
System.out.print("Please enter an age for this person:");
String age = input.nextLine();
try{
isValidAge(age);
}catch(InvalidAgeException a){
System.out.println(a);
}
public static void isName(String name) throws InvalidNameException
{
if(name.isEmpty())
{
throw new InvalidNameException("You did not enter a name.");
}
String[] namez = name.split(" ");
for(int i=0;i<namez.length;i++)
{
char[] charz = namez[i].toCharArray();
for (char n : charz)
{
if(!Character.isLetter(n))
{
throw new InvalidNameException("You have entered an invalid name.");
}
}
}
}
Put a continue; in your exception handling. It will break the loop an reenters it.
I would assume that the error lies within the compatibility of your isName() method and the method loop shown. It probably happens after it sets the name to a variable too. I cant tell you anything really specific because I cant see the isName method though.
The easiest way I know of doing this is to validate the obtained String using a regular expression. You can do something like this:
Scanner input = new Scanner(System.in);
System.out.print("Enter your name: ");
String name = input.nextLine();
String regex = "[A-Z a-z]+(\\s)[A-Z a-z]+";
System.out.println(name.matches(regex)? "matches": "does not match");
The expression regex is used to evaluate a sequence of alpha characters (no numbers or special characters) separated by a space. So, something like: "Joe Smith" will pass validation, but something like "Joe 123Klkjsd" will not.
You can take this code and test the input String in a while() loop:
while(!name.matches(regex))
{
// Prompt the user to re-enter a valid name and assign to name variable
}
Something like that should work.
It would be better to evaluate each variable within a do-while loop. Thus if there is an error in the variable age would not necessarily re-enter the name.
Scanner input = new Scanner(System.in);
String name;
String age;
System.out.println("Enter person info or q to quit.");
do{
System.out.print("Please enter the name of this person: ");
name = input.nextLine();
if(name.equalsIgnoreCase("q")) break;
try{
isName(name);
break;
}catch (InvalidNameException n){
System.out.println(n);
continue;
}
} while (true);
if(!name.equalsIgnoreCase("q"))
do{
System.out.print("Please enter an age for this person: ");
age = input.nextLine();
if(age.equalsIgnoreCase("q")) break;
try{
isValidAge(age);
System.out.printf("Nombre; %s\nEdad: %s",name,age);
break;
}catch (InvalidAgeException a){
System.out.println(a);
continue;
}
} while (true);
boolean acceptPcode=true;
boolean acceptQty=false;
int Qty=0;
List<Integer> purchasedProdQty=new ArrayList<>();
while(acceptPcode==true && acceptQty==false){
do{
try{
System.out.print("Enter Qty: ");
Qty=sc.nextInt();
acceptQty=true;
}catch(InputMismatchException ime){
System.out.println("Invalid quantity please enter a number!");
acceptQty=false;
}
if(acceptQty==true)
purchaseProdQty.add(Qty);
}while(acceptQty==false);
}
my question is that when i enter a letter it goes in an infinity loop and it doesn't prompt the user to enter a quantity ....which is
Enter Qty: Invalid quantity please enter a number!
Enter Qty: Invalid quantity please enter a number!
Enter Qty: Invalid quantity please enter a number!......
You forgot to read the \n (or \r\n) characters that are from the next line. In your current code, the scanner is waiting for an int input, bu the current next input is this break line char. Just add sc.nextLine() in your code to consume the break line char:
Qty=sc.nextInt();
sc.nextLine();
acceptQty=true;
From what I can gather it seems your scanner(sc) is throwing an exception. This causes acceptQty to constantly be false keeping you stuck in your inner do-while loop.
You need to consume any illegal characters in the exception block otherwise they won't be consumed by the Scanner#nextInt method call causing the loop to repeat itself indefinitely:
} catch(InputMismatchException ime) {
System.out.println
("Invalid quantity: " + sc.nextLine() + " please enter a number ");
...
}
You are getting exception while reading out of sc and so it always go into infinity loop. Can you paste what's the value assiged in sc?
I believe you're doing this all wrong. Your method of validation is very obscure and can be simplified. Suppose you have the following method:
public int readNumber(final String prompt, final Scanner scanner){
System.out.println(prompt);
try{
return scanner.nextInt();
}catch(Exception ex){
System.err.println("Enter a valid number");
return readNumber(prompt, scanner);
}
}
This method will print out the prompt (the first argument) and read input from the provided Scanner (the second argument). If the user enters something that can't be parsed as an int, it will invoke the same method (recursion).
Take out both of your loops and when you want to read an int from your Scanner, do something like:
int value = readNumber("Enter a quantity", sc);
You know for sure that Integer.MAX_VALUE >= value >= Integer.MIN_VALUE
I wrote a program to determine a prime number and am required to use 'Q' as the quit function to get out of the program. Below is the code i have written. I am wondering how I would modify method of quitting the program to make it exit correctly.
import java.util.Scanner;
public class Practice
{
public static void main(String[]args)
{
Scanner keyboard = new Scanner(System.in);
int number, i=2;
String quit;
boolean prime = true;
System.out.println("Please enter a number to determine if it is prime, to quit please enter Q.");
number = keyboard.nextInt();
quit = keyboard.nextLine();
for (i=0; i<number;i++)
{
if ((number%2==0) || (number==1) || (number%3==0))
{
prime = false;
}
}
if (prime==false)
{
System.out.println(number+" is not a prime number.");
}
else if(prime==true)
System.out.println(number+" is a prime number.");
if (quit.charAt(0)=='Q')
{ System.exit(0);}
and my output upon entering 'Q' is:
----jGRASP exec: java Practice
Please enter a number to determine if it is prime, to quit please enter Q.
Q
Exception in thread "main" java.util.InputMismatchException
at java.util.Scanner.throwFor(Scanner.java:909)
at java.util.Scanner.next(Scanner.java:1530)
at java.util.Scanner.nextInt(Scanner.java:2160)
at java.util.Scanner.nextInt(Scanner.java:2119)
at Practice.main(Practice.java:15)
----jGRASP wedge2: exit code for process is 1.
----jGRASP: operation complete.
}
}
When the input through the console is given as "Q", the value of type String is getting assigned to a variable of type int, which is incorrect.
number = keyboard.nextInt();
The type of in the input needs to be checked, before it can be assigned to a int variable.
You have:
number = keyboard.nextInt();
quit = keyboard.nextLine();
Think for a moment about what actually happens here. 'Q' is not a number and so nextInt(), as documented, throws an InputMismatchException. Your use of nextLine() doesn't make much sense following that.
You have a couple of options:
Use Scanner.hasNextInt() to determine if the next token truly is a well-formed integer. If not, read it as a string and check it.
Use Scanner.next() always, and check if it is "Q" before parsing it with Integer.parseInt() (being prepared to handle errors there as well).
The Scanner.next* functions don't implicitly skip invalid values. The Scanner is only doing what you tell it to do, and if you tell it to grab an integer but the input is not an integer, it rightfully complains. It is up to you to use the Scanner appropriately and check your possible input cases.
You should read in the numbers as Strings with keyboard.nextLine();
and check first if the it contains 'Q'. If it does, quit, else do, number = Integer.parseInt(yourVariableHere); and go from there
Try this instead:
String input;
int number = 1;
int i=2;
Then do this:
System.out.println("Please enter a number to determine if it is prime, "
+ "\nto quit, please enter Q.");
input = keyboard.nextLine();
if (input.charAt(0)=='Q')
{
System.exit(0);
}
else
{
try
{
number = Integer.parseInt(input);
}
catch(NumberFormatException nfe)
{
System.out.println("Please enter a number or Q!");
}
}