I am currently using two different scanners in my project in two separate classes: both take in user input that do different things. Calling the first scanner works normally, but when I try to call the second scanner, even after I've closed the first, it registers the input as null.
Class 1
Scanner scan = new Scanner(System.in);
public void foobar(){
System.out.println("Enter data: ");
String foo = scan.next();
scan.close();
class2.function(foo);
}
Class 2
Scanner scan1 = new Scanner(System.in);
public void foobar1(String foo){
System.out.println("Enter more data: ");
String fooo = scan1.Next();
//Automatically prints null here and closes program
}
Am I supposed to only use one Scanner somehow? Or do I use the Scanner class in some other manner? Thanks!
scan.close(); also closes System.in so that no more data can be read from the stream. So when you start reading from scan1, System.in will no longer return any data.
Therefore, don't close any Scanner instance until you're done with all the scanning if you're using the same input stream for all the instances.
Look at the docs of Scanner#close() for more info.
Closes this scanner. If this scanner has not yet been closed then if its underlying readable also implements the Closeable interface then the readable's close method will be invoked.
And if you look at the docs of System.in, you can see that it does implement the Closeable interface.
Thus the InputStream#close() is called and that closes the InputStream leaving you without a input stream to read data from.
Closes this input stream and releases any system resources associated with the stream.
No need to create two scanners, You can use same Scanner for both as once scan is closed Stream System.in also get closed.
like:
Scanner scan = new Scanner(System.in);
public void foobar(){
System.out.println("Enter data: ");
String foo = scan.next();
class2.function(foo,scan);
}
where:
public void function(String foo,Scanner scan1){
System.out.println("Enter more data: ");
String fooo = scan1.next();
System.out.println(fooo);
}
but still if you need to create two scanners use scan.reset(); instead of scan.close(); in class1
Related
Why isn't my inputScanner blocking after the first input? It goes into a continous loop. Ignore other details of this code.
public class Test {
public static void main(String[] args) {
boolean finished;
do {
Scanner inputScanner = new Scanner(System.in);
finished = inputScanner.hasNext("exit");
boolean validNumber = inputScanner.hasNextDouble();
if (validNumber) {
double number = inputScanner.nextDouble();
System.out.print(number);
} else if (!finished) {
System.out.println("Please try again.");
}
inputScanner.close();
} while (!finished);
}
}
EDIT: On a previous post which was related to this, it was mentioned that "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)". Why is this happening?
Why isn't my inputScanner blocking after the first input?
Because you're creating a new Scanner each time you enter the loop, so it's not the same object on 1st iteration than in 2nd and further iterations
public class Test {
public static void main(String[] args) {
boolean finished;
do {
Scanner inputScanner = new Scanner(System.in); //Here you're making a new instance of inputScanner each time you come to this line after the do-while loop ends.
finished = inputScanner.hasNext("exit");
boolean validNumber = inputScanner.hasNextDouble();
if (validNumber) {
double number = inputScanner.nextDouble();
System.out.print(number);
} else if (!finished) {
System.out.println("Please try again.");
}
inputScanner.close();
} while (!finished);
}
}
If you want it to be "blocked" or "closed", then move this line before the do { line.
Scanner inputScanner = new Scanner(System.in);
For your second question:
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)
From Oracle's docs:
"Attempting to perform search operations after a scanner has been
closed will result in an IllegalStateException"
It's like trying to make a dead person to do something, it would be like a zombie! (And Java hates zombies!) D:
But you're not getting that IllegalStateException because as I said on the answer for your 1st question, you're making a new object each time you go into the do-while loop.
Edit
Why can't you reopen it? Also from Oracle's docs:
When a Scanner is closed, it will close its input source if the source
implements the Closeable interface.
Thus inputScanner.close() closes System.in.
And because of the general contract for OutputStream's close (with the help of this answer):
public void close() throws IOException --> Closes this input stream and releases any system resources associated with this stream. The general contract of close is that it closes the input stream. A closed stream cannot perform input operations and cannot be reopened.
If you take a look at documentation of Scanners methods like hasNext(String) or hasNextDouble you will see that it
Throws:
IllegalStateException - if this scanner is closed
(emphasis mine)
So to throw IllegalStateException you first need to close Scanner, not stream from which it is reading data.
So lets take a look at this example:
Scanner sc = new Scanner(System.in);
System.out.println("type something:");
System.out.println(sc.hasNext());// true
System.out.println("your data: "+ sc.nextLine());
sc.close();
System.out.println("type something:");
System.out.println(sc.hasNext());// throws java.lang.IllegalStateException: Scanner closed
Last line throws IllegalStateException because you are invoking hasNext method on closed scanner (so we know that after invoking sc.close() stream from which it reads must be also closed so we can safely assume that there are no more elements to read, or since stream was closed we may not be allowed to read it).
Now if we don't close scanner but close System.in we will still be able to use this instance of scanner without getting exceptions. So lets simply change sc.close(); to System.in.close() (I will skip exceptions handling for simplicity):
Scanner sc = new Scanner(System.in);
System.out.println("type something:");
System.out.println(sc.hasNext());// true
System.out.println("your data: "+ sc.nextLine());
System.in.close();
System.out.println("type something:");
System.out.println(sc.hasNext());// false
As you can see there is no exception here because it wasn't scanner which was closed, but stream which scanner which was being read.
Why closing System.in doesn't cause scanner to throw exception?
I suspect that decision to not throw exception here was made with assumption that exception symbolize problem with code. If programmer allowed scanner to being closed he should also make sure that this particular closed instance of scanner will not be used anywhere.
Now returning false instead of throwing exception is normal reaction where there is no more elements to read. So if stream which scanner was reading was closed naturally (like when we read text file and read its last line so there is nothing more to read) scanner handles this situation like something normal (so there is no need to point that this is some exceptional situation).
Now in your loop you are kind of combining these two scenarios. Your code can be simplified to something like:
Scanner sc = new Scanner(System.in);
System.out.println("type something:");
System.out.println(sc.hasNext());// true
System.out.println("your data: "+ sc.nextLine());
System.in.close();
sc = new Scanner(System.in);//IMPORTANT
System.out.println("type something:");
System.out.println(sc.hasNext());// false
As you see in line
sc = new Scanner(System.in);//IMPORTANT
you are creating new instance of scanner which wasn't closed yet, so its hasXYZ methods always returns false because System.in can't provide no more values.
Additional trap
One problem which I didn't mentioned earlier is fact that in case of wrong input, which is neither "exit" nor double if you are are not consuming that invalid cached value from scanner by using any of nextXZY methods like hasNext("exit") or hasNextDouble will be still based on that invalid data, like:
Scanner sc = new Scanner("foo 1");
System.out.println(sc.hasNextInt());//false because `foo` is not integer
System.out.println(sc.hasNextInt());//also false because we are still
//reading `foo` which is not integer
String str = sc.next();//lets read (sonsume) foo
System.out.println(sc.hasNextInt());//true since 1 is integer
Solution
Simplest solution to such problem is creating only one instance of Scanner which will handle System.in and reuse it in your entire application. Then at the end of your application you can decide to close your scanner or System.in.
So your code can look like:
boolean finished;
Scanner inputScanner = new Scanner(System.in);
do {
finished = inputScanner.hasNext("exit");
boolean validNumber = inputScanner.hasNextDouble();
if (validNumber) {
double number = inputScanner.nextDouble();
System.out.print(number);
} else if (!finished) {
System.out.println("Please try again.");
inputScanner.next();// lets not forget to consume from scanner cached
// invalid data which is neither double or "exit"
}
} while (!finished);
inputScanner.close();
im trying to learn Java, meaning that my experience and knowledge is almost none, and i hope you can help me with this:
(The thought i had was like how you can name yourself in videogames, with the option to display the name in future instances without any deeper meaning later on)
import java.util.Scanner;
public class Playername {
public static void main(String[] args) {
public String getName();
Scanner Charname = new Scanner (System.in);
System.out.print ("What is your name?");
Charname.nextLine();
String getName = Charname;
System.out.print (Charname);
}
}
i probably messed this up, reading only the early chapters of a book about java and then trying to use commands and things in way's they were not supposed to be used.
(i wanted to save the name of the scanner and then copypaste it to the String variable)
thank you
PS: The error i get is "cannot convert from scanner to string", basically stating that my question would be how the idea i had can, in the most simplistic way possble, be realised.
Try this
Scanner Charname = new Scanner (System.in);
System.out.print ("What is your name?");
String input = Charname.nextLine();
String getName = input;
System.out.print (input);
You cannot assign scanner object directly to string reference.
You are trying to assign Charname which is a Scanner to a String
What you want to do is to assign Charname.nextLine() which is a String to your variable
Scanner Charname = new Scanner (System.in);
System.out.print ("What is your name?");
String getName = Charname.nextLine();
System.out.print(getName);
Welcome to StackOverflow!
Firstly, I'd like to start you off with some code conventions.
These help others read your code, since even though you may know what is going on; we may not.
Now, for your question.
Scanner scannerName = new Scanner (InputStream inputStream);
This line creates a Scanner object with the InputStream coming from the an input stream, and we name it scannerName. Generally, you want to label your objects what they are, or some abbreviation of that.
Scanner scanner1 = new Scanner(System.in);
This is sufficient for our purposes. Since we want to get information from the System.in inputstream, or console, we use System.in as our InputStream.
Now, this scanner object that we've created can receive input from the console. It does this through the use of methods like
scanner1.nextLine();
The above piece of code returns a String value.
Alone, it's pretty useless. So we'll assign a String object to take and store that value.
String characterName = scanner1.nextLine();
What this does is it sets the String's value to be equivalent to the value of the scanner1's inputstream, after hitting enter.
So if a user enters "Johnathan Nathan", and then presses Enter,the String named characterName will be set to "Johnathan Nathan".
A full working example is:
Scanner scanner1 = new Scanner(System.in);
System.out.println("Please enter your name: ");
String characterName = scanner1.nextLine();
System.out.println("Hello, " + characterName());
This would ask for the person's name, then say hello to them directly after.
Finally, if you have any questions regarding how a class is used, you can always look up the Javadoc of the class you're having problems with.
I can't conceptually understand in the below code (that retrieves characters from keyboards and prints to the command line) where I specified that input must come from the keyboard?
public class Adder
{
public static void main(String arr[])
{
//Explain this next line, please:
Scanner in = new Scanner(System.in);
System.out.println("Enter First No.");
int a = in.nextInt();
System.out.println("Enter Second No.");
int b = in.nextInt();
int c = a+b;
System.out.println("Sum is: "+c);
}
}
System.in isn't a method, it's a field that's tied to your keyboard by default.
The "standard" input stream. This stream is already open and ready to supply input data. Typically this stream corresponds to keyboard input or another input source specified by the host environment or user.
You can call the System.setIn(InputStream in) method to change it to a different input stream.
Reference: I/O from the Command Line
Scanner sc = new Scanner(System.in);
Lets break it down
Scanner: The Scanner class is a class in java.util, which allows the user to read values of various types
System.in: An InputStream which is typically connected to keyboard input of console programs
Scanner S = new Scanner(System.in)
above line will invoke Constructor of Scanner class with argument System.in, and will return a reference to newly constructed object.
S is connected to a Input Stream that is connected to Keyboard, so now at run-time you can take user input to do required operation.
further study:
Scanner (Java Platform SE 8)
let me know, if you have any confusion.
I've just learned about scanners but one thing I noticed was when I wrote
Scanner input = new Scanner(System.in); //Creates scanner object
System.out.println("Enter a line: "); //Ask for input
String line = input.nextLine(); //Enter input
System.out.println("You entered: " + line); //Output the input
System.out.println("And enter a number: ");
int value = input.nextInt();
System.out.println(value + " " + line);
the top line of code could be used for both thing I wanted to get input for (string and ints). My question is whether I should be using the same name for a scanner 'input' in this case for multiple things i'd like to input. I'm new so even if I can't find a problem that could come from using the same name, if later on in a big program this could become problematic?
See the scanner instance input is a reference and you are making it point to the standard input stream by specifying new Scanner(System.in);.
In a stream, everything will be in bytes, the methods nextLine() , nextInt() etc will scan / parse the stream and give you the data of that *particular type.
So using the same scanner instance i.e, input is fine because you are parsing data as you receive it.
Yes you can use the same scanner object until its not closed and pointing to input stream.
If you don't need it anymore then use close method to close the Scanner.
I have this code that calls to a method in order to check if a number is a certain length, and if not, a new number should be reintroduced by the user.
Problem here is, I can't find the proper way to close a Scanner class in order to prevent a resource leak.
Here's the code so far.
public static void setIdentification(Person p, int dni) {
Scanner input = new Scanner (System.in);
String lengthChecker = Integer.toString(dni);
if (lengthChecker.length() < 1 || lengthChecker.length() > 8) {
int dni1;
do{
System.out.println("The ID number isn't valid. Please, introduce a valid number: ");
dni1 = input.nextInt();
lengthChecker = Integer.toString(dni1);
} while (lengthChecker.length() > 8 || lengthChecker.length() < 1 );
p.dni = dni1;
} else {
p.dni = dni;
}
}
public static void main(String[] args) {
Scanner input1 = new Scanner (System.in);
int dni = input1.nextInt();
Person person1 = new Person();
setIdentification(person1, dni);
}
I have tried to set the input.close(); in a number of different locations but I always end up getting a run-time error.
There's probably a million ways to optimize this code but right now I'm just really curious as to how to get those Scanners closed.
#Jules is correct. In this case, it is neither necessary or advisable to close the Scanner.
But assuming that you did, then the recommended way to do it is this:
try (Scanner input1 = new Scanner (System.in)) {
int dni = input1.nextInt();
Person person1 = new Person();
setIdentification(input1, person1, dni);
}
... noting that you must change your setIdentification method so that it doesn't attempt to open its own scanner. Creating multiple scanners for the same input stream is a mistake. Indeed, it is the mistake in your code.
This works for Java 7 and later. (Under most circumstances, you should not be writing new code for older versions of Java. Android is an exception, because support for Java 7 extensions has only recently become available in Android toolchains.
So why can't you open and close multiple scanners on the same stream? Two reasons:
When you close a Scanner, you automatically close the underlying stream. That means if you then attempt to open / use another scanner on the stream, it will fail when you attempt to read from the closed stream. Streams cannot be reopened.
Even if you don't close the scanner / stream, creating a second scanner on a stream is likely to lead to trouble. A scanner has to read ahead in order to figure out where the token boundaries are. It then keeps any read-ahead characters in an internal buffer. Each scanner has its own buffer. So if you have two or more scanners for the same stream, and interleave their use, one scanner is liable to "grab" characters that the other scanner needs.
Closing your scanner will close the input stream it was created using. In your case, this is System.in. This stream is a special case: it is opened by the environment before your program starts running, and therefore should not usually be closed by your program.
In this case, it's fine to not close your Scanner. Just let the garbage collector deal with it.