How to use multiple Scanner objects on System.in?
What am I doing wrong?
Using multiple scanners on the same stream is the underlying problem. Scanners can (and will) consume the stream - this may (will) lead to unexpected side-effects. Best not to do it.
If the input is closed, then the input (but Strings have no close
method) is closed for everyone - and that's not much fun for anyone.
Edit: "Details" on why multiple scanners are bad: Do not create multiple buffered wrappers on an InputStream
...any buffered wrapper is unsafe; this condition is also exploitable if a Scanner is used instead...
See also Java code question ... scanner related? which also talks about some approaches.
How can I apply Scanner and multiple objects at the same time? - newbie
According to your question, you should create an object of the student class. So student class should contain
class Student {
// data members
String name;
int age, semester number;
float GPA;
}
And from main method you should be creating object of student class like:
Student std1 = new Student();
Student std2 = new Student();
Student std2 = new Student();
Now you can access the data members of each object like:
std1.name = "Some name" // std1.name = in.nextLine();
std1.age = // some age
std1.GPA = // your GPA
You can do the same for each object . Use appropriate way of taking input from the scanner object as you do and store it as shown above.
Finally calculate GPA and display:)
[Edited] Simple Example:
// import Scanner class for console base input
import java.util.Scanner;
// your student class
class Student {
// data members
String name;
int age;
float GPA;
// display method
void display() {
System.out.println("Your name: "+this.name);
System.out.println("Your age: "+this.age);
System.out.println("Your GPA: "+this.GPA+"\n");
}
}
// class which contain main method (enty point)
class StudentInfo {
public static void main(String[] args) {
// create object of scnner
Scanner in = new Scanner(System.in);
// create three different object of student
Student std1 = new Student();
Student std2 = new Student();
Student std3 = new Student();
// new set data for student
System.out.println("Enter name, age and GPA of student:");
//for first student
std1.name = in.next();
std1.age = in.nextInt();
std1.GPA = in.nextFloat();
// for second student
System.out.println("Enter name, age and GPA of student:");
std2.name = in.next();
std2.age = in.nextInt();
std2.GPA = in.nextFloat();
// for third student
System.out.println("Enter name, age and GPA of student:");
std3.name = in.next();
std3.age = in.nextInt();
std3.GPA = in.nextFloat();
// display info of each student
std1.display();
std2.display();
std3.display();
// now calculate Average GPA and display
float avg = (std1.GPA + std2.GPA + std3.GPA)/3;
System.out.println("Average GPA: "+ avg);
}
}
Cannot use multiple Scanner objects in Java
There's a couple of problems here.
First, you do not want to close the System.in
stream. Other parts of the program may be using it, and you don't want to interfere with their normal operation.
Second, there's no benefit to creating more than one Scanner object. It's simply reading input from a stream, and having more than one reference to that stream isn't necessary or beneficial to your operations.
To that end, the fix to this would be straightforward:
- Use only one instance of the Scanner attached to
System.in
, and - Remove the
close()
method call.
How to make multiple Scanners with the same input line?
One scanner is enough.
String input1 = User.next();
String input2 = User.next();
enter this values separated by space example you entered Hello World
.
the Hello
goes to input1
then the World
goes to input2
Multiple Scanner Inputs (Java)
You don't need multiple scanners. one is more than enough
By an input like 1 3 5
you can read that as a whole line(string)
Scanner sc = new Scanner(System.in);
String input1 = sc.nextLine();
System.out.println(input1);
or just get integer by integer
int inputA1 = sc.nextInt();
int inputA2 = sc.nextInt();
int inputA3 = sc.nextInt();
System.out.println("--------");
System.out.println(inputA1);
System.out.println(inputA2);
System.out.println(inputA3);
how to use two scanners on one method
This:
try (Scanner scanner = new Scanner(System.in)) {
// ...
}
is a try-with-resources block. When the block finishes executing, it will call scanner.close()
.
The problem with that, for your use case, is that the Scanner, in turn, invokes System.in.close()
. Once a stream has been closed, you can't read from it again, so you will get an exception when you try to create another Scanner reading from System.in
subsequently.
The most trivial fix to your code is to merge the two try-with-resources blocks, and reuse the same Scanner, so you don't close it in between. There is no good reason to have two separate scanners anyway.
But actually, you shouldn't be using try-with-resources at all.
The general rule is not to close a stream that you don't own, which roughly translates to don't close a stream you didn't open, given that Java has no concept of "ownership". You didn't open System.in
, the JVM did.
You don't know what else in your program is relying on it continuing to be open. If you do close such a stream, you mess up the state of the stream for future readers of the stream.
Now, you may think that you need to use twr, because your IDE flags a resource leak warning on the Scanner otherwise. In general, you may want to close a Scanner; in this specific case, you do not. Ignore (or suppress) that warning, if that is why you are using twr.
Proper way to use Scanner with multiple functions?
to use a single instance of Scanner (or any other datatype or class), you can use the design pattern "Singleton" which consist to instantiate a single instance of your Object for the whole project.
The Singleton definition (a new class) :
import java.util.Scanner;
public class ScannerSingleton {
private static Scanner sc = null;
private ScannerSingleton() {
sc = new Scanner(System.in);
}
public static Scanner getInstance() {
if (sc == null) {
synchronized(ScannerSingleton.class) {
if (sc == null)
sc = new ScannerSingleton();
}
}
}
}
and each time you want to use your scanner anywhere you only have to call ScannerSingleton.getInstance()
which will return your single instance of scanner
example of use:
String test = ScannerSingleton.getInstance().nextLine();
Should a Scanner only be instantiated only once? if that's the case why so?
There are actually two separate things going on here.
You should create one
Scanner
per input source. For example, oneScanner
for each distinct input file, one forSystem.in
, one for each distinct socket input stream.The reason is (as Chrylis points out) is that various methods of
Scanner
read ahead on the scanner's input source. If the characters are not consumed by the operation, they are not put back into the input source. Rather they are buffered by theScanner
, and kept for the nextScanner
operation to use. So if you have two Scanners trying to read from the same input source, one may steal input intended for the other.This is the real reason why opening multiple
Scanner
objects onSystem.in
is bad. Not the "redundancy" argument that you proposed. There is nothing fundamentally wrong with a bit of redundancy ... especially if it simplifies the application. But scanners competing for input may result in unexpected behavior / bugs.The second problem is that when you
close()
aScanner
that also closes the input source.In your case that means that you are closing
System.in
. And then you are creating a secondScanner
to read from the (now closed)System.in
.When you attempt to us a
Scanner
to read from a closedSystem.in
, that leads to aNoSuchElementException
.
So if you hadn't called close()
on the first Scanner
, your code might have worked, but that would depend on the sequence of operations you made on the first Scanner
.
People are saying
Scanner
ain't cloneable.
They are correct.
Related Topics
Javac Not Working in Windows Command Prompt
Getting the Inputstream from a Classpath Resource (Xml File)
Java - Swing Listen an Action in a Text Field of a Form
How to Read Request Body Multiple Times in Spring 'Handlermethodargumentresolver'
Compare One String with Multiple Values in One Expression
How to Compile a .Java with Support for Older Versions of Java
Java - How to Drag and Drop JPAnel with Its Components
Spring Qualifier and Property Placeholder
Cannot Find Firefox Binary in Path. Make Sure Firefox Is Installed
Are Java Primitive Ints Atomic by Design or by Accident
Raising a Number to a Power in Java
How to Make Anonymous Inner Classes in Java Static
How to Determine If a List Is Sorted in Java