Still in while loop hell, Now with refined question!

M

mmoski

I've refined my code to make it nice and basic.

import java.util.Scanner;

public class Parse {

public static void main (String[] args) {

Scanner sc = new Scanner(System.in);

Node head = null;
Node prev = null;
String read = sc.next();
Node a = new Node();

while(sc.hasNext()){ // <-- PROBLEM AREA.

a.data = read;

if(head == null){
head = a;
}else{
prev.next = a;
}
prev = a;
read = sc.next();
}

for(Node pointer = head; pointer != null; pointer = pointer.next)
{
System.out.println(pointer.data);
}

}
}

class Node{
public Node next;
public String data;
}

First off, the list has to be of my own design, so the linkedList
class is useless here. My problem is the while loop. I know that the
scanner usually blocks for whatever reason. My question is, does
anybody have a suggestion for me? If the scanner stalls waiting for
more input, how do I make it un-stall?
 
P

Patricia Shanahan

mmoski said:
First off, the list has to be of my own design, so the linkedList
class is useless here. My problem is the while loop. I know that the
scanner usually blocks for whatever reason. My question is, does
anybody have a suggestion for me? If the scanner stalls waiting for
more input, how do I make it un-stall?

By giving it more data, which does not help with the real objective of
getting your loop to finish.

Two possible solutions:

1. Provide an end-of-file, so that the Scanner will reach a hasNext()
false condition. You could do this by redirecting standard in to come
from a file, or by entering the appropriate file ending character for
the environment in which you are running.

2. Don't use end-of-file at all. Pick some other end-of-data marker, a
special data value, and make the loop continuation depend on the input
not being the end-of-data marker.

Patricia
 
M

mmoski

By giving it more data, which does not help with the real objective of
getting your loop to finish.

Two possible solutions:

1. Provide an end-of-file, so that the Scanner will reach a hasNext()
false condition. You could do this by redirecting standard in to come
from a file, or by entering the appropriate file ending character for
the environment in which you are running.

2. Don't use end-of-file at all. Pick some other end-of-data marker, a
special data value, and make the loop continuation depend on the input
not being the end-of-data marker.

Patricia

Perhaps if I were to use a read line to wrap the whole while and it
could reach it's EOF when it detects a blank line ie: by hitting enter
twice while in the console. This is my next step but I fear that I'll
still stall because I don't get how the program will make it to the
next line because it has to break the nested while loop first.

Basically I want the user to type in input such as:

input one this is something
input B this is something else
hello world

I want it to read in a line and then using another while loop inside
the first I want it to then read each token in the line into a list.
In the end it should put the head node of each list into an array to
make an array of lists, which will then be processed in a certain
way. I had this EXACT problem last year and never got a solution. I
know that sc.next() will never return null, and that it blocks while
waiting for input.

I know what doesn't work.

What does?
 
B

blmblm

I've refined my code to make it nice and basic.

import java.util.Scanner;

public class Parse {

public static void main (String[] args) {

Scanner sc = new Scanner(System.in);

Node head = null;
Node prev = null;
String read = sc.next();
Node a = new Node();

while(sc.hasNext()){ // <-- PROBLEM AREA.

Yes, it is a problem, and there's one more reason (for its being
a problem) that I'm not sure anyone has pointed out yet:

It doesn't make sense to check what hasNext() returns *after*
making the call to next(); normal usage is to call next() only
if hasNext() returns true. If you run this program and provide
it a single string as input, followed by end-of-file, the loop
will execute zero times. As I think someone suggested in the
other thread, wouldn't it be simpler and less error-prone to write

while(sc.hasNext()) {
String read = sc.next();
// do stuff with read
}

rather than having two calls to next() at different points in
the program?
 
B

blmblm

[ snip ]
Perhaps if I were to use a read line to wrap the whole while and it
could reach it's EOF when it detects a blank line ie: by hitting enter
twice while in the console. This is my next step but I fear that I'll
still stall because I don't get how the program will make it to the
next line because it has to break the nested while loop first.

Basically I want the user to type in input such as:

input one this is something
input B this is something else
hello world

I want it to read in a line and then using another while loop inside
the first I want it to then read each token in the line into a list.
In the end it should put the head node of each list into an array to
make an array of lists, which will then be processed in a certain
way. I had this EXACT problem last year and never got a solution. I
know that sc.next() will never return null, and that it blocks while
waiting for input.

I know what doesn't work.

What does?

If you want to read input a line at a time, how about using a
BufferedReader? Here's a quickly-hacked-together example of using
one to read input a line at a time, until a blank line is detected.
It compiles and runs for me, but no claims about all details being
best-practice.

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class EchoUntilBlank {

public static void main (String[] args) throws IOException {
// probably should deal with the IOException in the code
// rather than just throwing it, but -- quick hack for now

BufferedReader br =
new BufferedReader( new InputStreamReader(System.in));

String line = null;

while(((line = br.readLine()) != null) && (!line.equals(""))) {
System.out.println(line); // replace with your processing
}
}
}
 
M

mike.mainguy

[ snip ]


Perhaps if I were to use a read line to wrap the whole while and it
could reach it's EOF when it detects a blank line ie: by hitting enter
twice while in the console. This is my next step but I fear that I'll
still stall because I don't get how the program will make it to the
next line because it has to break the nested while loop first.
Basically I want the user to type in input such as:
input one this is something
input B this is something else
hello world
I want it to read in a line and then using another while loop inside
the first I want it to then read each token in the line into a list.
In the end it should put the head node of each list into an array to
make an array of lists, which will then be processed in a certain
way. I had this EXACT problem last year and never got a solution. I
know that sc.next() will never return null, and that it blocks while
waiting for input.
I know what doesn't work.
What does?

If you want to read input a line at a time, how about using a
BufferedReader? Here's a quickly-hacked-together example of using
one to read input a line at a time, until a blank line is detected.
It compiles and runs for me, but no claims about all details being
best-practice.

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class EchoUntilBlank {

public static void main (String[] args) throws IOException {
// probably should deal with the IOException in the code
// rather than just throwing it, but -- quick hack for now

BufferedReader br =
new BufferedReader( new InputStreamReader(System.in));

String line = null;

while(((line = br.readLine()) != null) && (!line.equals(""))) {
System.out.println(line); // replace with your processing
}
}

}

I vote for BufferedReader (or any Reader implementation for that
matter). If the lines are all text and you really want to process
input an entire line at a time, this is really the most java-esque way
of doing it IMHO.
 
L

Lew

Besides all the advice on how to get a line in to your program, you have a
separate problem of how to do the loop, and how to stop it.

It is good to focus on one problem at a time. The fact that you can gives you
the design principle to separate each problem into separate methods or
separate classes.

Many here have spoken of the way to get in a line to parse into your Node
list. That makes it one problem, and it deserves its own method. Let's call
that method retrieveLine().

public class NodeWorker
{
public String retrieveLine()
{
String result;
// put one of the suggested implementations here
result = ...;
return result;
}
}

Actually, once you fill in that ellipsis, you've got a complete, but so far
useless class.

Get that part to compile and then add another method to do something useful,
say, create a Node from a String.

Wait! What's a Node? Well, it's something you add to a NodeList that holds a
String.

class Node
{
private String data;
private Node next;

public String getData()
{
return data;
}
public void setData( String v )
{
this.data = v;
}

public Node getNext()
{
return next;
}
public void setNext( Node v )
{
this.next = v;
}
}

What I'm showing here is to use standard get/set accessor methods for private
variables.

(If the class were generic it would be a Node<T> and you'd substitute T for
String in the class definition.)

Now you need to have an add( Node n ) method in NodeWorker. This is where you
use that one part of your original program where you manipulate head and prev.

You really need to think about whether prev does any good yet. Start with
just having head.

Where does head go? In NodeWorker?

Unlike the other variables, head does not get accessor methods.
Just add( Node n ).

// within NodeWorker
private Node head; // don't presume to initialize it yet

public void add( Node n )
{
if ( n == null )
{
String msg = "Let's avoid null for now, shall we?";
throw new IllegalArgumentException( msg );
}
n.setNext( head );
head = n;
}

Notice that this handles just one eensy-weensy piece of the action. No
worries about what the Node has for data, just a little play with the structure.

At this point you should write the main() for NodeWorker and try to get just
these methods to do something useful, perhaps watching in a debugger to see if
it does what you want.

Or anything at all.

Then add the logic to, say, parse the next token from a line and create a node
for it. Test.

Add a loop to main() to check for a next token, then do something with it
inside the loop using the methods you've developed by that point.

Make sure to follow blmblm's advice:
It doesn't make sense to check what hasNext() returns *after*
making the call to next(); normal usage is to call next() only
if hasNext() returns true.

Build it one step at time, and it'll come.
 
L

Lew

Lew said:
Unlike the other variables, head does not get accessor methods.

Actually, you might want a getter for it eventually. I didn't see a need for
it at first, but perhaps later.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top