How to Use Multiple Scanner Objects on System.In

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 Hellogoes to input1 then the Worldgoes 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.

  1. You should create one Scanner per input source. For example, one Scanner for each distinct input file, one for System.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 the Scanner, and kept for the next Scanner 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 on System.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.

  2. The second problem is that when you close() a Scanner that also closes the input source.

    In your case that means that you are closing System.in. And then you are creating a second Scanner to read from the (now closed) System.in.

    When you attempt to us a Scanner to read from a closed System.in, that leads to a NoSuchElementException.

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



Leave a reply



Submit