This question already has answers here:
how to read from standard input non-blocking?
(5 answers)
Closed 8 years ago.
I would like to ask to the user if he could press a key before continuing. Then my program will wait for that during 10 seconds.
If nothing is done, then, I would like to be able to exit the program.
My problem is that the function scanner block my program (until the user have pressed a key) and doesn't allow the program to execute the end.
Do you have any idea of what I could do/use instead of scanner? I am just a beginner in java so please, be indulgent with me.
import java.util.Scanner;
public class Test{
public Test(){
Scanner scan = new Scanner(System.in);
boolean first = true;
System.out.println("Press any key to start.\n");
for(int fr = 0; fr <11; fr++){
System.out.println(fr);
try{
Thread.sleep(1000);
} catch (Exception e) {
System.err.println("error -> "+e.getMessage()); // in case of exception, error message
}
if(fr == 10){
Default def = new Default();
}else if(scan.hasNext() == true){
//System.out.println("Hello");
User user = new User(); // or exit, it doesn't matter
}
}
}
}
Use a KeyListener.
First make a Component, give it the focus, and add a KeyListener.
Example code:
Component comp = new Componenet();
comp.addKeyListener(new KeyListener() {
public void keyTyped(KeyEvent e) {
System.out.print("Hello");
}
public void keyPressed(KeyEvent e) {}
public void keyReleased(KeyEvent e) {}
});
try {
Thread.sleep(1000);
} catch (Exception e) {
}
System.exit(0);
A possible solution is using a different thread to read user input from the scanner. Here is an example code:
Scanner scanner = new Scanner(System.in);
ExecutorService scannerExecutor = Executors.newSingleThreadExecutor();
Future<String> nextLineFuture = scannerExecutor.submit(scanner::nextLine);
/* For Java < 8:
Future<String> nextLineFuture = scannerExecutor.submit(new Callable<String>() {
#Override
public String call() throws Exception {
return scanner.nextLine();
}
});
*/
String input;
try {
input = nextLineFuture.get(5, TimeUnit.SECONDS);
}
catch (TimeoutException e) {
input = "Nothing was entered";
}
catch (InterruptedException | ExecutionException e) {
// Handle the exception
return;
}
System.out.println(input);
However, you need to keep in mind some of the issues with this:
Even when nextLineFuture.get(...) throws TimeoutException, the nextLine call will still be running. If you later run scannerExecutor.submit(scanner::nextLine) again, the input will first be consumed by the previous call, so you should make sure to have a reference to the last Future created whose result hasn't been used yet.
Because of the issue above, this approach will not work if you need to use different scanner methods such as nextBoolean, nextInt, etc. You can, however, always use nextLine on the primary scanner and then parse the line manually (for example, by using yet another scanner)
Related
I want to stop and skip a command while it's waiting for input after 3.5 seconds. I have tried to use System.currentTimeMillis() by subtracting from the start time, however the code I made does not skip the input.
food is an arrayList from the table class.
public void timer() {
startTime = System.currentTimeMillis();
while(false||(System.currentTimeMillis()-startTime)<3500)
{
correct = input(); //What I want to skip after 3.5 seconds
}
record();
}
Here is the input() method:
public boolean input()
{
Scanner console = new Scanner (System.in);
//I want to skip everything after this after 3.5 seconds.
int num = console.nextInt();
num--;
System.out.println("You selected " + table.food.get(num).toString());
table.food.remove(num);
if (num==choice)
{
return true;
}
return false;
}
One of the problems you are facing is that any of the Scanner's next methods can not be interrupted when reading from a console. Therefore you have to read the input in a different way, for example by using a InputStreamReader.
After that you can submit a specific task to a ExecutorService that handels the execution of the "input reading" seperately from the main Thread. You will get a Future on which you can define a timeout.
Note that this operation is still blocking (on both threads).
This solution is somewhat based on this article.
import java.io.*;
import java.util.concurrent.*;
public class Test {
static class ReadInput implements Callable<Integer> {
public Integer call() throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
try {
while (br.ready() == false) {
Thread.sleep(250);
}
String input = br.readLine();
return Integer.parseInt(input);
} catch (InterruptedException e) {
return null;
}
}
}
public static void main(String[] args) {
Integer input = null;
ExecutorService ex = Executors.newSingleThreadExecutor();
try {
Future<Integer> future = ex.submit(new ReadInput());
input = future.get(3500, TimeUnit.MILLISECONDS);
} catch (ExecutionException | InterruptedException | TimeoutException e) {
// handle exceptions that need to be handeled
} finally {
ex.shutdownNow();
}
System.out.println("done: " + input);
}
}
Note that timeout in the ReadInput should be lower than the timeout in the main Thread.
I'm trying to do this: The question is displayed in the console. If during some time the user does not write the answer, then the next question is asked. If the user enters an answer, the next question is asked immediately. My code:
public class Test {
private boolean stopQuestion;
Thread scannerThread = new Thread();
public static void main(final String[] args) {
final Test test = new Test();
test.scannerThread = new Thread(new Runnable() {
#Override
public void run() {
try {
String string;
do {
string = test.requestInput(new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(3000);
} catch (final InterruptedException e) {
}
test.scannerThread.interrupt();
}
}));
} while (!test.stopQuestion);
System.out.println("Input: " + string);
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
});
test.scannerThread.start();
}
public String requestInput(final Thread timer) throws IOException {
final BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
timer.start();
System.out.println("Any question");
System.out.println("Please type your answer: ");
try {
while (!br.ready()) {
Thread.sleep(100);
}
} catch (final InterruptedException e) {
System.out.println("Time is over. Next question: ");
return null;
}
System.out.println("Thank You for providing input!");
return br.readLine();
}
}
If you do not write anything to the console, everything seems to work as expected. Time ends and the next question is asked. But if something is written to the console, the timer starts to malfunction and the next question does not wait for the specified amount of time, sometimes it does not wait at all. I do not understand what's the matter.
I created instance of thread outside the method and pass instance to the method as reference but then throws IllegalThreadStateException.
I see two major problems with your code:
You are continously creating threads that are supposed to read input:
do {
string = test.requestInput(new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(3000);
} catch (final InterruptedException e) {
e.printStackTrace();
}
test.scannerThread.interrupt();
}
}));
} while (!test.stopQuestion); // <-- this is always true
You are opening as many BufferedReaders on System.in as many timer threads you are launching:
final BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
Also, you are not closing any of these BufferedReader instances.
This question already has answers here:
why does the catch block give an error with variable not initialized in Java
(7 answers)
Closed 6 years ago.
So, I'm working on a project that automates everything from character sheets to dice rolls for a table top RPG I like to play. I'm trying to store character data (character name, 2 arrays of stats, and 2 arrays of those stat values) that can be accessed at the start of executing the app. This has been very helpful so far.
However, I'd also like to display the name and stats so the user can confirm that this is the character data they want to use. And I'm having trouble displaying the data in a readable format. Here's my code (you'll find the problem I'm having toward the bottom, although if you see anything else that could be optimized along the way, I would appreciate any feedback :-)":
import java.io.*;
import javax.swing.JOptionPane;
public class fengShuiFiles implements Serializable {//start class
private FileOutputStream outFile;
private ObjectOutput objectWriter;
private FileInputStream inFile;
private ObjectInputStream objectReader;
public void WriteFile(String fileNameIn, String[] sArray1, String[] sArray2,
String[] sArray3, String[] sArray4) {
try {
outFile = new FileOutputStream(fileNameIn + ".txt", true);
objectWriter = new ObjectOutputStream(outFile);
objectWriter.writeObject(sArray1);
objectWriter.writeObject(sArray2);
objectWriter.writeObject(sArray3);
objectWriter.writeObject(sArray4);
} catch (IOException e) {
JOptionPane.showMessageDialog(null, "I/O occurred during a write operation\nFor more",
"information see console output.",
"Read File", JOptionPane.ERROR_MESSAGE);
e.printStackTrace();
} // End try/catch
} // End Open
//not sure if I'll need this. Keeping it for now just in case
//public void writeRecords(String textRecords)
//{
// outFile.close();
// pw.println(textRecords);
//} // End WriteRecords
public void ReadFile(String fileNamein) throws FileNotFoundException {
fengShuiFiles[] sArray1, sArray2, sArray3, sArray4;
try {
inFile = new FileInputStream(fileNamein + ".txt");
objectReader = new ObjectInputStream(inFile);
sArray1 = (fengShuiFiles[]) objectReader.readObject();
sArray2 = (fengShuiFiles[]) objectReader.readObject();
sArray3 = (fengShuiFiles[]) objectReader.readObject();
sArray4 = (fengShuiFiles[]) objectReader.readObject();
} catch (IOException | ClassNotFoundException e) {
JOptionPane.showMessageDialog(null, "I/O error occurred opening a",
"file\nFor more information see console output.",
"Read File", JOptionPane.ERROR_MESSAGE);
e.printStackTrace();
} // End try/catch
for (int x = 0; x < sArray1.length; x++) {
}
}
public void closeFile() {
try {
outFile.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} // End closeFile
}//end class
So, that sArray1.length in the for statement toward the bottom? It's coming up with an error message saying that sArray1 may not have been initialized. And I'm having trouble figuring out why, and how I can get that length so I can print out the arrays in a readable manner. Does anyone have any ideas? Thanks.
You need to initialize local variables. If an exception occurs, it's possible that some or all of the arrays aren't initialized and the compiler won't allow that.
The easiest way to get rid of the error is to initialize the arrays to null, but your program has a logic problem. You're catching the exceptions and continuing, even though there's no way your program can work correctly after that. You should instead throw the exceptions out of the readFile() method and then most likely exit the program. You could also continue as if the file didn't exist, but at least show a warning about it.
You always have to initialize variables in java. You do this in your try block, but if an exception occurs, the array will not have been initialized.
You can move the for loop to the try block:
public void ReadFile(String fileNamein) throws FileNotFoundException {
fengShuiFiles[] sArray1, sArray2, sArray3, sArray4;
try {
...
for(int x = 0; x < sArray1.length; x++) {
}
} catch (IOException | ClassNotFoundException e) {
...
} // End try/catch
}
Or use a default value to initialize the array in the catch block:
public void ReadFile(String fileNamein) throws FileNotFoundException {
fengShuiFiles[] sArray1, sArray2, sArray3, sArray4;
try {
...
} catch (IOException | ClassNotFoundException e) {
...
sArray1 = new fengShuiFiles[0]; // Some default value.
} // End try/catch
for(int x = 0; x < sArray1.length; x++) {
}
}
Something that might be more convenient though, is to return the read arrays, and do something with them in the calling method.
For instance:
public Optional<fengShuiFiles[][]> ReadFile(String fileNamein) throws FileNotFoundException {
try {
fengShuiFiles[] sArray1, sArray2, sArray3, sArray4;
// read the file
return Optional.of(new fenShuiFiles[][]{ sArray1, sArray2, sArray3, sArray4 });
} catch (IOException | ClassNotFoundException e) {
...
return OPtional.empty();
}
}
Then in some other method:
Optional<fengShuiFiles[][]> ret = ReadFile(...);
if(ret.isPresent()) {
for(fengShuiFiles[] arr : ret.get()) {
System.out.println(Arrays.toString(arr)); // Print here
}
}
How can I make my Java run again from the start (main) when it encounters an exception without closing and running it again manually?
My program basically writes on a file. When it cannot find the file I will throw the FileNotFoundException then write the file (say for example hello.txt). After it writes, the program closes (in NetBeans cause I am still developing it) and start showing this at the buttom:
Exception in thread "main" java.lang.NumberFormatException: null
at java.lang.Integer.parseInt(Integer.java:542)
at java.lang.Integer.parseInt(Integer.java:615)
at app4pics1word.App4pics1word.cache(App4pics1word.java:127)
at app4pics1word.App4pics1word.<init>(App4pics1word.java:18)
at app4pics1word.App4pics1word.main(App4pics1word.java:146)
Java Result: 1
you can try this
public static void main(String[] args) {
try {
//something wrong happens here
}catch(Throwable e) {
e.printStackTrace();
main(args);
}
}
You should use exception handling instead of restarting the program. If you restart the program, the error will still be there and thus your program will keep on trying to run for eternity, always failing with the same exception.
You would like to catch your exception and make sure that the input is valid:
boolean okInput = false;
int x = -1;
String someData = "rr";
do {
try {
x = Integer.parseInt(someData); // try to parse
okInput = true;
} catch(NumberFormatException n) {
// Error, try again
okInput = false
someData = "2";
}
} while(!okInput); // Keep trying while input is not valid
// Here x is a valid number
This tutorial provides you good code in general of how exceptions work.
is this what you are looking for ?
public static void main(String [] args) {
boolean done = false;
do {
try {
writeSomeFile();
done = true;
}
catch (Exception ex)
{
System.out.println("Exception trapped "+ex)
}
} while (!done);
}
You can make it a loop that is broken only when the try block succeeds without an Exception:
public static void main(String[] args) {
while(true) {
try {
...
break; //at the end of try block
}
catch (SomeException e) {
//print error message here, or do whatever
}
}
//program continues here once try block gets through w/o exceptions
...
}
However, instead of having this in your main I recommend hiding this rather ugly structure inside a method.
I have to send a set of files to several computers through a certain port. The fact is that, each time that the method that sends the files is called, the destination data (address and port) is calculated. Therefore, using a loop that creates a thread for each method call, and surround the method call with a try-catch statement for a BindException to process the situation of the program trying to use a port which is already in use (different destination addresses may receive the message through the same port) telling the thread to wait some seconds and then restart to retry, and keep trying until the exception is not thrown (the shipping is successfully performed).
I didn't know why (although I could guess it when I first saw it), Netbeans warned me about that sleeping a Thread object inside a loop is not the best choice. Then I googled a bit for further information and found this link to another stackoverflow post, which looked so interesting (I had never heard of the ThreadPoolExecutor class). I've been reading both that link and the API in order to try to improve my program, but I'm not yet pretty sure about how am I supposed to apply that in my program. Could anybody give a helping hand on this please?
EDIT: The important code:
for (Iterator<String> it = ConnectionsPanel.list.getSelectedValuesList().iterator(); it.hasNext();) {
final String x = it.next();
new Thread() {
#Override
public void run() {
ConnectionsPanel.singleAddVideos(x);
}
}.start();
}
private static void singleAddVideos(String connName) {
String newVideosInfo = "";
for (Iterator<Video> it = ConnectionsPanel.videosToSend.iterator(); it.hasNext();) {
newVideosInfo = newVideosInfo.concat(it.next().toString());
}
try {
MassiveDesktopClient.sendMessage("hi", connName);
if (MassiveDesktopClient.receiveMessage(connName).matches("hello")) {
MassiveDesktopClient.sendMessage(newVideosInfo, connName);
}
} catch (BindException ex) {
MassiveDesktopClient.println("Attempted to use a port which is already being used. Waiting and retrying...", new Exception().getStackTrace()[0].getLineNumber());
try {
Thread.sleep(MassiveDesktopClient.PORT_BUSY_DELAY_SECONDS * 1000);
} catch (InterruptedException ex1) {
JOptionPane.showMessageDialog(null, ex1.toString(), "Error", JOptionPane.ERROR_MESSAGE);
}
ConnectionsPanel.singleAddVideos(connName);
return;
}
for (Iterator<Video> it = ConnectionsPanel.videosToSend.iterator(); it.hasNext();) {
try {
MassiveDesktopClient.sendFile(it.next().getAttribute("name"), connName);
} catch (BindException ex) {
MassiveDesktopClient.println("Attempted to use a port which is already being used. Waiting and retrying...", new Exception().getStackTrace()[0].getLineNumber());
try {
Thread.sleep(MassiveDesktopClient.PORT_BUSY_DELAY_SECONDS * 1000);
} catch (InterruptedException ex1) {
JOptionPane.showMessageDialog(null, ex1.toString(), "Error", JOptionPane.ERROR_MESSAGE);
}
ConnectionsPanel.singleAddVideos(connName);
return;
}
}
}
Your question is not very clear - I understand that you want to rerun your task until it succeeds (no BindException). To do that, you could:
try to run your code without catching the exception
capture the exception from the future
reschedule the task a bit later if it fails
A simplified code would be as below - add error messages and refine as needed:
public static void main(String[] args) throws Exception {
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(corePoolSize);
final String x = "video";
Callable<Void> yourTask = new Callable<Void>() {
#Override
public Void call() throws BindException {
ConnectionsPanel.singleAddVideos(x);
return null;
}
};
Future f = scheduler.submit(yourTask);
boolean added = false; //it will retry until success
//you might use an int instead to retry
//n times only and avoid the risk of infinite loop
while (!added) {
try {
f.get();
added = true; //added set to true if no exception caught
} catch (ExecutionException e) {
if (e.getCause() instanceof BindException) {
scheduler.schedule(yourTask, 3, TimeUnit.SECONDS); //reschedule in 3 seconds
} else {
//another exception was thrown => handle it
}
}
}
}
public static class ConnectionsPanel {
private static void singleAddVideos(String connName) throws BindException {
String newVideosInfo = "";
for (Iterator<Video> it = ConnectionsPanel.videosToSend.iterator(); it.hasNext();) {
newVideosInfo = newVideosInfo.concat(it.next().toString());
}
MassiveDesktopClient.sendMessage("hi", connName);
if (MassiveDesktopClient.receiveMessage(connName).matches("hello")) {
MassiveDesktopClient.sendMessage(newVideosInfo, connName);
}
for (Iterator<Video> it = ConnectionsPanel.videosToSend.iterator(); it.hasNext();) {
MassiveDesktopClient.sendFile(it.next().getAttribute("name"), connName);
}
}
}