Recently a friend of mine showed me her code seeking my advice on why it wouldn't work. Her original code was this:
public static void printStem(String word) ...
public static void main(String[] args)
{
Scanner keyboard = new Scanner(System.in);
System.out.println("Please enter the words: ");
String word = keyboard.next();
printStem(word);
while (keyboard.hasNext())
{
printStem(word);
word = keybord.next();
}
}
This will yield really weird results. It will ask the user twice, then executes printStem twice (which might be expected), and after that goes ahead and always prints only the first entered corpus (word).
Eventually I figured out that it would work as expected when removing the keyboard.next() from outside the loop like so
public static void printStem(String word) ...
public static void main(String[] args)
{
Scanner keyboard = new Scanner(System.in);
System.out.println("Please enter the words: ");
while (keyboard.hasNext())
{
String word = keybord.next();
printStem(word);
}
}
When asked why this would be I had no plausible explanation, as this should behave identical. My best guess is that something must be smelly with hasNext() but I couldn't figure out why exactly. So. What is going on here? Any explanation is appreciated :)
Some explanation about 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.
In your first piece of code
you scan for a word: String word = keyboard.next();
You print it: printStem(word);
You enter into a while loop which waits until you give some input: keyboard.hasNext()
In step 3 you take the input but never store it in String word and you print it. Naturally previous value of word will be printed.
Then you do a next read by next().
Explanation for next():
Finds and returns the next complete token from this scanner. A complete token is preceded and followed by input that matches the delimiter pattern. This method may block while waiting for input to scan, even if a previous invocation of hasNext() returned true.
Hence you get a weird behavior.
This will yield really weird results
Yeah, because the logic is wrong.
You get the input
String word = keyboard.next();
print it
printStem(word);
then print it again, and ask for another word:
while (keyboard.hasNext())
{
printStem(word);
word = keybord.next();
}
So every time you loop you print the word they entered last time, rather than the word they entered this time. You just need to swap the two lines in the while-loop, which then makes the keyboard.next() and printStem(word) outside of the loop body redundant.
as this should behave identical
No it shouldn't. You reversed the order of operations in the while-loop body.
Related
So I am trying to make a code that will prompt the user to either use a basic calculator, or a word counter that displays how many words are in a given sentence entered by the user, this is done using methods. I have figured out how to properly set up the calculator, but the word counter is giving me some issues:
public static int wordCounter(String str){
String words[]=str.split(" ");
int count=words.length;
return count;
}
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("What do you want to do( calculator(0)/word counter(1) )? ");
//This runs and I select '1' for word counter
int choice = input.nextInt(); //Input the choice here
if (choice == 0) {
// It runs this selection statment, and since zero is not selected,
//it runs the word Counter branch
calculator();
}else{
System.out.println("Please enter a sentence:"); // Tells me to enter a sentence
String sentence=input.nextLine();
//^ This input is completely skipped and goes
//right to the 'System.out.print(); Statement.
System.out.print("There are "+ wordCounter(sentence) + " words in the sentence.");
//^ This prints a 1 immediately after the branch is selected with '1'
}
}
I'm not sure where it is going wrong since this only happens while it is in the if/else statement. Doing some testing also showed me that it seems that the first scanner "int choice=input.nextInt()" Is somehow interfering with the second scanner for the string. Any ideas keeping a similar formatting would be greatly appreciated.
Please forgive my formatting, it may not look great.
nextLine() will only return the remainder of the current line being scanned. Since you would have pressed enter after selecting the number, all it will capture is an empty string.
To fix it, just add a nextLine() directly after you get the integer.
public String nextLine()
Advances this scanner past the current line and returns the input that was skipped. This method returns the rest of the current line, excluding any line separator at the end. The position is set to the beginning of the next line.
Since this method continues to search through the input looking for a line separator, it may buffer all of the input searching for the line to skip if no line separators are present.
https://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html#nextLine()
The problem is when you enter the number int choice = input.nextInt() it's only scanning the integer, not the newline. So when you call input.nextLine() it instantly returns an empty string. One way to fix this would be to replace that line with
int choice = Integer.parseInt(input.nextLine());
I ran into an issue. Below is my code, which asks user for input and prints out what the user inputs one word at a time.
The problem is that the program never ends, and from my limited understanding, it seem to get stuck inside the while loop. Could anyone help me a little?
import java.util.Scanner;
public class Test{
public static void main(String args[]){
System.out.print("Enter your sentence: ");
Scanner sc = new Scanner (System.in);
while (sc.hasNext() == true ) {
String s1 = sc.next();
System.out.println(s1);
}
System.out.println("The loop has been ended"); // This somehow never get printed.
}
}
You keep on getting new a new string and continue the loop if it's not empty. Simply insert a control in the loop for an exit string.
while(!s1.equals("exit") && sc.hasNext()) {
// operate
}
If you want to declare the string inside the loop and not to do the operations in the loop body if the string is "exit":
while(sc.hasNext()) {
String s1 = sc.next();
if(s1.equals("exit")) {
break;
}
//operate
}
The Scanner will continue to read until it finds an "end of file" condition.
As you're reading from stdin, that'll either be when you send an EOF character (usually ^d on Unix), or at the end of the file if you use < style redirection.
When you use scanner, as mentioned by Alnitak, you only get 'false' for hasNext() when you have a EOF character, basically... You cannot easily send and EOF character using the keyboard, therefore in situations like this, it's common to have a special character or word which you can send to stop execution, for example:
String s1 = sc.next();
if (s1.equals("exit")) {
break;
}
Break will get you out of the loop.
Your condition is right (though you should drop the == true). What is happening is that the scanner will keep going until it reaches the end of the input. Try Ctrl+D, or pipe the input from a file (java myclass < input.txt).
it doesn't work because you have not programmed a fail-safe into the code. java sees that the scanner can still collect input while there is input to be collected and if possible, while that is true, it keeps doing so. having a scanner test to see if a certain word, like EXIT for example, is fine, but you could also have it loop a certain number of times, like ten or so. but the most efficient approach is to ask the user of your program how many strings they wish to enter, and while the number of strings they enter is less than the number they put in, the program shall execute. an added option could be if they type EXIT, when they see they need less spaces than they put in and don't want to fill the next cells up with nothing but whitespace. and you could have the program ask if they want to enter more input, in case they realize they need to enter more data into the computer.
the program would be quite simplistic to make, as well because there are a plethera of ways you could do it. feel free to ask me for these ways, i'm running out of room though. XD
If you don't want to use an EOF character for this, you can use StringTokenizer :
import java.util.*;
public class Test{
public static void main(){
Scanner sc = new Scanner (System.in);
System.out.print("Enter your sentence: ");
String s=sc.nextLine();
StringTokenizer st=new StringTokenizer(s," ");//" " is the delimiter here.
while (st.hasMoreTokens() ) {
String s1 = st.nextToken();
System.out.println(s1);
}
System.out.println("The loop has been ended");
}
}
I had the same problem and I solved it by reading the full line from the console with one scanner object, and then parsing the resulting string using a second scanner object.
Scanner console = new Scanner(System.in);
System.out.println("Enter input here:");
String inputLine = console.nextLine();
Scanner input = new Scanner(inputLine);
List<String> arg = new ArrayList<>();
while (input.hasNext()) {
arg.add(input.next().toLowerCase());
}
You can simply use one of the system dependent end-of-file indicators ( d for Unix/Linux/Ubuntu, z for windows) to make the while statement false. This should get you out of the loop nicely. :)
Modify the while loop as below. Declare s1 as String s1; one time outside the loop. To end the loop, simply use ctrl+z.
while (sc.hasNext())
{
s1 = sc.next();
System.out.println(s1);
System.out.print("Enter your sentence: ");
}
I'm practicing HashSet from Java book by Cay S. Horstmann and Gary Cornell and I think there's a mistake in example code on page 687. We have a Scanner importing words to HashSet and it looks like this (I removed some unneeded code to make a problem more visible):
Set<String> words = new HashSet<String>();
Scanner in = new Scanner(System.in);
while (in.hasNext()) {
String word = in.next();
words.add(word);
}
The problem is there's no way stop this loop. Or maybe there's something I'm missing?
To stop the loop I've added another static helper method:
public static boolean isStop(Scanner in) {
if (in.next().equals("stop")) {
return true;
}
return false;
}
And now the main code looks like this:
Set<String> words = new HashSet<String>();
Scanner in = new Scanner(System.in);
while (!isStop(in)) {
String word = in.next();
words.add(word);
}
Is there any other way to stop scanner loop? I can't believe that book's author has made a mistake ?
The loop stops as soon as this condition is false:
in.hasNext()
I.e., there are no more words.
Inside the loop is a command to read the next word:
in.next()
So words will continue to be read until the Scanner has no more words to read. This loop will terminate at the end of whatever the Scanner is reading.
Since you are scanning System.in, the loop won't stop as it will keep on adding "words" to your Set but there's no visible error in the program.
Your idea of selecting a keyword to stop the loop once a user input matches that keyword sounds good.
You don't really need a static method using your Scanner as argument for that.
Just add the following after String word = in.next();:
if (word.equalsIgnoreCase("stop")) {
System.out.printf("Quitting with set: %s%n", words);
in.close();
return; // assuming method is void
}
The scanner will continue while there are still words in the input, as others explained. Note that when we're talking about System.in, it usually waits until the user enters more text, and so will not terminate until the user closes the stream (supplies the appropriate end-of-file for the operating system). In Unix/Linux, for the loop to terminate, the user will need to use control-D.
The loop won't stop as it will keep on adding "words" to your Set but there's no visible error in the program.
Your idea of selecting a keyword to stop the loop once a user input matches that keyword sounds good.
You don't really need a static method using your Scanner as argument for that.
Just add change your code as follows:
Set<String> words = new HashSet<String>();
Scanner in = new Scanner(System.in);
System.out.print("Type a word...");
while (in.hasNext()) {
String word = in.next();
if (word.equalsIgnoreCase("stop")) {
System.out.printf("Quitting with set: %s%n", words);
return; // assuming method is void
}
else {
words.add(word);
System.out.print("Type a word (or \"stop\" to quit)...");
}
}
IF there is code to be executed after the loop then yes, I'd say the authors made a mistake. Write to them about it! If this is an example of adding items to a Set then the example is fine. It all depends on what the authors' intent of the example was.
hasNext() is a blocking method meaning it will always wait for more input. There are related questions about this. Your way of "fixing this" is what the general consensus has done.
I have a program that needs to read lines of input. It needs to be many lines at once. For example:
As I enter my time machine or
maybe not,
I wonder whether free will exists?
I wonder whether free will exists
maybe not
as I enter my time machine or.
That all gets entered at one time by the user. I was trying to use .hasNextLine() method from Scanner class, but it is not returning false.... it waits for input again. Ive been looking around for a solution and it appears that .hasNextLine() waits for input, but i do not know what alternative to use. Any suggestions? The actual code looks like:
while(input.hasNextLine());
{
line += input.nextLine();
}
Thanks for your help
Perhaps you should use some sort of "stop" sequence meaning when the user enters a particular character sequence, it will break out the loop. It might look something like:
public static void main(String args[]){
final String stopSequence = "/stop";
final Scanner reader = new Scanner(System.in);
String input = reader.nextLine();
while(!input.equalsIgnoreCase(stopSequence)){
//process input
input = reader.nextLine();
}
}
I ran into an issue. Below is my code, which asks user for input and prints out what the user inputs one word at a time.
The problem is that the program never ends, and from my limited understanding, it seem to get stuck inside the while loop. Could anyone help me a little?
import java.util.Scanner;
public class Test{
public static void main(String args[]){
System.out.print("Enter your sentence: ");
Scanner sc = new Scanner (System.in);
while (sc.hasNext() == true ) {
String s1 = sc.next();
System.out.println(s1);
}
System.out.println("The loop has been ended"); // This somehow never get printed.
}
}
You keep on getting new a new string and continue the loop if it's not empty. Simply insert a control in the loop for an exit string.
while(!s1.equals("exit") && sc.hasNext()) {
// operate
}
If you want to declare the string inside the loop and not to do the operations in the loop body if the string is "exit":
while(sc.hasNext()) {
String s1 = sc.next();
if(s1.equals("exit")) {
break;
}
//operate
}
The Scanner will continue to read until it finds an "end of file" condition.
As you're reading from stdin, that'll either be when you send an EOF character (usually ^d on Unix), or at the end of the file if you use < style redirection.
When you use scanner, as mentioned by Alnitak, you only get 'false' for hasNext() when you have a EOF character, basically... You cannot easily send and EOF character using the keyboard, therefore in situations like this, it's common to have a special character or word which you can send to stop execution, for example:
String s1 = sc.next();
if (s1.equals("exit")) {
break;
}
Break will get you out of the loop.
Your condition is right (though you should drop the == true). What is happening is that the scanner will keep going until it reaches the end of the input. Try Ctrl+D, or pipe the input from a file (java myclass < input.txt).
it doesn't work because you have not programmed a fail-safe into the code. java sees that the scanner can still collect input while there is input to be collected and if possible, while that is true, it keeps doing so. having a scanner test to see if a certain word, like EXIT for example, is fine, but you could also have it loop a certain number of times, like ten or so. but the most efficient approach is to ask the user of your program how many strings they wish to enter, and while the number of strings they enter is less than the number they put in, the program shall execute. an added option could be if they type EXIT, when they see they need less spaces than they put in and don't want to fill the next cells up with nothing but whitespace. and you could have the program ask if they want to enter more input, in case they realize they need to enter more data into the computer.
the program would be quite simplistic to make, as well because there are a plethera of ways you could do it. feel free to ask me for these ways, i'm running out of room though. XD
If you don't want to use an EOF character for this, you can use StringTokenizer :
import java.util.*;
public class Test{
public static void main(){
Scanner sc = new Scanner (System.in);
System.out.print("Enter your sentence: ");
String s=sc.nextLine();
StringTokenizer st=new StringTokenizer(s," ");//" " is the delimiter here.
while (st.hasMoreTokens() ) {
String s1 = st.nextToken();
System.out.println(s1);
}
System.out.println("The loop has been ended");
}
}
I had the same problem and I solved it by reading the full line from the console with one scanner object, and then parsing the resulting string using a second scanner object.
Scanner console = new Scanner(System.in);
System.out.println("Enter input here:");
String inputLine = console.nextLine();
Scanner input = new Scanner(inputLine);
List<String> arg = new ArrayList<>();
while (input.hasNext()) {
arg.add(input.next().toLowerCase());
}
You can simply use one of the system dependent end-of-file indicators ( d for Unix/Linux/Ubuntu, z for windows) to make the while statement false. This should get you out of the loop nicely. :)
Modify the while loop as below. Declare s1 as String s1; one time outside the loop. To end the loop, simply use ctrl+z.
while (sc.hasNext())
{
s1 = sc.next();
System.out.println(s1);
System.out.print("Enter your sentence: ");
}