Java - Scanner: does hasNext() changes accordingly after setting useDelimiter()? - java

Code:
Scanner input;
File file = new File("Latex3.bib");
input = new Scanner(file);
input.useDelimiter("#ARTICLE");
while(input.hasNext()) {
System.out.println("It should not print this");
s = input.next();
System.out.println("Token"+c+": "+s);
c++;
author = s.substring
(s.indexOf("author={")+8,
s.indexOf("}", s.indexOf("author={")+8));
System.out.println("Authors for this ARTICLE: "+author);
System.out.println();
}
(in the code, c is an int that I declared earlier in the original code for just counting and increasing by each loop).
I was getting weird exception from the code that I think it should not throw. After testing each input files, it turns out my while loop runs even when there's no "#ARTICLE" in the Latex3.bib file.
As far as I know, if the file does not have "#ARTICLE", that means that input does not get any token. So from the beginning, its hasNext() should return false. But it just wasn't.
The part what I think funny and strange is: if Latex3.bib is completely empty(not even one space bar or enter), the while loop or whatever reads it as an empty file, therefore no token is given to input.
However, if Latex3.bib has like 1~3 linebreak(enters), then that while loop runs. I have no idea why this is happening. I am suspecting that Scanner.useDelimiter(pattern) does not affect or at least cooperate perfectly with other Scanner methods like hasNext(), although I believe this won't be the real case because it's a very crucial functionality.
edit:
Just to be clear what exception I got, the StringIndexOutOfBoundsException was thrown at the point of assigning author(String). Well it's obvious because the file was empty... and there was nothing to substring or find index..

Related

Java System.in hasNext method works only first time it is called

This problem has me stumped. I've written a method which is called from inside a loop. The first time it works perfectly, after that it just hangs.
This is the method:
public static String promptUser(){
String path = "";
Scanner reader = new Scanner(System.in);
while (!path.contains(ROOT_FOLDER)){
System.out.println(String.format("Please paste in the directory path from WinSCP, including %s: ", ROOT_FOLDER));
while (true) {
if (reader.hasNext()){
path = reader.nextLine();
break;
}
}
}
reader.close();
return path;
}
And this is the loop
while (true) {
try {
listFiles(promptUser());
break;
}
catch (Exception e) {
e.printStackTrace();
System.err.println(e.getMessage());
}
}
The first time I run it, it will prompt the user as many times as it takes to get the info we need (a directory path). It then sends a request for that to an FTP server and if that path does not exist I want it to continue prompting the user. But my debugger is telling me on the second go round it just hangs on:
if (reader.hasNext()){
No amount of hitting the enter key gets it to continue. On the first invocation of promptUser I could enter something without the root folder and it would just keep asking until it got the root folder. So why doesn't it do that on the second invocation?
What is going on?
The first time you call promptUser it does the following:
Create a Scanner that wraps System.in.
Call hashNext which blocks until there is data to be read.
Read a single line.
Close the Scanner.
Return the line.
The problem is step 4. When you close the Scanner, you also close System.in.
Next time you call promptUser
Create another Scanner that wraps System.in. System.in is closed at this point.
Call hashNext() which immediately returns false ... because the stream wrapped by the Scanner is closed.
Repeat 2. ad nauseam. You have an infinite loop.
Solution: don't close System.in or a Scanner that wraps it. And don't just create a second Scanner that wraps System.in. Instead, reuse the original Scanner.
But is it necessary to close the scanner at some point?
You should never need to close a Scanner that wraps (the original) System.in stream. The reasons that we close streams are:
to cause buffered data to be written (for an output stream), and
to avoid file descriptor leaks.
The problem with leaking file descriptors is that a process (i.e. your JVM) can only have a certain number of files open at a time. If you leak file descriptors, you may find that attempts to open files start to fail with unexpected IOExceptions.
In the case of System.in there is no data to be written. Since you can't open System.in again (because you don't know what it is connected to) at most one file descriptor can be "leaked", so this is not a problem.
Eclipse warns that I should.
The Eclipse heuristics about closing scanners, etcetera are rather simplistic. In this case, the warning is probably a false alarm, though I would need to see the code to be sure.
You should not use break inside the loop when you fetch the next element. This causes your while(true) loop to exit. This means that you get the first item and finish.
You should change it to something like this:
while(reader.hasNext()) {
path = reader.nextLine();
// do something with the path here...
}
Read the documentation of hasNext()
Returns true if this scanner has another token in its input. This method may block while waiting for input to scan. The scanner does not advance past any input.
Returns:
true if and only if this scanner has another token
So, hasNext() is waiting for you to enter some value. It'll wait till it finds a single string entered by user.

Java "While" Loop -- Counting Matches Algo - Assigning value must occur inside the while loop

I apologize in advance; I couldn't find the answer to this simple question in Search.
I'm a newbie to coding. Currently on Udacity working my way through the Intro to Java Programming course.
There's something that I'm not understanding as it relates certain Algorithms.
Take the "counting matches" algo for example.
The assignment of double input = in.nextDouble(); needs to occur inside the while-loop.
If I place it just above the while-loop, it breaks the program. Why?
It seems to me that Java shouldn't care when the value is stored in the variable.
import java.util.Scanner;
public class CountingMatches
{
public static void main(String[] args)
{
Scanner in = new Scanner(System.in);
int counter = 0;
System.out.print("Enter a value, Q to quit: ");
// double input = in.nextDouble(); // remember to place the assignment of this variable inside the while loop.
// I tend to want to place this outside the while loop because I still don't
// understand why it necessarily must occur inside the while loop.
while (in.hasNextDouble())
{
double input = in.nextDouble(); // this assignment is properly located here as opposed to just above the while-loop
if (input < 0)
{
counter++;
}
System.out.print("Enter a value, Q to quit: ");
}
System.out.println("The water line fell on " + counter + " years.");
}
}
Because in.nextDouble() can only be used if Scanner has already confirmed the next token can be parsed as a double. In addition to waiting for user input, this is what hasNextDouble() guarantees for you. If you take it out of the loop, not only are you skipping that hasNextDouble() guarantee (and not giving the user a chance to input anything), you are also only running nextDouble() one time, so you wouldn't have the newest value anyway.
Returns true if the next token in this scanner's input can be interpreted as a double value using the nextDouble() method. The scanner does not advance past any input.
-- https://docs.oracle.com/javase/8/docs/api/java/util/Scanner.html#hasNextDouble--
since you can´t do any further input when you move it outside the loop the condition for the loop in.hasNextDouble() will allways be true. Afterwards you will be stuck in an infinite loop, which makes the programm like like it´s brocken, but actually it´s just repetitively looping and printing until you stop the java process by yourself.
You are right that java shouldn't (and doesn't) care when the value is being stored in a variable, but there is more to it.
in.hasNextDouble() doesn't return until the line inside the wrapped input stream has ended.
It does not alter the stream in any way, but it guarantees there is a character sequence waiting in the stream and if true can be parsed as a double. The buffer is not altered until nextDouble() is called.
This is what breaks your code. When you remove the line from the buffer without it being parseable to a double an exception is thrown, because no characters are waiting in System.in

Continue reading console input after Ctrl+Z in Java

For a university assignment, from the console I need to be able to read in multiple lines until the user enters Ctrl+Z. That I have no issue with, my problem lies with me being unable to read anything in from System.in after that because it always throws a NoSuchElementException.
The following is the code that I am using for reading in the multiple lines, it was provided by the instructor and so I don't want to change it.
System.out.println("To terminate input, type the correct end-of-file indicator ");
System.out.println("when you are prompted to enter input.");
System.out.println("On UNIX/Linux/Mac OS X type <ctrl> d");
System.out.println("On Windows type <ctrl> z");
Scanner input = new Scanner(System.in);
while (input.hasNext()) {
//Processes input
addFileIntoDirectory(input.nextLine());
}
I understand that this is caused by the Ctrl+Z which equates to an EOF marker, but I don't know how to move past it. No matter how many reads after it I do, regardless of if I have typed more to the console, I just instantly get back another NoSuchElementException.
I have tried having a separate scanner for the menu, closing the scanner above and opening a new one for the menu but neither works.
Is there a way to flush/purge System.in or to reset it?
Please let me know if you would like more details. I have kept the rest of the program vague as it is homework.
EDIT 1: Assignment says "The system provides a textual selection menu as follows, and
runs in loop." Which means the program is not to terminate on Ctrl+Z.
add files from user inputs
display the whole directory
display the size of directory
exit
Please give a selection [0-4]:
The short answer is:
if (!input.hasNext())
input = new Scanner(System.in);
The long answer is:
Below is code, with comments made for removing later, to demonstrate the problem as I understand it and solution.
Note this demo is intended to only work with integer and ^Z inputs.
Copy out the code and save into file HN.java to compile.
Run the program and it will prompt One. Enter integers to your heart's content and exit the loop by entering ^Z.
Two will be displayed followed by the NoSuchElementFound exception in the question. This is because the ^Z remains in the Scanner object input and thereby fails on the nextInt() method.
The first inclination might be to use hasNext() to account for this. So go ahead and uncomment /*Comment1 and recompile and run again.
Now you avoid the exception, but the program blazes through to the end, skipping over the nextInt() originally intended.
So now, uncomment /*Comment2, recompile, and run again. Now the program will wait at the Two prompt as intended. If you enter an integer here, you will proceed to the Three prompt for another entry.
However, if you enter ^Z at Two, again, the program skips the next input. To correct this, uncomment /*Comment3, recompile, and run, and you will see the program works for all combos of integers and ^Z at the various inputs.
Now, you might be wondering why I didn't just reuse the !input.hasNext() solution in /*Comment3. Here's a demo why:
Put back the /*Comment3 and uncomment the /*Comment4, compile and run again. The program works fine and dandy with a ^Z input at the Two prompt, but if you enter an integer there, you'll see the system waiting for input, but there is no prompt Three!
This is because the integer you entered was used in the preceding nextInt() so when the program gets to the hasNext(), it stops and waits for input.
The lesson here is you use the !input.hasNext() when you KNOW you have a ^Z in queue such as when it was used to escape the while loop in this program and the original poster's question. Otherwise the else structure is better suited.
hasNext() is confusing to work with. You have to keep in mind that if nothing is in queue the program will stop and wait for input at that point. This may mess up your prompting if you're not careful.
import java.util.Scanner;
public class HN
{
public static void main(String args[])
{
Scanner input = new Scanner(System.in);
int temp = 0;
System.out.println("One");
while (input.hasNext())
{
temp = input.nextInt();
}
System.out.println("Two");
/*Comment2
if(!input.hasNext()) input = new Scanner(System.in);
Comment2*/
/*Comment1
if (input.hasNext())
Comment1*/
{
temp = input.nextInt();
System.out.printf("%d\n", temp);
}
/*Comment3
else input = new Scanner(System.in);
Comment3*/
/*Comment4
if(!input.hasNext()) input = new Scanner(System.in);
Comment4*/
System.out.println("Three");
if (input.hasNext())
{
temp = input.nextInt();
System.out.printf("%d\n", temp);
}
System.out.println("Four");
}
}

Curious why this recursive code won't work, and exhibits really anamolous behavior in another method

New programmer here, having some problems with some code about what I would think is recursion.
public static int sum (int a) {
int input = goodInput(); //get input from below method without having to put its code in this one
if (input==-1)//so user has the ability to exit at any time
return a; //when user has finally entered -1, the final sum is sent out
else; //for scenarios before last input
int b = a + input; //adding the newest input to the sum
int c = sum(b); //throw the total into the method again until -1 is read
return c; //once -1 is read, a in that iteration is sent up through every iteration of the method until the original method gets its return
}
public static int goodInput () { //code to get input of correct type
Scanner input = new Scanner (System.in);
while (!input.hasNextInt()) { //if I put in integer input, the loop should not be entered, but this isn't happening
System.out.println("Integers only please");
input.next();
}
int finalInput = input.nextInt(); //Finally set good input
input.close(); //close scanner
return finalInput;
}
First method here is clearly just a way to get a sum. I know there are multitudes of other ways to just sum some numbers together, I've done a few myself, but when my class had its lesson on methods and wrote it up having something like the code I listed was the first thing I could think of as a solution, rather than what the teacher ended up recommending. Thought it would be a good learning exercise, in any case.
This code doesn't show any errors in eclipse, so I am stumped as to why it refuses to work. Indeed, it produces results I am really curious of; it naturally asks input at the beginning of the program, but when I enter 0, 1, or any other int, despite the scanner actually having an integer, "Integers only please" is printed, followed by Java announcing exceptions at the end of the while loop, at goodInput's calling in sum, at the return of c, and at the execution of sum in the main method, as well as at java.util.NoSuchElementException, java.util.Scanner.throwFor, and at java.util.Scanner.next.
I have very little idea what is happening here; my best guess would be memory issues, but bugs start occuring at the very first occasion! And the code in goodInput works perfectly well when just used as the main method; not sure why it being called by sum would cause problems.
Again, I don't just want some sum method. I just want to know why the code is behaving in this manner, and how an implementation of sum with my approach would actually work.
Not recursion is the problem here, but your Scanner. I have to admit that I am not too familiar with the Scanner class, but it seems that if you call input.close() and then reenter goodInput later, your System.in is closed. At least, stepping through with the debugger, I found that the line "Integers only please", is printed in the second invocation of goodInput. Deleting the line input.close(); did the trick for me, and your method worked as intended.
I'd suggest you initialize your scanner in the main method, pass it as an argument, and close it in the main method afterwards.
Edit:
The close method of the Scanner states the following:
If this
scanner has not yet been closed then if its underlying
java.lang.Readable readable also implements the java.io.Closeable
interface then the readable's close method will be invoked.
So, the underlying reader, i.e., System.in, was closed when you called close on the Scanner.

How to write a reverse line program with recursion?

I'm learning recursion and am having problems writing a 'simple' program. Help would be appreciated. Thanks!The code compiles with no syntax erros but i still cant use it to serve its purpose.
my updated code:
import java.io.*;
import java.util.*;
class recursion1
{
static Scanner inFile = null;
public static void main(String[] args) throws IOException
{
try
{
inFile = new Scanner(new File(args[0]));
}
catch (IOException e)
{
System.out.println("File may not exist");
}
reverse(inFile);
inFile.close();
}
public static void reverse(File inFile) throws IOException
{
String line = inFile.nextLine();
if (inFile.hasNextLine())
{
reverse(inFile);
}
System.out.println(line);
}
}
I'm confused as to the purpose of the counter. You decrement it, but you never evaluate it for any sort of logical comparison. I don't think it is unneccessary, you just need to utilize it in a comparison that is used to break the recursive loop. Recursion requires a part that makes a call to the recursive function, and another part that breaks the cycle and begins the process of backing out of the recursive calls.
Here is how to write a reversing program in general. I'm not giving you Java, I'm giving you "pseudocode".
function print_reverse(file)
local_variable line
line = read_from(file)
if (we are not at end of file)
print_reverse(file)
print line
Because line is a local variable, you get a new instance of it on each call to print_reverse(). When you read in the whole file, and you want to print the lines in reverse, the lines need to be stored somewhere. In this recursive function, the lines are stored one at a time, one in each call to print_reverse().
I like to think of recursive functions as "winding" further and further until they hit a limit, then "unwinding" as they come back out. The limit is called the "basis case". With any recursive function you need to have a clear idea of what your basis case is. For print_reverse(), the basis case is hitting the end of file on the input file.
After print_reverse() hits its basis case, it stops calling itself recursively; it prints a line and then unwinds. As each recursive call ends, it returns to the previous recursive call, which then in turn prints its line and unwinds again. This continues until the first call prints its line and terminates, at which point the recursion is finished and all lines have been printed.
So, to summarize: when "winding" we read a line and save it, the basis case is end of input, and when "unwinding" we print a saved line. Since unwinding occurs in the exact opposite order of winding, the lines print in reversed order.
If the input file is very large, this recursive solution may use up all the available stack space, in which case the program will crash. If you wanted to write a file-reversing program that could handle input files of any size, recursion is not going to work. However, look at how clean and simple this program is. Some problems are easier to code and understand if you use a recursive solution.
Reversing a file is pretty easy to do iteratively; just use a loop to read each line from the file and keep appending lines to some sort of list, then loop over the list in reverse printing lines. But other programs are elegantly simple when you write them recursively, and much harder if you don't. For example, the "Towers of Hanoi" puzzle has a very clean recursive solution.
http://www.mathcs.emory.edu/~cheung/Courses/170/Syllabus/13/hanoi.html

Categories

Resources