Scanner exception in a biggner project (student management app) [duplicate] - java

Say I have the following example code:
Scanner scan1 = new Scanner(System.in); // declaring new Scanner called scan1
int x = scan1.nextInt(); // scan for user input and set it to x
System.out.println(x); // print the value of x
scan1.close(); // closes the scanner (I don't know exactly what this does)
Scanner scan2 = new Scanner(System.in); // declaring new Scanner called scan1
int y = scan2.nextInt(); // scan for user input and set it to y
System.out.println(y); // print the value of y
I read the Oracle documentation on the Scanner class and came across this:
When a Scanner is closed, it will close its input source if the source implements the Closeable interface.
Does this mean that once a Scanner (of System.in) is closed, I will no longer be able to use System.in throughout the entire Java program? Or does it mean I will no longer be able to use it throughout the class? Or only the method? Or only its scope?
Another question I have is, is a Scanner restricted to the scope it was declared in (similar to the primitive data types)?

Yes, it does mean that System.in will be closed. Test case:
import java.util.*;
public class CloseScanner {
public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(System.in);
scanner.close();
System.in.read();
}
}
This code terminates with
$ java CloseScanner
Exception in thread "main" java.io.IOException: Stream closed
at java.io.BufferedInputStream.getBufIfOpen(BufferedInputStream.java:162)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:206)
at java.io.BufferedInputStream.read(BufferedInputStream.java:254)
at CloseScanner.main(CloseScanner.java:7)
Once closed, you won't be able to use System.in for the rest of your program. The fact that close() is passed through is nice because it means you don't have to maintain a separate reference to the input stream so that you can close it later, for example:
scanner = new Scanner(foo.somethingThatMakesAnInputStream());
You can do that and call .close() on the scanner to close the underlying stream.
In most cases you won't want to close System.in, so you won't want to call .close() in that case.

Related

Java - program skips Scanner(System.in) [duplicate]

This question already has an answer here:
How to use java.util.Scanner to correctly read user input from System.in and act on it?
(1 answer)
Closed 5 years ago.
public static char[] puzzleInput() {
printEnterPuzzleMessage();
Scanner puzzleS = new Scanner(System.in);
if(puzzleS.hasNext()) {
char[] puzzle = puzzleS.next().toCharArray();
while(!isLegalPuzzleStructure(puzzle)) {
printIllegalPuzzleMessage();
puzzleInput();
}
return puzzle;
}
puzzleS.close();
return null;
}
public static void main(String[] args) throws Exception{ //Q - 8
Scanner fileName = new Scanner(System.in);
if(!fileName.hasNext()) {
System.out.println("No argument has been received");
System.exit(0);
}
String filePath = fileName.nextLine();
fileName.close();
Scanner vocabulary = new Scanner(new File(filePath));
String[] vocabularyArr = scanVocabulary(vocabulary);
vocabulary.close();
printReadVocabulary(filePath, vocabularyArr.length);
printSettingsMessage();
printEnterPuzzleMessage();
char[] puzzle = puzzleInput();
Hi, a beginner in Java is here.
In the function puzzleInput, I open a Scanner to get an input from the user. For some reason, the program won't give me a chance to put in input, and therefor the argument (puzzle) gets a null as default, and later when puzzle is needed not as a null - throws a NullPointerException.
There are many other functions in the code, but most of them are just a print commands, and the ones who are not were being checked by me, and are OK.
The problem is just the scanner won't give me a chance to put in an input.
Some points I'd like to clarify further:
1. The first Scanner (fileName) is not being skipped by the program, and I'm able to give it an argument.
2. I made sure I closed all the other scanners i've opened before.
Can someone explain me what I'm doing wrong?
program won't give me a chance to put in input
Your problem is that you are closing your Scanner in main:
Scanner fileName = new Scanner(System.in);
...
fileName.close();
This in turn closes the System.in input-stream which then cannot be reused in your puzzleInput() method because it is already closed. The right thing to do here is to pass in the Scanner variable into your puzzleInput() method and continue to reuse it there and not try to open up a new Scanner.
public static char[] puzzleInput(Scanner scanner) {
printEnterPuzzleMessage();
if(scanner.hasNext()) {
...
// don't close it here
return null;
}
...
Scanner scanner = new Scanner(System.in);
...
puzzleInput(scanner);
Couple of other comments:
Calling a Scanner fileName is not a good pattern. Choosing good names for your variables will help make the code self-documenting. scanner would be a better name of course.
When dealing with any input/output, it is a good practice to wrap any opening method in a try/finally block so it gets close properly. See also the try-with-resources functionality added in Java 7.
If you want a chance to do something with the input with a prompt, why not assign it to a String variable? This allows you to manipulate the input however you want later on too.
String input = scannerName.nextLine();

Unexpected behavior of Scanner [duplicate]

This question already has answers here:
Close a Scanner linked to System.in
(5 answers)
Closed 5 years ago.
In below code have two methods scanner1 and scanner2 in both methods new object of Scanner is created and scanning the input after that closing the Scanner by invoking close().
import java.util.Scanner;
public class TestScanner {
public static void scanner1(){
Scanner sc = new Scanner(System.in);//created object of scanner
System.out.println("Enter string :");
String input = sc.nextLine(); //scanning input
sc.close(); //closing scanner object
}
public static void scanner2(){//problem in scanner2
Scanner sc = new Scanner(System.in);//created another scanner object
System.out.println("Enter String :");
String input = sc.nextLine();//scanning object
sc.close();//closing the input
}
public static void main(String[] args) {
scanner1();
scanner2();//problem here
}
}
For scanner1 method working fine but when scanner2 method get invoked getting the below error:
Enter string : India Exception in thread "main"
java.util.NoSuchElementException: No line found Enter String : at
java.util.Scanner.nextLine(Unknown Source) at
cheggapril.TestScanner.scanner2(TestScanner.java:17) at
cheggapril.TestScanner.main(TestScanner.java:24)
Problem is why in scanner2 method scanner not able to scan the user input even in this method creating fresh one object of Scanner.
Please give some clear explanation. any ref or example will be much greatful.
The reason is quite simple, closing the 1st scanner object closes internally too the input stream which is actually being used by the second scanner
your options are: use only one scanner or close those when you are sure all of them are not required anymore..

How can I clear the input buffer to ignore input given before prompt?

I have a client/server game where users take turns giving input to the game. I want anything a user types when it is not their turn to be ignored. I want to scan only the inputs the user gives after they are prompted. I am using java.util.Scanner for input, but I can't find a way to "flush" the scanner buffer without the program hanging. I also cannot find examples of other input reading methods doing what I want.
This is what I tried:
Scanner in = new Scanner(System.in);
//do game stuff
//I don't care about anything typed at this time
while(in.hasNextLine()){
in.nextLine();
}
System.out.println("Enter your move:");
String input = in.nextLine();
There is no way to disable a Scanner and re-enable it. Here are a few suggestions:
You can manually empty the Scanner before the player's turn like so (what (I think) you've been doing):
while(in.hasNext()) in.next();
Or, you can close the scanner at the end of the player's turn and instantiate a new one at the beginning of the next turn (you can't reopen a closed Scanner):
//Player's turn
//
//End of player's turn...
in.close();
//Beginning of player's turn
in = new Scanner(System.in);
This, however, will throw an IllegalStateException if you try to access the Scanner after it has been closed. To solve this, try (on Java 7 and later) the try-with-resources block:
//Overridden close method because you don't want to close System.in
try (Scanner in = new Scanner(new InputStreamReader(System.in)
{public void close() throws IOException {}})) {
System.out.println("Enter your move:");
String input = in.nextLine();
}
//End of player's turn
//Scanner is automatically closed and this code is out of the scanner's scope
I think this last option is your best bet. It restricts the scope of the Scanner to the relevant code, and it automates the instantiating/closing. Plus, it uses a (relatively) recent Java feature, so that might be the required answer to your problem.

Scanner objects in methods and NoSuchElementException [duplicate]

This question already has answers here:
java.util.NoSuchElementException - Scanner reading user input
(5 answers)
Closed 7 years ago.
I have really tried to find the answer through the threads but still hope to get some feed back.
The code below is bad style I think but I don't know why it shoot me a
java.util.NoSuchElementException after enter the number since I make two Scanner objects for two methods and I should be able to start a new input. And if I erase the input.close() in inputAndPrintNumber(), it works and compile correctly. I really hope to know why and how to fix it if I still use two Scanner obj and without erasing the input.close() if possible.
import java.util.*;
public class t{
public static void main(String [] args){
inputAndPrintNumber();
inputAndPrintString();
}
public static void inputAndPrintNumber(){
Scanner input = new Scanner(System.in);
String s = input.nextLine();
System.out.print(s);
input.close();
}
public static void inputAndPrintString(){
Scanner input2 = new Scanner(System.in);
int a = input2.nextInt();
System.out.print(a);
}
}
I don't even sure whether the code below is better or any better idea?
import java.util.*;
public class t{
public static Scanner input = new Scanner(System.in);
public static void main(String [] args){
inputAndPrintNumber();
inputAndPrintString();
input.close();
}
public static void inputAndPrintNumber(){
String s = input.nextLine();
System.out.print(s);
}
public static void inputAndPrintString(){
int a = input.nextInt();
System.out.print(a);
}
}
When you call scanner.close() it not only closes scanner, but also stream from which it reads data, in this case System.in. So if you are going use System.in later don't close it (if it is closed, we can't reopen it and read any data from it, hence exception).
Your second code example solves this problem because Scanner is being closed when you are sure that nothing else will be read from input stream.
BTW it seems that you mixed places where nextLine and nextInt should be invoked (nextLine seems to be more appropriate for inputAndPrintString while nextInt for inputAndPrintNumber).

Java Multiple Scanners

I have a class that creates multiple Integer objects and puts them into a LinkedList as shown below:
public class Shares<E> implements Queue<E> {
protected LinkedList<E> L;
public Shares() {
L = new LinkedList<E>();
}
public boolean add(E price) {
System.out.println("How many of these shares would you like?");
Scanner scanInt;
scanInt = new Scanner(System.in);
Integer noShares = scanInt.nextInt();
for (int i = 0; i < noShares; i++) {
L.addLast(price);
}
scanInt.close();
return true;
}
}
I have an application that scans for the input "add" from the console and if found, invokes the method add as shown below:
public class Application {
private static Scanner scan;
public static <E> void main(String[] args) {
Queue<Integer> S = new Shares<Integer>();
scan = new Scanner(System.in);
System.out.println("Please type add");
String sentence = scan.nextLine();
while (sentence.equals("quit") == false) {
if (sentence.equals("add")) {
System.out
.println("What price would you like to buy your shares at?");
S.add((Integer) scan.nextInt());
} else
System.exit(0);
sentence = scan.nextLine();
}
}
}
The application should allow the user to enter "add" as many times as they wish but the error "no line found" appears after the add method has been invoked.
I'm guessing this is because the Scanner in the method, has not been closed and then reopened when needed. Is this what is wrong with the program and if so, how would I go about fixing it?
Please note, this program is not finished, as I will be adding a selling method that sells these shares. That is why I am using a while loop.
Having multiple wrappers for any stream is a great way to really confuse yourself. I suggest you only ever wrap a stream once unless you really know what you are doing.
The simplest way to do this is to use a singleton in this case as it wraps another singleton (the best is to pass around the Scanner as an argument)
public class Application {
// use this Scanner in all you other code, don't create another one.
static final Scanner scan = new Scanner(System.in);
public static <E> void main(String[] args) {
Im guessing this is because the scanner in the method has not been closed
Once you close a stream it closes the underlying stream and you can't use it again. Only close System.in if you want to prevent it being used again.
how would I go about fixing it?
The best solution is to have all your Scanner use in one place, one method or one class. You have your main() do all the interaction with the user and pass the values to your data structure. Having objects which initialise themselves is a bad practice to get into and if you start doing this, it will plague you for the rest of your development days ;) (Seriously you will see this done again and again and its often a nightmare)
BTW Never exit a program without explanation. Calling System.exit(0); without even an error message is also a nightmare. I once worked on a project which has 260 calls to System.exit() often without an error message, you can imagine how much fun it is to diagnose a server just stopping for no apparent reason.
A first mistake is that this line of code
scanInt.close();
closes the System.in, not just the scanInt object. This means that after the first call to add, the scan object will only consume the input it already has and then you'll receive a NoSuchElementException: Remove this line.
Now, if you replace the last line you have with this
sentence = scan.nextLine();
System.out.println("sentence: \"" + sentence + "\"");
you will see that the last input you get before exiting is an empty String. So in the next loop you enter the else statement and your program stops execution. You can fix this problem by adding the following:
scan.nextLine(); // consume the first always empty String...
System.out.println("Please type add");
sentence = scan.nextLine(); // and then get the actual value
However, I will agree with Peter that you should not use multiple wrappers. Consider passing the Scanner object as an argument in the Shares class contractor.
Having multiple scanners (on same stream) is a very bad practice, because scanners consume the stream they share.
I've verified it while debugging the Scanner class source code, and there I’ve found:
a reference to the source input stream
a internal private buffer used to hold input.
So when a scanner instance consume its stream, basically it just read a bunch of bytes (1024) and the stream's position is moved ahead.
For example when the nextLine() method is invoket, behind the scenes the source.read() copy the result into the private buffer.
Obviously the state of other Scanner becomes corrupted (invalid).
Try to debug the Java source code yourself and/or look at the method Scanner.readInput().

Categories