Use of Scanner class in recursive functions - java

I am trying to use a recursive method/function, which uses the Scanner class. Closing the scanner, causes an exception to be thrown the next time the same method is called within the recursion. A workaround to this is not to close the scanner at all, but this is not a right approach. I suspect the same scanner object is used between recursive calls, so that's why closing it creates havoc. If my assumption is correct then closing the scanner in the last method call would be a valid workaround (i.e. no actual resource leak). Is there anything I may be missing before jumping into Scanner and related implementation code?
EDIT
The answers provided were really useful and enlightening. In summary, the problem is the constant re-opening and closing of the scanner, and not recursion per se. The reason I would avoid passing the scanner object as parameter is that this example simulates a larger project, calling multiple recursive functions and I would have to pass the scanner object in all of them.
On the practical side, and from the answers provided, I think just closing the scanner in the last recursive call would work without having any resource leaks. Any related opinions would be welcome, esp. if you see something wrong with my approach.
Here is an example of my initial experiment:
package scanner;
import java.util.Scanner;
public class Main {
public static void acceptValidInput() {
System.out.print("Enter a number greater than 10: ");
Scanner sc = new Scanner(System.in);
int i = sc.nextInt();
// Adding this will make an exception to be thrown:
sc.close();
if (i <= 10) {
acceptValidInput();
}
}
public static void main(String[] args) {
acceptValidInput();
System.out.println("Your input is valid");
}
}

Once you start to consume an input stream using a Scanner, you should not try to read from it in any other way anymore. In other words, after you have constructed a Scanner to read from System.in, you need to use it for all further reading from System.in. This is because Scanner buffers input, so you have no idea how much input it has already consumed but not emitted yet.
Therefore, I recommend that you construct one Scanner, then use it for all the reading:
public class Main {
public static void acceptValidInput(Scanner sc) {
System.out.print("Enter a number greater than 10: ");
int i = sc.nextInt();
if (i <= 10) {
acceptValidInput(sc);
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
acceptValidInput(sc);
System.out.println("Your input is valid");
sc.close();
}
}

It works:
package scanner;
import java.util.Scanner;
public class Main {
public static void acceptValidInput(Scanner sc) {
int i = sc.nextInt();
if (i <= 10) {
System.out.print("Enter a number greater than 10: ");
acceptValidInput(sc);
}
}
public static void main(String[] args) {
System.out.print("Enter a number greater than 10: ");
Scanner sc = new Scanner(System.in);
acceptValidInput(sc);
sc.close();
System.out.println("Your input is valid");
}
}
The result is:
Enter a number greater than 10: 4
Enter a number greater than 10: 5
Enter a number greater than 10: 11
Your input is valid
Process finished with exit code 0

Closing the scanner closes also the underlying input stream. In this case it is the System.in stream - you shouldn't do this. Either do not close it or create a single scanner for all method calls.

public class abc{
public void acceptValidInput() {
System.out.print("Enter a number greater than 10: ");
Scanner sc = new Scanner(System.in);
int i = sc.nextInt();
// Adding this will make an exception to be thrown:
if (i <= 10) {
acceptValidInput();
}
}
public static void main(String[] args) {
while(true){
abc a=new abc();
a.acceptValidInput();
System.out.println("Your input is valid");
}
}}
try this.

Related

Scanner variable cannot be resolved

In my program, the user will be asked to input 3 integers. The integers will then be read using the Scanner class and listed back to the user.
This is my code:
import java.util.Scanner;
public class Echoer
{
public static void main(String[] args)
{
/* The Data Below Will Read The Numbers Input Into The Prompt*/
Scanner input = new Scanner(System.in);
System.out.println("Please Enter Three Integers: ");
int number;
number = input.nextInt();
Scan.close();
System.out.println("Thanks. The Numbers You Entered Are: " + number);
}
}
This is the error it returns:
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
Scan cannot be resolved
Why does it return this error? How can I fix this issue?
In your code, you never defined what Scan was. Use input.close() rather than Scan.close().
Scan cannot be resolved
means that you never defined Scan. This is because you said Scan.close(). You need to change it to input.close() because input is the name of the instance of the Scanner class.
As others pointed out, you have to close input instead of Scan as shown below.
import java.util.Scanner;
public class Echoer
{
public static void main(String[] args)
{
/* The Data Below Will Read The Numbers Input Into The Prompt*/
Scanner input = new Scanner(System.in);
System.out.println("Please Enter Three Integers: ");
int number;
number = input.nextInt();
input.close();
System.out.println("Thanks. The Numbers You Entered Are: "+number);
}
}

My code isn't working

I am a beginner programmer and i am trying a program for my father.
import java.util.*;
import java.lang.*;
import java.io.*;
class Employee
{
String m1,m2,m3,m4,m5,m6,m7;
void main()
{
Scanner w=new Scanner(System.in);
Scanner n=new Scanner(System.in);
System.out.println("Please enter your name ");
String name=w.nextLine();
System.out.println("Please choose your client");
System.out.println("1 - XXXXXX");
int client=n.nextInt();
m1=name;//Storing name
if(client==1)//If statement storing client
{
m2="XXXXXX";
}
else
{
System.out.println("You have entered a wrong choice");
return;
}
String msg=m1+"\t"+m2;
System.out.println(msg);
}
}
This Code will give the output "as you have entered a wrong choice'"
It jumps to elsse statement. What is the error and is there an easier way to run this program. Thanks
Could yo please inform me on my error as
Ok try this code:
import java.util.Scanner;
public class Try
{
static String m1,m2,m3,m4,m5,m6,m7;
public static void main(String[] args)
{
Scanner w=new Scanner(System.in);
System.out.println("Please enter your name ");
String name=w.nextLine();
System.out.println("Please choose your client");
System.out.println("1 - XXXXXX");
int client=w.nextInt();
m1=name;//Storing name
if(client==1)//If statement storing client
{
m2="XXXXXX";
}
else
{
System.out.println("You have entered a wrong choice");
return;
}
String msg=m1+"\t"+m2;
System.out.println(msg);
}
}
You have missed you main method signature. In Java there is a specification of main method. Your main method should be like
public static void main(String []args){
}
In your case you main method should be
public static void main(String args[]) {
String m1, m2, m3, m4, m5, m6, m7;
Scanner w = new Scanner(System.in);
Scanner n = new Scanner(System.in);
System.out.println("Please enter your name ");
String name = w.nextLine();
System.out.println("Please choose your client");
System.out.println("1 - XXXXXX");
int client = n.nextInt();
m1 = name;//Storing name
if (client == 1)//If statement storing client
{
m2 = "XXXXXX";
} else {
System.out.println("You have entered a wrong choice");
return;
}
String msg = m1 + "\t" + m2;
System.out.println(msg);
}
Your problem are the 2 scanners.
Because a scanner work with an iterator, that keep the position inside the given inputstream (in this case), when you instantiate the 2 scanners, they both set their iterator at the same position into the stream, then you use "w.nextLine();", and the first scanner advances trough the stream returning the first line, as you wish, but the second scanner, that you haven't used, is still at the beginning of the stream, so basically when you use n.nextInt();, the scanner tries to parse your name as int, and it's strange that it doesn't throws an InputMismatchException, as it should do ("https://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html#nextInt%28%29").
Rework your code as #Sarthak Mittal suggested and it should work.
PS: keep in mind indentation, it's important, really
First:
void main()
There is no such thing in Java. It should be,
public static void main(String[] args)
To know the meanings of public, static, String[] args read this: Explanation of 'String args[]' and static in 'public static void main(String[] args)'
Secondly,
int client = n.nextInt();
The value inside client depends on your input. If you input 2 or 3 instead of 1, your code'll definitely go to the else part. So make sure your input is 1.
Thirdly,
Get rid of the extra scanner. You need only one.
The rest of your code is ok.

To create a reference variable or not to when using Scanner class?

Normally, Scanner inputs are coded like this:
import java.util.Scanner;
public class ScannerWithReference {
public static void main(String[] args) {
System.out.println("Enter a double value: ");
Scanner input = new Scanner(System.in);
double newValue = input.nextDouble();
System.out.println(newValue);
}
}
However, you can also write them like this:
import java.util.Scanner;
public class ScannerWithoutReference {
public static void main(String[] args) {
System.out.println("Enter a double value: ");
double newValue = new Scanner(System.in).nextDouble();
System.out.println(newValue);
}
}
Both programs print out the double value from the same input. I understand why this works. I also understand that creating a reference variable input allows me to use input.close() to prevent resource leaks.
However, I don't know when to do it the first way or the second way. I normally see it written the first way. Can I get some clarification on why some would write this code the second way?
I would always do it the first way. The possibility or crashing because the scanner does not read a double is in my opinion as likely to happen as it is actually going to get a double.
Practice defensive programming at all times.
java.util.Scanner;
java.util.InputMismatchException;
public class ScannerWithReference {
public static void main(String[] args) {
double newValue = 0.0;
Scanner scanner = new Scanner(System.in);
System.out.println("Enter a double value: ");
try {
newValue = scanner.nextDouble();
System.out.println("Thanks for the double");
}
catch (InputMismatchException e) {
System.out.println("Sorry not a dobule, try again");
}
scanner.close();
}
}
its better to use the second one because its much more optimized code.
if you are a good programmer you can try the second one that pretty good.
for a beginner its better to use the first one its more descriptive and can understand whats actually happening.

Confusin Error with Scanner

I keep getting this error and I do not know why :
Exception in thread "main" java.util.NoSuchElementException
at java.util.Scanner.throwFor(Scanner.java:907)
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 Daily.takingData(Daily.java:33)
at Daily.main(Daily.java:20)
this is my code:
import java.io.*;
import java.util.Scanner;
public class Daily
{
private static int size;
public static void main(String[] args) throws Exception {
System.out.println("Please enter amount of rows");
Scanner scan1 = new Scanner(System.in);
size = scan1.nextInt();
scan1.close();
System.out.println();
takingData(size);
}
public static void takingData(int rows) throws Exception {
System.out.println("Enter 1 To View Number of Markets");
System.out.println("Enter 2 To View Start and End Dates of Markets");
System.out.println("Enter 3 To View Start and End Dates of Contracts");
System.out.println("Enter 4 To View Averages of Markets");
System.out.println("Enter 0 To Quit Program");
int choice = 0;
Scanner scan2 = new Scanner(System.in);
choice = scan2.nextInt();
System.out.println("Got here");
scan2.close();
if (choice == 0)
System.exit(0);
}
}
My Out put is :
Enter 1 To View Number of Markets
Enter 2 To View Start and End Dates of Markets
Enter 3 To View Start and End Dates of Contracts
Enter 4 To View Averages of Markets
Enter 0 To Quit Program
(error here)
You are getting an error because you close your scanner right after you scan:
size = scan1.nextInt();
scan1.close();
and then try to scan again in takingData
remove the scan1.close(); that is outside of your takingData.
When you close a Scanner, the InputStream that it is scanning from is also closed, in this case your System.in is being closed.
When a Scanner is closed, it will close its input source if the source implements the Closeable interface.
Taken from Scanner javadocs
The problem is that you're closing the first instance of Scanner here
scan1.close();
which is closing the associated InputStream (System.in) - this prevents the second Scanner instance of reading from the stream.
Don't close the scanner. Also you could create a single instance of Scanner for reading all values.
From a design point of view I would move from static methods to an OO approach with the single Scanner instance created in the constructor of Daily and all methods becoming instance methods. This will help with testability of the Object.
public class Daily {
private final Scanner scanner;
public Daily() {
scanner = new Scanner(System.in);
}
public int getRows() {
System.out.println("Please enter amount of rows");
return scanner.nextInt();
}
public static void main(String[] args) throws Exception {
Daily daily = new Daily();
int rows = daily.getRows();
int mainOption = daily.getMainOption(rows);
switch (mainOption) {
case 0: // TODO: refactor to use enums
System.exit(0);
}
}
public int getMainOption(int rows) {
System.out.println("Enter 1 To View Number of Markets");
System.out.println("Enter 2 To View Start and End Dates of Markets");
System.out.println("Enter 3 To View Start and End Dates of Contracts");
System.out.println("Enter 4 To View Averages of Markets");
System.out.println("Enter 0 To Quit Program");
return scanner.nextInt();
}
}
The answer to your question is here: https://stackoverflow.com/a/13042296/1688441 for question:
java.util.NoSuchElementException - Scanner reading user input
I am quoting:
When you call, sc.close() in first method, it not only closes your
scanner but closes your System.in input stream as well. This you can
verify by printing its status at very top of the second method as :
System.out.println(System.in.available());
So now when you re-instantiate, Scanner in second method, it doesn't find any open
System.in stream and hence the exception.
Get rid of the initial int choice, and try this:
int choice = scan2.nextInt();
Shouldn't really make a difference, but it could help.

initialization problems?

I am trying to make a program that lets the user enter an unknown value of names and then output the longest name entered. This is my code so far. When i compile I have several errors and they are all the same "cannot find symbol". Do i need to initialize those variables if so where?
import java.util.Scanner;
public class Name
{
public static void main(String[] args)
{
Scanner kb = new Scanner(System.in);
longestName(kb);
}
public static void longestName(Scanner sc)
{
String name=kb.nextLine();
biggestName=name;
System.out.println("Type -1 if you want to quit");
int number=kb.nextInt();
While (number !=-1);
{
String name1=kb.nextLine();
if (name1.length() > biggestName)
{
biggestName=name1;
}
System.out.println("Do you want to continue? Type -1 to quit.");
int number1=kb.nextInt();
}
System.out.println("Longest name is "+biggestName);
}
}
Thanks for the help guys fixed the errors, and some other changes and the program gives the correct output.
import java.util.Scanner;
public class Name
{
public static void main(String[] args)
{
Scanner kb = new Scanner(System.in);
longestName(kb);
}
public static void longestName(Scanner kb)
{
String biggestName;
System.out.println("Enter the first name");
String name=kb.nextLine();
biggestName=name;
System.out.println("Type -1 if you want to quit");
int number=kb.nextInt();
while (number !=-1)
{
System.out.println("Enter another name");
Scanner kb1 = new Scanner(System.in);
String name1=kb1.nextLine();
int length1=biggestName.length();
int length2=name1.length();
if (length2 > length1)
{
biggestName=name1;
}
System.out.println("Do you want to continue? Type -1 to quit.");
number=kb.nextInt();
}
System.out.println("Longest name is "+biggestName);
}
}
There are quite a few errors in your code. Without explaining every error in detail, here is an example of a modified version which works:
import java.util.Scanner;
public class Name
{
public static void main(String[] args)
{
Scanner kb = new Scanner(System.in);
longestName(kb);
}
public static void longestName(Scanner sc)
{
System.out.println("Enter name, or type '-1' if you want to quit");
String name=sc.nextLine();
String biggestName="";
while (!name.equals("-1"))
{
if (name.length() > biggestName.length())
{
biggestName=name;
}
name=sc.nextLine();
}
System.out.println("Longest name is "+biggestName);
}
}
You passed in your Scanner to longestName, but in longestName, you named the parameter sc. Use sc instead of kb in longestName.
Use lowercase while instead of While; remove the semicolon following the while; a semicolon there means that that is the body, instead of the { } block below it.
I assume that at the bottom of the while loop, that you want to assign the next integer to number, not a new variable number1 that immediately goes out of scope.
You didn't declare what biggestName is (or name).
Two errors here :
While (number !=-1);
While should be while, and the ; makes an infinite loop.
And another problem is that you don't change number in the loop anyway.
1-
public static void longestName(Scanner sc)
Either change the name of the scanner to kb, or change every kb within the method to sc.
2- See Scanner issue when using nextLine after nextXXX
3- Use while instead of While, and remove the ;.
I can see the below problems in the code:
longestName() method should be using the reference name sc instead of kb (since kb is having scope only in main method)
The variable biggestName is not declared. It should be either declared as a class variable or a variable in longestName() method and should be of type String
It is not While, it is while with 'w' in smaller case
There should not be a semicolon after the while statement
At the end of the while loop, the number to be compared for the while loop is to be calculated and is currently assigned to wrong variable. kb.nextInt() should be assigned to variable number and not to number1 since the variable number1 is never read/used.
The > operator can not be applied for String types. In the line if (name1.length() > biggestName), we are comparing int with String and will result in compilation error. The line should be modified as if (name1.length() > biggestName.length())
Method nextInt() will cause InputMismatchException to be thrown if you are providing an input which is not a number.
Now I feel I should have written a corrected code like Joe Elleson did. But hope this answer helps.

Categories

Resources