why my program never reach the solve method? - java

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

Related

Scanner.nextLine() ignores whitespace? (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();
}

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.hasNext() not working properly when running in Eclipse

I wrote a simple program to loop and find max of a set of numbers input by the user as:
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int currMax, currEl;
currMax = sc.nextInt();
while (sc.hasNext()) {
currEl = sc.nextInt();
currMax = (currEl > currMax ? currEl : currMax);
}
sc.close();
System.out.println(currMax);
} // end function main
}
I am using Eclipse on Windows.
When I run it the first time it runs fine, and considers Ctrl-Z as EOF and exits the loop. But second time onwards, it does not seem to read the EOF. I am unable to explain this, or fix this behavior.. what do you think is going on, and how do I fix it??
Follow-up: The problem happens with Eclipse, and not when I use cmd line. I suspect this is what is happening -- if I use cmd line, I can do Ctrl-Z and then hit Enter, but if I use Eclipse, I believe as soon as I hit Ctrl-Z, s.hasNext() evaluates to false and the above program terminates.

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

why's this program giving a runtime error on jcreator but not on netbeans?

This is my solution for sphere's online judge palin problem. It runs fine on Netbeans, but the judge is rejecting my answer saying it gives a RuntimeError. I tried it on JCreator and it says:
Exception in thread "main" java.lang.NumberFormatException: For input string: ""
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
at java.lang.Integer.parseInt(Integer.java:468)
at java.lang.Integer.parseInt(Integer.java:497)
at Main.main(Main.java:73)
I'm not passing an empty string for it to parse, why is this?
The code:
import java.io.*;
import java.util.*;
class Main {
public static int firstPalinLargerThanNum(int num){
int foundPalin =0;
int evalThisNum = ++num;
while (true){
if (isPalin(evalThisNum))
break;
evalThisNum++;
}
foundPalin = evalThisNum;
return foundPalin;
}
public static boolean isPalin(int evalThisNum){
boolean isItPalin = false;
int dig=0;
int rev=0;
int n = evalThisNum;
while (evalThisNum > 0)
{
dig = evalThisNum % 10;
rev = rev * 10 + dig;
evalThisNum = evalThisNum / 10;
}
if (n == rev) {
isItPalin=true;
}
return isItPalin;
}
public static void main(String args[]) throws java.lang.Exception{
BufferedReader r1 = new BufferedReader(new InputStreamReader(System.in));
/*BufferedReader r1 = new BufferedReader (new FileReader(new File ("C:\\Documents and Settings\\Administrator\\My Documents\\NetBeansProjects\\Sphere\\src\\sphere\\sphere\\PALIN_INPUT.txt")));*/
String read = r1.readLine();
int numberOfTestCases = Integer.parseInt(read);
for (int i=0; i<numberOfTestCases;i++){
read = r1.readLine();
if (read!=null){
int num = Integer.parseInt(read);
System.out.println(firstPalinLargerThanNum(num));
}
}
}
}
Input:
2
808
2133
line 73 is: int num = Integer.parseInt(read);
You will get that error if you hit <Enter> when the program is expecting a number.
Suppose your input is
2
3
<Enter>
You will receive the error you have indicated after processing the number 3, as you have told your routine to iterate twice.
As an aside, on top of error handling around the number parsing, you might also want to introduce a trim() to the readLine() method calls:
String read = r1.readLine().trim();
This will allow you to handle gracefully the input in the event that the user to put in whitespace around the numbers.
Just a wild guess: Could there be a problem with different end-of-line separators.
E.g. your program actually gets 2<CR><LF>808<CR><LF>2133<CR><LF>, thinks that the line ends at the <CR> and processes the line.
Now when it tries to process the next line it finds <LF> which makes it think it read an empty String.
You cannot assume that the user knows how to use your program and will give you correct input. The judge probably hit enter, without typing any number. How is he/she supposed to know the input that your program requires? A program should fail gracefully, not blow up in the user's face with cryptic errors.
You should be doing something like the following, so that the user knows what to do:
private static function readInt(BufferedReader reader) throws IOException
{
boolean done = false;
int result = -1;
while ( ! done ){
System.out.print("Please enter an integer: ");
String str = reader.readLine();
try{
result = Integer.parseInt(str);
done = true;
}catch(NumberFormatException cantconvert){
System.out.println("That isn't an integer. Try again.");
}
}
return result;
}
Additionally, you shouldn't use an exception specifier with the main function (that is, don't use "throws" in the signature of "main"). You should handle those IOExceptions and print a pretty and intelligible message to the user, even if there is nothing you can do about the exception to fix it or make it go away.
I just ran your example code under Eclipse 3.4 without error. I was only able to induce a similar error when I did not provide the specified number of test cases, i.e.:
6
56
87
[Enter]
So I am inclined to agree with akf that there must be an extra Enter happening somewhere, because this error will only be generated when there are insufficient lines of input.

Categories

Resources