nextDouble creating a loop in a different method [duplicate] - java

This question already has answers here:
Scanner - java.util.NoSuchElementException
(3 answers)
Closed 4 months ago.
I'm working on a program for my Java class and things were going really well until I inputted a number in the getSideLength method. If the number is valid, it will skip everything back to main and start a new loop on the first quesiton. I honestly have know idea what is going on and neither did my teacher. I'm running of of VS Code if that makes a difference.
package week7;
import java.util.Scanner;
import java.lang.Math;
public class Lab7b {
static void calculateSideA(){
double b = getSideLength("B");
double c = getSideLength("C");
double a = Math.sqrt(Math.pow(c,2)-Math.pow(b,2));
System.out.println("A right triangle with sides 'B' = "+b+" and 'C' (hypotenuse) = "+c+", has a side 'A' which has a length of: "+a);
}
static void calculateSideB(){
double a = getSideLength("A");
double c = getSideLength("C");
double b = Math.sqrt(Math.pow(c,2)-Math.pow(a,2));
System.out.println("A right triangle with sides 'A' = "+a+" and 'C' (hypotenuse) = "+c+", has a side 'B' which has a length of: "+b);
}
static void calculateSideC(){
double a = getSideLength("A");
double b = getSideLength("B");
double c = Math.sqrt(Math.pow(a,2)+Math.pow(b,2));
System.out.println("A right triangle with sides 'A' = "+a+" and 'B' = "+b+", has a side 'C' (hypotenuse) which has a length of: "+c);
}
static double getSideLength(String letter){
Scanner entry = new Scanner(System.in);
boolean valid = false;
double sideLength = 0;
do{
try{
System.out.print("Please enter the length of the "+letter+" side: ");
sideLength = entry.nextDouble();
entry.nextLine();
valid = true;
}catch(Exception e){
System.out.println("Please enter a number.");
valid = false;
entry.nextLine();
}
}while(!valid);
entry.close();
return sideLength;
}
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
boolean rerun = false;
boolean valid = false;
do{
String letter = "";
do{
try{
System.out.print("Enter the side of the triangle would you like to calculate: (A/B/C) ");
letter = input.nextLine();
if(letter.equalsIgnoreCase("A")||letter.equalsIgnoreCase("B")||letter.equalsIgnoreCase("C")){
valid = true;
if(letter.equalsIgnoreCase("A")){
calculateSideA();
}
else if(letter.equalsIgnoreCase("B")){
calculateSideB();
}
else if(letter.equalsIgnoreCase("C")){
calculateSideC();
}
else{
System.out.println("Something has gone wrong.");
}
}
else{
System.out.println("Please enter A, B, or C.");
valid = false;
}
}catch(Exception e){
System.out.println("Please enter A, B, or C.");
valid = false;
}
}while(!valid);
valid = false;
do{
System.out.print("Would you like to play again? (Y/N) ");
String answer = input.nextLine();
if(answer.equalsIgnoreCase("Y")||answer.equalsIgnoreCase("N")){
if(answer.equalsIgnoreCase("Y")){
valid = true;
rerun = true;
}
else{
System.out.println("Thank you. Come Again.");
rerun = false;
valid = true;
}
}
else{
System.out.println("Please enter either Y or N");
valid = false;
}
}while(!valid);
}while(rerun);
input.close();
}
}
Here's what a run looks like:
Enter the side of the triangle would you like to calculate: (A/B/C) c
Please enter the length of the A side: 5
Enter the side of the triangle would you like to calculate: (A/B/C) Please enter A, B, or C.
Enter the side of the triangle would you like to calculate: (A/B/C) Please enter A, B, or C.
Enter the side of the triangle would you like to calculate: (A/B/C) Please enter A, B, or C.
and on and on.
Any ideas?

The output
Enter the side of the triangle would you like to calculate: (A/B/C) A
Please enter the length of the B side: 3.0
Please enter the length of the C side: 4.0
A right triangle with sides 'B' = 3.0 and 'C' (hypotenuse) = 4.0, has a side 'A' which has a length of: 2.6457513110645907
Would you like to play again? (Y/N) Please enter either Y or N
Would you like to play again? (Y/N) N
Thank you. Come Again.
The problem:
Once you call close() in your Scanner object, you are closing the input stream. Once you do that, you can't reopen it in the life of the application. You need to work with the same Scanner object throughout. The fact your teacher didn't know that, scares me.
The solution:
Pass the Scanner object to the methods that need to use it.
static double getSideLength(String letter, Scanner entry) {
boolean valid = false;
double sideLength = 0;
do {
try {
System.out.print("Please enter the length of the " + letter + " side: ");
sideLength = entry.nextDouble();
valid = true;
} catch (Exception e) {
System.out.println("Please enter a number.");
valid = false;
}
} while (!valid);
return sideLength;
}
And of course, you need to pass it thru the methods that wraps this one. There might be other (minor) bugs with your application. You will need to clean up those.

Related

Loops and user input validation in java, again

So, I think about two days back I asked a question about input validation, and how to loop programs until the user gave a valid input..
So I made a calculator and I wanted to loop every step of the program so that if the user didn't put a double (69, 42.0) or the appropriate operator char (/, *, +, -) they would be stuck on that step till they got it right or otherwise closed the app entirely.
So one thing I got from the last question about this is that I could make a boolean value called "restart" or something and encapsulate my entire code except for the main method obviously and at the end I could make a question that they could answer true or false and the entire app could run again. While I admit having a "start over" button on my app is cool and useful for all my other a projects (probably not, I'm sure this can be done more efficiently), It still didn't satiate me and my original problem.
SO...
I got to trying everything I could (I know stack likes people who show that they at least tried).
EXAMPLE 1
Scanner input = new Scanner(System.in);
double valX;
System.out.println("Calculator Activated.");
do
{
System.out.print("Value X: ");
valX = input.nextDouble();
}while (!input.hasNextDouble());
{
System.out.println("Invalid number!");
}
//Didn't work ¯\_(ツ)_/¯
EXAMPLE 2
Scanner input = new Scanner(System.in);
double valX;
System.out.println("Calculator Activated.");
while (!input.hasNextDouble())
{
System.out.println("Value X: ");
valX = input.nextDouble();
}
//neither this one...
Note that the solution you guys give me has to apply to every step of the program.
And for a bit more clarity is the entire src code without the stuff I tried and the "restart" loop.
import java.util.Scanner;
public class CalTest
{
public static void main(String[] args)
{
Scanner input = new Scanner(System.in);
double valX, valY, divided, multiplied, added, subtracted; //Declared all my variables...
char operator;
boolean restart; //Didn't need to declare it true or false since I'm using a Scanner anyway
do //Start of the entire program
{
System.out.println("Calculator Activated.");
System.out.print("Value X: "); //I need a loop here...
valX = input.nextDouble();
System.out.print("Operator: "); //And here...
operator = input.next().charAt(0);
System.out.print("Value Y: "); //And here too..
valY = input.nextDouble();
divided = valX / valY;
multiplied = valX * valY;
added = valX + valY;
subtracted = valX - valY;
if (operator == '/')
System.out.println("Result: " + divided );
else if (operator == '*')
System.out.println("Result: " + multiplied); //<--Not sure if I need a loop with the if's
else if (operator == '+')
System.out.println("Result: " + added);
else if (operator == '-')
System.out.println("Result: " + subtracted);
else
System.out.println("Invalid operator!");
System.out.print("Try again? "); //I also need a loop here, I think.
restart = input.nextBoolean();
} while (restart); //End of it if you declared false.
System.out.println("Calculator terminated.");
}
}
At one point I tried to use the same "restart the app" concept and made a boolean variable for every single step in the code and it honestly was tiresome and not worth it.
Also I'm just a beginner if it's a concept of the loops that I'm missing then I'm happy to learn it from you guys.
Again, gracias to anyone who answers and helps contribute to my learning.
In your final code example in the class called CalTest where you assign valX = input.nextDouble(); you could a call recursive method that handles the exception until the input is what you want. Something like this:
private static double getNextDouble(Scanner input) {
try {
return input.nextDouble();
} catch (InputMismatchException e) {
System.out.println("Value X must be a number: ");
input.next();
return getNextDouble(input);
}
}
You'll replace valX = input.nextDouble(); with valX = getNextDouble(input);.
You can tidy this up and make it work for your other potential error cases, perhaps creating a parameter for the output message and passing it in as an argument.
public static void main(String[] args) {
double valX=0,valY=0;
char operator='0';//dummy default
Scanner input = new Scanner(System.in);
System.out.println("Calculator Activated.");
Double dX = null;
do
{
System.out.print("Value X: ");
dX = getDouble(input.next());
}while (dX==null);
{
valX = dX;
}
Character op = null;
do
{
System.out.print("Operator: ");
op = getOperator(input.next());
}while (op==null);
{
operator=op;
}
Double dY = null;
do
{
System.out.print("Value Y: ");
dY = getDouble(input.next());
}while (dY==null);
{
valY = dY;
}
System.out.println("Done: "+ valX + " "+operator + " " +valY);
}
static Double getDouble(String input) {
Double d = null;
try {
d = new Double(input);
}catch(NumberFormatException ex){
}
return d;
}
static Character getOperator(String input) {
Character c = null;
if("+".equals(input) || "-".equals(input) || "*".equals(input) || "/".equals(input)){
c = input.charAt(0);
}
return c;
}

My function with scanner crashes instead of returning input number (java)

I created a function that asks user for a number. The function checks if it is a positive integer and if it is an integer at all, and should return that number.
The program crashes every time if the user puts in a positive integer. I am new to eclipse IDE and don't know where to look for a log of runtime errors.
I already tried return height.nextInt() and deleted the z variable, didn't work.
(This function is for a bigger program that eventually prints out a pyramid.)
package skener;
import java.util.Scanner;
public class MyClass
{
public static int z = 0;
public static int userInput()
{
Scanner height = new Scanner(System.in);
System.out.println("Please choose a number: ");
while(!height.hasNextInt() || (height.nextInt() < 0))
{
//height = new Scanner(System.in);
System.out.println("Wrong number, try again: ");
height = new Scanner(System.in);
}
z = height.nextInt();
height.close();
return z;
}
public static void main(String[] args)
{
System.out.println(userInput());
}
}
If user input is 3, I expect to get return 3, to use in another program. Instead the program simply terminates and the terminal doesn't provide any error messages and doesn't return the input.
your program should be like below,
Scanner height = new Scanner(System.in);
System.out.println("Please choose a number: ");
z = height.nextInt();
while((z < 0))
{
System.out.println("Wrong number, try again: ");
z = height.nextInt();
}
return z;
here we are getting the integer value in z and we are checking the condition and returning if it's positive or we will ask user to enter again. Please use import scanner module in import java.util.Scanner;
I believe this is what you want.
Scanner height = new Scanner(System.in);
System.out.println("Please choose a number: ");
int z = -1; // default value means no valid integer entered.
// ensure that the next value is an int and if so.
// it is >= 0.
while (height.hasNextInt() && (z = height.nextInt()) < 0) {
System.out.println("Wrong number, try again: ");
}
// Display the value
System.out.println("z = " + z);
// and if in a method, return it.
return z;
Your solution was very close. You should not have closed the scanner because that also closes the Console input which you would not be able to re-open and read from.
And as you specified in your original code, if you don't check for a non-numeric value, before getting an int, your code will throw an exception.

in my code variable enter cannot be found by compiler...what to do?

/* Write a program that displays a menu with options 1. Add 2. Sub
Based on the options chosen, read 2 numbers and perform the relevant operation. After performing the operation, the program should ask the user if he wants to continue. If the user presses y or Y, then the program should continue displaying the menu else the program should terminate.
*/
import java.util.Scanner;
class menu
{
public static void main(String args[])
{
Scanner sc = new Scanner(System.in);
do
{
System.out.println("enter 1 for add and 2 for sub");
int a = sc.nextInt();
System.out.println("enter two numbers");
int b = sc.nextInt();
int c = sc.nextInt();
int d;
if (a == 1)
{
d = b + c;
System.out.println("sum is" + d);
}
else if (a == 2)
{
d = b - c;
System.out.println("difference is" + d);
}
System.out.println("to continue enter y or Y AND TO TERMINATE
ANY OTHER SYMBOL");
char enter = sc.next().charAt(0);
}
while (enter == 'y');
}
}
The reason enter is not recognized by the while loop is because it is in the local scope of the do code block. I would suggest defining enter before the do block like so
char enter;
do { pass; } while(true);
This will make it accessible to the while loop's Boolean expression and allows you to initialize enter by simply doing this
enter = sc.next().charAt(0);

Where should I put the variable scanner declaration? "int figureNumber = stdin.nextInt();"

I want to make it so that a user entering the wrong data type as figureNumber will see a message from me saying "Please enter an integer" instead of the normal error message, and will be given another chance to enter an integer. I started out trying to use try and catch, but I couldn't get it to work.
Sorry if this is a dumb question. It's my second week of an intro to java class.
import java. util.*;
public class Grades {
public static void main(String args []) {
Scanner stdin = new Scanner(System.in);
System.out.println();
System.out.print(" Please enter an integer: ");
int grade = stdin.nextInt();
method2 ();
if (grade % 2 == 0) {
grade -= 1;
}
for(int i = 1; i <=(grade/2); i++) {
method1 ();
method3 ();
}
}
}
public static void main(String args[]) {
Scanner stdin = new Scanner(System.in);
System.out.println();
System.out.print(" Welcome! Please enter the number of figures for your totem pole: ");
while (!stdin.hasNextInt()) {
System.out.print("That's not a number! Please enter a number: ");
stdin.next();
}
int figureNumber = stdin.nextInt();
eagle();
if (figureNumber % 2 == 0) { //determines if input number of figures is even
figureNumber -= 1;
}
for (int i = 1; i <= (figureNumber / 2); i++) {
whale();
human();
}
}
You need to check the input. The hasNextInt() method is true if the input is an integer. So this while loop asks the user to enter a number until the input is a number. Calling next() method is important because it will remove the previous wrong input from the Scanner.
Scanner stdin = new Scanner(System.in);
try {
int figureNumber = stdin.nextInt();
eagle();
if (figureNumber % 2 == 0) { //determines if input number of figures is even
figureNumber -= 1;
}
for(int i = 1; i <=(figureNumber/2); i++) {
whale();
human();
}
}
catch (InputMismatchException e) {
System.out.print("Input must be an integer");
}
You probably want to do something like this. Don't forget to add import java.util.*; at the beginning of .java file.
You want something in the form:
Ask for input
If input incorrect, say so and go to step 1.
A good choice is:
Integer num = null; // define scope outside the loop
System.out.println("Please enter a number:"); // opening output, done once
do {
String str = scanner.nextLine(); // read anything
if (str.matches("[0-9]+")) // if it's all digits
num = Integer.parseInt(str);
else
System.out.println("That is not a number. Please try again:");
} while (num == null);
// if you get to here, num is a number for sure
A do while is a good choice because you always at least one iteration.
It's important to read the whole line as a String. If you try to read an int and one isn't there the call will explode.
You can actually test the value before you assign it. You don't need to do any matching.
...
int figureNumber = -1;
while (figureNumber < 0) {
System.out.print(" Welcome! Please enter the number of figures for your totem pole: ");
if (stdin.hasNextInt()){
figureNumber = stdin.nextInt(); //will loop again if <0
} else {
std.next(); //discard the token
System.out.println("Hey! That wasn't an integer! Try again!");
}
}
...

Java- String index out of bounds exception " String index out of Range"

I am new to java, and going to bite the bullet by asking what is I am sure, a dumb question. I created some methods, and simply wanted to call them in main. I am getting an error for the while loop in the main method. The compiler is saying " Exception in thread main java.lang.StringIndexOutOfBoundsException: String index out of range:0 at java.lang.String.charAt(String.java:686) at Project3.main(Project3.java:61)
Any help would be greatly appreciated. Thanks. Full Code is below:
import javax.swing.JOptionPane;
import java.util.Scanner;
public class Project3
{
public static void main(String[] args)
{
int iScore1; //first variable input by user to calc average
int iScore2; //second variable input by user to calc average
int iScore3; //third variable input by user to calc average
double dAverage; //returned average from the three test scores
char cLetterGrade; //letter grade associated with the average
double dGPA; //the GPA associated with the letter grade
char cIterate = 'Y'; // loop check
String strAgain; //string user inputs after being asked to run again
System.out.print(createWelcomeMessage());
//pause in program
pressAnyKey();
while (cIterate == 'Y')
{
//prompt user for test scores
System.out.print("\n\nPlease enter the first test score: ");
Scanner keys = new Scanner(System.in);
iScore1 = keys.nextInt();
System.out.print("\nPlease enter the second test score: ");
iScore2 = keys.nextInt();
System.out.print("\nPlease enter the third test score: ");
iScore3 = keys.nextInt();
//calculate average from the three test scores
dAverage = calcAverage(iScore1, iScore2,iScore3);
System.out.print("\nThe average of the three scores is: " + dAverage);
//pause in program
pressAnyKey();
//get letter grade associated with the average
cLetterGrade = getLetterGrade(dAverage);
System.out.print("\nThe letter grade associated with the average is " + cLetterGrade);
//pause in program
pressAnyKey();
//get the GPA associated with the letter grade
dPGA = calcGPA(cLetterGrade);
System.out.print("\nThe GPA associated with the GPA is "+ dGPA);
//pause in program
pressAnyKey();
System.out.print("\nDo you want to run again?(Y or N):_\b");
strAgain = keys.nextLine;
strAgain = strAgain.toUpperCase();
cIterate = strAgain.charAt(0);
}//end while
//display ending message to user
System.out.print(createEndingMessage());
}//end main method
}//end class Project3
public static String createWelcomeMessage()
{
String strWelcome;
strWelcome = "Why hello there!\n";
return strWelcome;
}//end createWelcomeMessage()
public static String createEndingMessage()
{
String strSalutation;
strSalutation = "See you later!\n";
return strSalutation;
}//end createEndingMessage()
public static void pressAnyKey()
{
JOptionPane.showMessageDialog(null, "Press any key to continue: ");
}//end pressAnyKey()
public static int getTestSCore()
{
int iScore;
System.out.print("Enter a test score: ");
Scanner keys = new Scanner(System.in);
iScore = keys.nextInt();
return iScore;
}//end getTestSCore()
public static int calcAverage(int iNum1, int iNum2, int iNum3)
{
double dAverage;
dAverage = ((double)iNum1 + (double)iNum2 + (double)iNum3) / (double)3.0;
return dAverage;
}//end calcAverage(int iNum1, int iNum2, int iNum3)
public static char getLetterGrade(double dGrade)
{
char cLetter;
if (dGrade <60)
{
cLetter = 'F';
}
else if (dGrade >=60 && dGrade <70)
{
cLetter = 'D';
}
else if (dGrade >=70 && dGrade <80)
{
cLetter = 'C';
}
else if (dGrade >=80 && dGrade <90)
{
cLetter = 'B';
}
else if (dGrade >=90)
{
cLetter = 'A';
}
return cLetter;
}//end getLetterGrade(double dGrade)
public static double calcGPA(char cLetterGrade)
{
double dGPA;
if (cLetterGrade == 'A')
{
dGPA = 4.0;
}
else if (cLetterGrade == 'B')
{
dGPA = 3.0;
}
else if (cLetterGrade == 'C')
{
dGPA = 2.0;
}
else if (cLetterGrade == 'D')
{
dGPA = 1.0;
}
else
{
dGPA = 0.0;
}
return dGPA;
}//end calcGPA(char cLetterGrade)
You're reading three ints using scanner.nextInt(). Since nextInt does not consume any whitespace or newline after the read token, that means that if the user enters a number and presses enter, there's still a linebreak in the stream.
So when you call nextLine later it just reads that linebreak and returns the empty string.
Since calling charAt on an empty string will cause an out of bounds error, you get the error you get.
To fix this, either use next instead of nextLine, which will read the next word (consuming any whitespace before it), instead of the next line, or call nextLine twice. Once to consume the linebreak and once to read the actual line.
You should still check whether the user enters an empty line though.
The problem is caused by this line:
cIterate = strAgain.charAt(0);
The string apparently does not have a character at index 0, in other words, it is empty.
You may want to check the user input and ask again if none was supplied.
If you move line 67 or so, it's the line that ends the class. Move it to the end, and that brings it down to three errors. One of those three errors is a misspelling, the one about keys.nextLine needs () --> keys.nextLine() and the last error is that the method header returns an int, not a double. Doing this does generate another error, but if you set cLetter to a space in single quotes, ' ' then the code compiles.

Categories