Why is System.in not responding properly to synchronization attempts? - java

I can't seem to force my calls to System.out to go in order if one of them takes input from a Scanner on System.in.
I'm sure that there's a simple answer (I can feel the down votes coming already), but it's eluding me.
public class RegexApp{
static Scanner s = new Scanner(System.in);
static String read = "";
public static void main(String[] args) {
while (true) {
System.out.println("Please enter text.");
RegexApp.GetLine mg = new RegexApp().new GetLine();
mg.start();
mg.join();
}
}
public class GetLine extends Thread{
public void run()
{
read=s.nextLine();
System.out.println(read);
}
}
}
Even though I've tried using thread.join() to force the app to complete the System.out.println(read); before the next iteration of the while loop and printout of another System.out.println("Please enter text.");, I can't seem to get these two things to happen in the right order.
I'll often get another System.out.println("Please enter text.");, immediately followed by the result of System.out.println(read); from the last line of input (vs. the reverse order as expected.)
It seems that the System.out call waiting for the input from System.in is just allowed to return whenever, and the app goes on with other System.out calls in the meantime. I'd like to ensure that the app actually waits for the result of one System.out call before looping to the next.
(I have tried synchronized(System.out),(this) and (System.in), with wait() and notify(), all to no avail.)
I get
Please enter text.
(I type HELLO and hit enter)
Please enter text.
HELLO
(I type GOODBYE and hit enter)
Please enter text.
GOODBYE
where I'd have expected
Please enter text.
(I type HELLO and hit enter)
HELLO
Please enter text.
(I type GOODBYE and hit enter)
GOODBYE
Please enter text.
Basically, the order is inverted, and I can't figure out why.
I've seen a related question on the site in which the order of flushing of streams is mentioned, and the fix involving synchronized(System.out){} is given, but that did not solve this problem.

Related

How to skip control when we are using scanner readLine() when user is nothing entered from keyboard?

My code is :
System.out.print("press key Y or N to run the test");
Scanner sc = new Scanner(System.in);
String input = null;
input = sc.nextLine();
There is nothing you can do. nextLine() waits for the user to press "Enter" on the keyboard; it will block forever until that happens.
If you really want that things happen "automatically", you will need a more complex solution; for example you can wait for user input in a separate thread; and if there is no input after a given amount of time, your other thread can start doing "whatever" "automatically".
Please tell the user to hit return after his input and check for empty lines like this:
if("".equals(input)){ //skip control
}
else{ //do something on input
}

Java scanner - can't read user input

I want to read user input like: 11 12 13 14 15 16
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
System.out.println(sc.next());
}
System.out.println("Test");
but it newer goes out of while loop and prints "Test".
How could i read that input?
The method hasNext() works like this:
If it sees the end of the file, it returns false;
If it sees another valid, non-whitespace input, it returns true;
If neither of the above is true, it waits for the next input the user is going to enter, and doesn't return until he does.
Usually, if you use Scanner for files, such a loop will work correctly, because a file has a definite end, and it usually doesn't get stuck waiting for more input.
But when you are working with console input (System.in, not redirected), then usually the user does not send the end-of-file signal. He just presses Return, and so, hasNext() sits and waits to see if the user will enter more input on the next line and so on.
There are two general ways to deal with this:
The user has to actually terminate the input. After you finish entering all your numbers and press Return, you also need to send the end-of-file sequence, which is usually ctrlD or ctrlZ.
If you do that, you will not be able to enter any more input to that program.
The program tells the user to enter some particular value that will tell it that the input is over. For example, the string "DONE". When you do that, you have to change the loop to something like:
String nextInput;
while( sc.hasNext() && ! (nextInput = sc.next()).equals( "DONE" ) ){
System.out.println(nextInput);
}
You can break the loop depending whether you want to quit or not E.g.
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
String next = sc.next();
if (next.equals("q")) { //if user press q then break the loop
break;
}
System.out.println(next);
}
System.out.println("Test");
}
Use api like:
while(sc.hasNextInt()){
int aba= sc.nextInt();
if (aba == 0) {//or even non numeric value here would let this loop exit
break;
}
}
So you need to enter 0 or even in other way enter non numeric value inorder to come out of loop. nextLine method will read whole line just once and then you will need to parse it and then convert to integer so it's good to use sc.nextInt which will do the work for you.

I need to make Scanner check to see if input is "quit", and then if it's not, accept an integer

I'm trying to write a program that gets an integer from the user, but also ends the program if the user enters "quit". When I run the program, it works when I enter "quit", but when I start entering an integer, I get a blank line. If I enter the integer the second time, it works. I have tried several suggestions that I have found for similar problems - including try/catch, parsing the input to Integer, and firing a blank Scanner#nextLine or Scanner#nextInt (and going back and forth between all of these options). Here is an example of my latest attempt. Any insight would be appreciated.
int colInput;
System.out.println(", please pick a column in which to place your token (1-8).");
System.out.println("(Type 'quit' to exit the game or 'restart' to start over.)");
System.out.print("Column Choice: ");
Scanner selectCol = new Scanner (System.in);
try {
if (selectCol.next().equals("quit"))
Connect4.close();
}
finally {
colInput = selectCol.nextInt();
}
String input = selectCol.next();
int colInput;
if (input.equals("quit"))
Connect4.close();
else
colInput = Integer.parseInt(input);
//Use colInput here or return colInput or whatever you wish to do with it
In the code you mention you are consuming the "next token" found by your scanner in the line
if (selectCol.next().equals("quit"))
the token is received and compared against "quit". No matter what the value of the token originally was it is lost afterwards. Then later in the finally block you ask your scanner for a new token. He is then waiting for a new value from System.in.
To receive the token from the scanner only if it matches "quit" you should change the line to
if (selectCol.next("quit"))
This way you are making use of a method offered by the Scanner class javadoc for next(String).

While-loop termination

If I comment out the line garbage = scan.nextLine();, the while-loop runs infinitely. Otherwise, it does not. I understand why it will run infinitely if there were only the print command, but I don't completely understand how the inclusion of the garbage variable stops it from running infintely. Can someone explain please?
import java.util.Scanner;
public class TypeSafeReadInteger
{
public static void main(String [] args)
{
Scanner scan = new Scanner(System.in);
String garbage;
System.out.print("Enter age as an integer > ");
while (! scan.hasNextInt())
{
garbage = scan.nextLine();
System.out.print("\nPlease enter an integer > ");
}
int age = scan.nextInt();
System.out.println("Your age is " + age);
}
}
garbage is just a variable, what 'stops' the while loop is the nextLine() It is a method that waits for user input. The while doesn't continue until your user inputs something using a keyboard and saves the input into the garbage variable.
You need to know two things:
hasNextLine() does not advance the Scanner instance.
nextLine() does advance the Scanner instance.
By "advance the Scanner instance", I mean "consume" input. Think of input as a stream, and think of a scanner object as something that is consuming that stream.
Things in a normal stream can only be consumed once. You captured your's in a variable called garbage, but you could just as easily have called scan.nextLine() without storing the result. I strongly advise you to read the Javadoc on Scanner to see which methods advance the Scanner instance and which do not.
To fix your code:
while (!scan.hasNextInt())
{
scan.nextLine(); // the order of the lines inside the loop makes the difference!
System.out.print("\nPlease enter an integer > ");
// when you perform nextLine() here - you reach the beginning of the loop
// without a token in the scanner - so you end up looping forever
}
int age = scan.nextInt();
By the way - as you can see from the example above, garbage is redundant.
If the user inputs an integer, then everything works. If they don't, then you get the infinite loop without the garbage = scan.nextLine(); line due to the way the Scanner class works.
When you do something like scan.hasNextInt();, no characters are actually read from the input. So if a user input something like "cat" in response to your prompt, then the input would be paused just before the first letter of that word. Since you are looping until there is an integer in the input, nothing further is read and you will loop infinitely because "cat" is just sitting in the input buffer.
By adding in the scan.nextLine() you will cause the Scanner to discard everything up to when the user hit <enter> and additional input could be processed.

Java Menu Loop Problems; Program loops too soon?

I am working on an assignment where I have to write a program to encrypt and decrypt Caeser ciphers. The part I am having trouble with though is not encrypting or decrypting, but another one of the requirements, which was that I have to provide a menu so that the user can choose to encrypt, decrypt, or quit. Furthermore, the program should keep prompting the use until the use selects quit. My code so far is:
import java.util.*;
public class CaeserShiftTester
{
public static void main (String[] args)
{
Scanner in = new Scanner(System.in);
String choice = "";
while (!choice.equalsIgnoreCase("C"))
{
System.out.println("\nPlease select an option");
System.out.println("[A] Encrypt Code");
System.out.println("[B] Decrypt Code");
System.out.println("[C] Quit");
choice = in.next();
if(choice.equalsIgnoreCase("A"))
{
System.out.println("Please enter your key:");
final int KEY = in.nextInt();
System.out.println(CaeserShiftEncryption.shiftAlphabet(KEY));
System.out.println("\nPlease enter your message:");
String message = in.nextLine();
System.out.println(CaeserShiftEncryption.encryptCode(message,KEY));
}
if(choice.equalsIgnoreCase("C"))
{
System.out.println();
}
}
}
}
My problem is, after the "New Alphabet" is printed out to the screen, the program loops back to the very beginning, asking the user to choose a, b, or c. The use never gets a chance to enter a message to be encrypted. Unfortunately, I am required to print out the New Alphabet that is generated, and I can't think of what might be wrong here. I hope you guys can help me out.
Also, the shiftAlphabet and encryptCode methods are both fully functional.
Take a look on this website: http://www.java-made-easy.com/java-scanner.html
particularly
don't try to scan text with nextLine(); AFTER using nextInt() with the same scanner! It doesn't work well with Java Scanner, and many Java developers opt to just use another Scanner for integers
Problems occur with the Scanner class when mixing different type of scans and then using the same Scanner instance with nextLine.
When you get such a problem try to create a new Scanner instance. A simple cure would be to have 1 Scanner for using nextLine and another for everything else.
In the past I've had problems with using the Scanner when it came to next and nextLine, the cure for me was to simply stick to only using nextLine.

Categories

Resources