Scanner.nextLine() ignores whitespace? (Java) - java

I have a command-line game and am testing with JUnit, this is the test:
#Test
public void testBattle() throws IOException{
String input = "go forward\ngo left\ntake Pointy Stick\ngo backward\ngo " +
"right\nnormal attack\nnormal attack\nquit\n";
provideInput(input);
actual = new File("src/main/testFiles/testBattle.txt");
expected = new File("src/main/testFiles/testBattleExpected.txt");
PrintStream o = new PrintStream(actual);
System.setOut(o);
ui.gameLoop();
assertTrue(FileUtils.contentEqualsIgnoreEOL(actual, expected, null));
}
And this is the provide input method:
private void provideInput(String data) {
String newdata = data.trim();
testIn = new ByteArrayInputStream(newdata.getBytes());
System.setIn(testIn);
}
I'm doing scanner nextline so:
command = input.nextLine().toLowerCase().trim();
where "input" here represents the scanner object
but I'm still getting this error, specifically when the first "normal attack" is passed into System.in
java.util.NoSuchElementException: No line found
on that line above. I thought nextline ignored whitespace? If not did I format my string wrong to not include it?
EDIT:
From the first few lines of UI.gameLoop() I only initialize the scanner once.
public void gameLoop() throws IOException, JsonSyntaxException {
input = new Scanner(System.in);
engine = new GameEngine(path);

I thought nextline ignored whitespace?
Nope. According to the javadocs, it reads past the next end-of-line sequence (or to EOF), and then returns everything up to but not including the end-of-line sequence.
If you are getting
java.util.NoSuchElementException: No line found
that means that the Scanner has already reached the end of the input stream, or (maybe) the Scanner is trying to read from an input stream that was prematurely closed somewhere else in your code.
We can make guesses about what the real problem is, but without seeing >>your<< minimal reproducible example, we can't take this much further.
Actually, I just spotted a clue:
... I am testing with JUnit ...
This is possibly at the root of your problems. A JVM can only "read to the end of System.in" once in its lifetime. If you have two or more JUnit tests that need to do this, it is going to be difficult, unless you can find a way to "mock" the System.in variable.
It may be simpler to reorganize your code so that you take the input from some stream that is passed to your game code as a parameter. By reorganizing you can make it easier to write unit tests.

There's not a lot to go on, but I'm guessing you're creating multiple Scanners, one for each time you want to read a line. This usually works ok interactively since humans are slow typers, but fails when each Scanner's readahead ends up consuming multiple lines.
You can see the difference in this MCVE:
import java.util.*;
import java.io.*;
class Foo {
public static void main(String[] args) throws Exception {
String newdata = "go forward\ngo left\ntake Pointy Stick\ngo backward\ngo " +
"right\nnormal attack\nnormal attack\nquit\n".trim();
ByteArrayInputStream testIn = new ByteArrayInputStream(newdata.getBytes());
System.setIn(testIn);
boolean includeBug = Boolean.valueOf(args[0]);
if (includeBug) {
for(int i=0; i<8; i++) {
Scanner input = new Scanner(System.in);
System.out.println("Read: " + input.nextLine());
}
} else {
Scanner input = new Scanner(System.in);
for(int i=0; i<8; i++) {
System.out.println("Read: " + input.nextLine());
}
}
}
}
When includeBug is true, it creates a new Scanner for each line and crashes like you say. If it's false, it creates a single Scanner and works correctly:
$ javac Foo.java
$ java Foo true
Read: go forward
Exception in thread "main" java.util.NoSuchElementException: No line found
at java.util.Scanner.nextLine(Scanner.java:1540)
at Foo.main(Foo.java:17)
$ java Foo false
Read: go forward
Read: go left
Read: take Pointy Stick
Read: go backward
(etc)

Are you checking if it has a next line? With Scanners, you usually either have to handle the exception (not really something I'd prefer) or you have to use the hasNextLine() method to avoid the exception.
while (input.hasNextLine()) {
command = input.nextLine().toLowerCase().trim();
}

Related

Code after while loop never executes

Obviously, my real code is more complex, but here's an example:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in).useDelimiter("\n");
String[] cmdSplit = null;
while (true) {
while (input.hasNext()) {
cmdSplit = input.next().split("\\s+");
System.out.println("stuff");
}
for (int i = 0; i < cmdSplit.length; i++) System.out.println(cmdSplit[i]);
}
}
}
In the above example, the code takes input from System.in, splits it, and should output each piece. However, for some reason, the code after the inner while loop never executes. If I replace while with if, it works. If you test it, you can see it doesn't run infinitely, because it only prints "stuff" once, showing the loop runs once. What is the issue with the while loop?
Reading from System.in is different than reading from a file or other fixed-size source of input. The input doesn't necessarily exist until you create it, and so attempts to read it need to block until the input actually arrives (i.e. you type it). Try typing another line - you'll see the stuff message again; that will allow .hasNext() to return because there is now input.
To have .hasNext() return false the input source needs to be closed. For a command line application you can do this by sending the EOF signal (Ctrl+D on Linux) which tells the process stdin has no more input. That's not generally how you want a program to work, though, so if your intent is to only read one line and then move on, you should in fact be using an if instead of a while as you've tried to do. Later if you need to read more input you'll call .hasNext() again and your program will block there until the user passes more input.
As #user7 mentions your outer while (true) combined with while(input.hasNext()) is redundant. If you want to read only once get rid of the while (true) and use if (input.hasNext()). Otherwise if you want to read forever just combine the two loops:
while (input.hasNext()) {
cmdSplit = input.next().split("\\s+");
System.out.println("stuff");
for (int i = 0; i < cmdSplit.length; i++) System.out.println(cmdSplit[i]);
} // Loop will terminate once stdin is closed, e.g. by the user sending EOF.
Yes , your code won't go to the for loop because the Scanner.hasNext() will always listen to the console for inputs.
You have to break the loop in order to come out and go to the for loop.
Scanner input = new Scanner(System.in).useDelimiter("\n");
String[] cmdSplit = null;
while (true) {
while (input.hasNext()) {
cmdSplit = input.next().split("\\s+");
System.out.println("stuff");
break;
}
for (String element : cmdSplit) {
System.out.println(element);
}
}
The reason it is printing "stuff" only one time is because the hasNext() returned false.
Let me explain what I have observed.
To get "stuff" printed indefinately the assignment has to be removed. meaning once you assigned the input the scanner does not have any more token
The java.util.Scanner.hasNext() method Returns true if this scanner has another token in its input.
This will print indefinitely
while (input.hasNext()) {
// cmdSplit = input.next().split("\\s+");
System.out.println("stuff");
}

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

How to give a blank line to an InputStream using IOUtils.toInputStream

I have code which consumes an InputStream through a Scanner which looks like
String input = scanner.nextLine().toLowerCase();
if (input.isEmpty()) {
return defaultAnswer;
} else if (input.startsWith("y")) {
return true;
} else if (input.startsWith("n")) {
return false;
}
where the scanner is initialized by a given InputStream coming from IOUtils.toInputStream("someString").
How would I be able to test the if (input.isEmpty()) path?
EDIT:
I swapped two lines in my code, and empty string ("") results in a NoSuchElementException, and a newline or carriage return results in an empty string being returned.
Either using IOUtils.toInputStream("") or new ByteArrayInputStream(new byte[0]) may work.
The latter would certainly provide an empty stream, but it may make your code fail because there isn't an empty line to read - there's no line terminator. For example:
import java.io.*;
import java.util.*;
public class Test {
public static void main(String[] args) {
InputStream stream = new ByteArrayInputStream(new byte[0]);
Scanner scanner = new Scanner(stream, "UTF-8");
String line = scanner.nextLine();
System.out.println(line);
}
}
That fails with:
Exception in thread "main" java.util.NoSuchElementException: No line found
at java.util.Scanner.nextLine(Unknown Source)
at Test.main(Test.java:10)
You can use Scanner.hasNextLine() to check whether a call to nextLine() is appropriate or not. You may want to do that in your code. It really depends on whether you're trying to model "input ended without a line" or "the user entered an empty line". Those are significantly different situations, and you should consider both of them.
If you want to provide a stream which contains a line break (i.e. "the user entered an empty line") then you might want to use IOUtils.toInputStream("\n") instead. I'm nervous about the fact that that's not specifying a Charset though - you should carefully consider what encoding you expect your input to be in.

why my program never reach the solve method?

sorry if its a stupid question, but I a beginner using StreamTokenizer, I am trying to solve this exercise this, please help me, I dont know what its wrong in my program that never reach my solve method, it also never finishes, I already ask in timus forum, but I know that here is faster to receive an answers
import java.io.*;
public class Prueba {
static int index = 0;
static double[] l = new double[131072];
public static void main(String args[]) throws IOException {
StreamTokenizer str = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
while (((str.nextToken() != StreamTokenizer.TT_EOF))) {
if (str.ttype == StreamTokenizer.TT_NUMBER) {
l[index++] = str.nval;
//System.out.println(str.nval);
// System.out.println(l[0]);
// System.out.println(l[1]);
}
}
solve();
}
public static void solve() {
double res;
for (int i = index - 1; i >= 0; i--) {
res = Math.sqrt(l[i]);
System.out.println(String.format("%.4f\n", res));
}
}
}
You are reading from the standard input, and your code loops until it gets a TT_EOF. To feed a TT_EOF into your program, you need to press Ctrl-D if you're using Unix, or Ctrl-Z followed by Enter if you're using Windows.
You are waiting on System.in, it is blocking on read, ergo, you will never get to EOF so you while loop will continue to wait for input.
As it is, you either need to pipe a file from command line, or enter text on console followed by EOF character. Pressing Ctrl+Z generates EOF in Windows, and pressing Ctrl+D generates EOF in Unix/Linux.
EDIT: If your input is single line you can check for TT_EOL instead of TT_EOF.
You must call eolIsSignificant(true) before entering the loop. This will make sure end-of-line is treated as separate token

Problem in looping when using method in Java

I'm doing a simple program regarding methods.
But I have one problem. Everything is already working except when looping.
When I choose to loop again. The program skips on inputting the name. And proceeds directly to the year and section.
Here's the code:
public static void main(String[] args) {
do{
System.out.println("Input info:");
name=stringGetter("Name: ");
yearandsec=stringGetter("Year and section: ");
sex_code=charGetter("Sex code: " + "\n" + "[M]" + "\n" + "[F]:");
scode=intGetter("Scholarship code: ");
ccode=intGetter("Course code: ");
units=intGetter("Units: ");
fee_per_unit=doubleGetter("Fee per unit: ");
misc=doubleGetter("Miscellaneous: ");
display();
switches(scode, units, fee_per_unit, misc);
System.out.println("Another?");
dec=rew.nextInt();
}while(dec==1);
}
Here's the method getting the value for name together with the year and section:
public static String stringGetter(String ny){
String sget;
System.out.println(ny);
sget=rew.nextLine();
return sget;
}
I'm really annoyed with this problem, and I don't have any idea on how to fix this. Please help. thanks
Here is a simpler and more complete program that reproduces the error:
public static Scanner rew = new Scanner(System.in);
public static void main(String[] args) {
int dec;
do {
System.out.println("Input info:");
String name=stringGetter("Name: ");
String yearandsec=stringGetter("Year and section: ");
dec=rew.nextInt();
} while(dec==1);
}
public static String stringGetter(String ny){
System.out.println(ny);
return rew.nextLine();
}
The problem is that after calling nextInt() the call to nextLine() reads up to the new line after the int (giving a blank line), not up to the next new line.
If you change dec to a String and change dec=rew.nextInt(); to dec=rew.nextLine(); then it will work fine. Here is a complete example that you can copy and paste into a blank file to see that it works correctly:
import java.util.*;
public class Program
{
public static Scanner rew = new Scanner(System.in);
public static void main(String[] args) {
String dec;
do {
System.out.println("Input info:");
String name = stringGetter("Name: ");
String yearandsec = stringGetter("Year and section: ");
dec = stringGetter("Enter 1 to continue: ");
} while(dec.equals("1"));
}
public static String stringGetter(String ny){
System.out.println(ny);
return rew.nextLine();
}
}
You may also want to consider adding proper parsing and validation to your program. Currently your program will behave in an undesirable way if the user enters invalid data.
The line:
dec = rew.nextInt();
Is reading an int value from the input stream and is not processing the newline character, then when you come back to point where you get the name at which point a new line is still in the Reader's buffer and gets consumed by the stringGetter returning an empty value for name.
Change the line to do something like:
do {
//....
s = stringGetter("Another (y/n)? ");
} while ("y".equals(s));
Well you haven't told us what "rew" is, nor what rew.nextInt() does. Is it possible that rew.nextInt() is waiting for the user to hit return, but only actually consuming one character of the input - so that the next call to rew.nextLine() (for the name) just immediately takes the rest of that line? I suspect that's what's happening because you're using System.in - usually reading from System.in only gives any input when you hit return.
(It's possible that this is also only a problem on Windows - I wonder whether it consumes the "\r" from System.in as the delimiter, leaving "\n" still in the buffer. Not sure.)
To test this, try typing in "1 Jon" when you're being asked whether or not to continue - I think it will then use "Jon" as the next name.
Essentially, I think using Scanner.nextInt() is going to have issues when the next call is to Scanner.nextString(). You might be better off using a BufferedReader and calling readLine() repeatedly, then parsing the data yourself.

Categories

Resources