Scanner Freezes Program When No Input Is Given - java

I'm making an application that is mainly used with pipes. At the start of the program, here is how I get all my input:
Scanner scanner = new Scanner(System.in);
List<String> input = new ArrayList<>();
while (scanner.hasNextLine()) {
input.add(scanner.nextLine());
}
scanner.close();
When used with pipes, this works well. For example, running ls | java -jar ... it prints out all the lines given from ls. However, when I just run java -jar ... with no input/pipe, it freezes and nothing happens. Even when I press enter and mash my keyboard it's still stuck. I can only stop the program by using ctrl-c. I think this is because there is nothing to read so Scanner waits until there is something to read. How do I read all lines from System.in without freezing, or is there a better way to do this? Thanks.
Edit:
Whoever marked this as a duplicate clearly did not read my question. My question was to check if the System.in was empty to not freeze the program, not how to get past the input stage. It is freezing because there is nothing in System.in so Scanner is taking forever, but I want to check if there is nothing in System.in.
Answer:
Thank you #QiuZhou for the answer. I modified his second example to get this:
List<String> input = new ArrayList<>();
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
while (reader.ready()) {
String nextLine = reader.readLine();
input.add(nextLine);
}
and it works like a charm.

It's freezing because, as you said, there is nothing to read so Scanner waits until there is something to read, but you want to read all lines from System.in without freezing, it sounds kind of conflicting to me, it's not like reading from a file, we don't know how many lines whoever using your program is going to type in, unless the person tell us. I suggest you define a special character as end of input, for example, done, when the person decides he has finished, just enter done to end waiting:
Scanner scanner = new Scanner(System.in);
List<String> input = new ArrayList<>();
System.out.println("Please enter something. Enter 'done' when finished.");
while (scanner.hasNextLine()) {
String nextLine = scanner.nextLine();
if(nextLine.equals("done"))break;
input.add(nextLine);
}
scanner.close();
To check if there is something to read in System.in without being stuck there, you can do it by using BufferedReader.ready(), as the document reads, Note that in.ready() will return true if and only if the next read on the stream will not block.
System.out.println("Please enter something. Enter 'done' when finished.");
List<String> input = new ArrayList<>();
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
while(true) {
if (reader.ready()) {
String nextLine = reader.readLine();
if(nextLine.equals("done"))break;
input.add(nextLine);
}
//since ready() will not block, you can add additional logic here, like if it
//takes too long to read next line from input, you can just end here
// break;
}

Related

Java: Read input without knowing number of input lines

This might be very very basic or may be something I am totally missing. I have started doing some competitive programming on online channels. I have to read comma separated strings and do some manipulations around it but the problem is that I do not know the number of lines of input. Below is the input example
Input 1
John,Jacob
Lesley,Lewis
Remo,Tina
Brute,Force
Input 2
Hello,World
Java,Coder
........
........
//more input lines
Alex,Raley
Michael,Ryan
I am trying to read input and breaking when end of the line is encountered but with no luck. This is what I have been trying
//1st method
Scanner in = new Scanner(System.in);
do{
String relation = in.nextLine();
//do some manipulation
System.out.println(relation);
}while(in.nextLine().equals("")); //reads only first line and breaks
//2nd method
Scanner in = new Scanner(System.in);
while(in.hasNext()){
String relation = in.next();
System.out.println(relation);
if(relation.equals("")){
break;
}
}
//3rd method
Scanner in = new Scanner(System.in);
while(true){ //infinite loop
String relation = in.nextLine();
System.out.println(relation);
if(relation.equals("")){
break;
}
}
Can somebody help here.
PS: Please don't judge. I am new to competitive programming though I know how to take user input in java and difference between next() and nextLine().
Im not gonna write why you shouldn't use Scanner. There are numerous articles why you shouldn't use Scanner in competitive programming. Instead use BufferedReader.
In competitive programming they redirect the input to your code from file.
It works like ./a.out > output.txt < input.txt for example.
So read until null is detected in the while loop.
public static void main(String args[] ) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String s;
while((s = br.readLine()) != null)
{
//System.out.println(s);
}
}
For testing through your keyboard, to simulate a null from your keyboard:
Press Ctrl+D. It will break out of the while loop above.
It should be fairly easy. Try
while(in.hasNextLine()){
String relation = in.nextLine();
if("exit".equalsIgnoreCase(relation))break;
//do some manipulation
System.out.println(relation);
}
The method Scanner#hasNextLine simply checks if there is a next line in the input, doesn't really advance the scanner. On the other hand, Scanner#nextLine reads the input as well as advances the scanner.
Update you might want to put some condition to exit the loop. E.g. the above snippet stops reading more input after it encounters a string "exit".
All your methods can be improved.
But let's consider your second method of while loop.
Scanner in = new Scanner(System.in);
String s;
while(in.hasNext()){
s=in.nextLine();
System.out.println(s);
}
In the same way, you can change each of your codes.
Also you can use BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); to buffer your input then check for in.readLine()) != null
Other than the above two methods (Buffered Reader method & Scanner method), I have another method for solving this issue. Have a look at the following code, you can catch NoSuchElementException to solve this issue , though I didn't recommended this as Exception handling is a costly process .
Out of all the methods, the Buffered should only be used during Competitive Coding as it has the least Complexity.
import java.util.*;
public class Program
{
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
try
{
while(true)
String a=sc.next();
System.out.print(a);
}
catch(NoSuchElementException k)
{
}
}
}

Code Behaving Differently On Different IDE

I am writing a program that takes information about a track and field competition and then does some computation with it. The issue I'm having now is only in the first user input section.
I first wrote my code in BlueJ and it worked fine. Then, I tried compiling it in JCreator and started getting this error where the program would only receive 3 user inputs before going onto the next piece of code when it should have received 5 (which it did when I compiled in BlueJ).
When I placed a System.out.println statement after the input statement however, the program (in JCreator) DID receive all 5 statements before proceeding. When I commented it out again, it only received 3 statements before continuing. Here is the code below.
String[] events = new String[5];
System.out.println("Please enter the 5 events in this competition.");
for(int i = 0; i < events.length; i++)
{
events[i] = input.nextLine();
System.out.println(i);
}
This is the output with the System.out.println statement.
This is the output with the System.out.println statement commented out.
Change the line
events[i] = input.nextLine();
to
String newLine;
while( (newLine = input.nextLine()).isEmpty() );
events[i] = newLine;
That should consume the extra newline characters and leave you with just the legitimate input in events.
The possible cause of your problem is newline characters, which are interpreted as line. It seems you are having additional newline characters in your input buffer.
You may check your IDE what character is provided when an enter key is pressed.
It seems you are using Scanner class to read input. You may try to wrap your System.in with InputStreamReader, that might help. (not sure, try it out)
Scanner input = new Scanner(new InputStreamReader(System.in));
events[i]=input.nextLine();
Instead you may also try to use BufferedReader to read the input.
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
events[i]=reader.readLine();
Hope it will help!!

Scanner nextLine, stuck in while loop or exiting at odd times

I started doing the CodeAbbey problems last night, they mentioned using stdIn since some the input data is long so copy/paste is much easier than by hand. I had never used the Scanner before so it looked easy enough. I got it working for single line inputs then I got a problem where the input was:
867955 303061
977729 180367
844485 843725
393481 604154
399571 278744
723807 596408
142116 475355
I assumed that nextLine would read each couple, xxxx yyyyy. I put the code in a while loop based on if nextLine is not empty. It runs, but I get weird output, and only after I hit return a few times.
package com.secryption;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
System.out.println("Input: ");
Scanner scanner = new Scanner(System.in);
String input = "";
while(!(scanner.nextLine().isEmpty())) {
input = input + scanner.nextLine();
}
String[] resultSet = input.split("\\s+");
for(String s : resultSet) {
System.out.println(s);
}
}
}
I thought I might need something after adding scanner.nextLine() to input. I tried a space and that didn't help. I tried a newline and that didn't make it better.
This "should" put all the numbers in a single array, nothing special. What am I missing with scanner?
EDIT: Ok so #Luiggi Mendoza is right. I found this How to terminate Scanner when input is complete? post. So basically it it working, I just expected it to do something.
The problem is here:
while(!(scanner.nextLine().isEmpty())) {
input = input + scanner.nextLine();
}
Scanner#nextLine reads the line and will continue reading. You're reading two lines and not storing the result of the first line read, just reading and storing the results of the second.
Just change the code above to:
StringBuilder sb = new StringBuilder();
while(scanner.hasNextLine()) {
sb.append(scanner.nextLine()).append(" ");
}
hasNext() is an end of file indicator that terminates by combining keys control d on Mac ox and control z on windows pressing enter won't send the right message
to JVM

java.util.Scanner: keeps waiting for additional input

Total Java newbie here. Working on one of my very first Java programs. Please help.
Here's what I am trying to achieve:
I need to accept user keyboard input of whitespace separated integers, copy them into an array and process them. KNOWN: user will enter only ONE line of data. I don't know how many numbers, but once they hit Enter, there won't be any more. As user input may contain words and special characters, I need to handle them with neat errors and prompt user to try again. When I run what I wrote below, I get in some kind of infinite loop where Scanner keeps waiting for additional input. How do I tell it it's over and there won't be any more input?
Here's the code:
<!-- language-all: java -->
public static void EnterInts () {
System.out.println("Enter series of integers separated by whitespace. Press Enter key when finished.");
Scanner input = new Scanner(System.in);
while (input.hasNext()){
if (input.hasNextInt(){
int i = input.nextInt();
System.out.println(i);
}
else {
System.out.println("Only integers can be entered. Try again.");
}
}
}
Seems like you should read the single line of input first, then create the Scanner to scan through that single line.
Try using a BufferedReader and InputStreamReader to read the line first:
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String str = in.readLine();
And then create the Scanner, perhaps passing a StringBufferInputStream created from the read string into its constructor.

Java Scanner won't "finish" reading input

I've been having trouble using java's Scanner class. I can get it to read my input just fine, but the problem is when I want to output something. Given multiple lines of input, I want to print just ONE line when all the input has been read completely. Here's the code I use for reading input:
public static void main(String[] args){
Scanner scanner = new Scanner(System.in); //scanner reads block of input
while(scanner.hasNextLine()){
//body of loop goes here
String s = scanner.nextLine();
Scanner ls = new Scanner(s); //scanner to parse a line of input
while(ls.hasNext()){
//body of nested loop goes here
ls.next();
}
}
System.out.println("Fin");
}
Even when all lines of input have been read, the program doesn't reach the System.out.println message. (Note that the message can't go anywhere else or it will output as many times as the loop is run). How do I fix this? Any help would be greatly appreciated.
As I can see in your outer while loop you have used
scanner.hasNextLine();
method. This method gets blocked if it has to wait for the input. Also you have
Scanner scanner = new Scanner(System.in);
statement. So the system.in will be waiting for input all the time, hence the hasNextLine() method has to wait for the input.
That is why the control gets stuck in the loop and can't proceed further.
To fix it you can first store input in a string variable and the call the scanner constructor on it.
You are reading from an Infinite stream in this case. hasNextLine() will keep returning true if there is another line in the input of this scanner. As its a System.in, it will keep reading from the Keyboard, unless you terminate it or tell the stream to stop.
Press "ctrl+Z" in the end, you will see that it works.
Edit : You could do something like this...
Scanner scanner = new Scanner(System.in); //scanner reads block of input
int BLOCK_SIZE =3,count=1;
while(scanner.hasNextLine()){
//body of loop goes here
String s = scanner.nextLine();
Scanner ls = new Scanner(s); //scanner to parse a line of input
while(ls.hasNext()){
//body of nested loop goes here
ls.next();
}
if(count++==BLOCK_SIZE)
{
break;
}
}
System.out.println("Fin");
}
You need to tell the program that there is going to be no more input. This is done by appending an EOF character. This can be done manually on Linux by pressing Ctrl-D in the console. I think on Windows you can press Ctrl-Z. The stream will be automatically closed if you are piping input from one program to another.
eg.
cat filename | java MyJavaProgram
The magic of
Scanner scanner = new Scanner(System.in);
while(scanner.hasNextLine()){
Is that there will never stop being input from System (unless you close the input with ctrl+d (for macs)).
To stop the loop, I suggest throw something more in the condition than just hasNextLine().
E.g.
Scanner scanner = new Scanner(System.in); //scanner reads block of input
int BLOCK_SIZE =3,count=1;
while(scanner.hasNextLine() && count++ <= BLOCK_SIZE){ //<- Use count here.
//body of loop goes here
String s = scanner.nextLine();
Scanner ls = new Scanner(s); //scanner to parse a line of input
while(ls.hasNext()){
//body of nested loop goes here
ls.next();
}
}
System.out.println("Fin");
}

Categories

Resources