I am working on a project that requires receiving and processing inputs from console. I use eclipse and accidentally discovered that when I press CTRL+Z in my console (without pressing ENTER after), the program crashes with a NoSuchElementException which I believe was thrown by the Scanner.nextLine() method. Below is the stripped down version of it.
Test.java
import java.util.NoSuchElementException;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String input = "";
while(true) {
System.out.printf("Say something: ");
input = scanner.nextLine();
String output = input.trim().toUpperCase();
if(output.equals("Q")) {
break;
}
System.out.printf("Uppercase: %s\n", output);
}
scanner.close();
}
}
Here is my test run:
Say something: hey
Uppercase: HEY
Say something: i'm boutta crash this program by pressing ctrl+z
Uppercase: I'M BOUTTA CRASH THIS PROGRAM BY PRESSING CTRL+Z
Say something: Exception in thread "main" java.util.NoSuchElementException: No line found
at java.base/java.util.Scanner.nextLine(Scanner.java:1656)
at Test.main(Test.java:11)
I also compiled the .java file with javac Test.java and run with java Test in Windows Command Prompt. Here is the output.
C:\>cd Test
C:\Test>javac Test.java
C:\Test>java Test
Say something: i'm gonna press ctrl+c
Uppercase: I'M GONNA PRESS CTRL+C
Say something: Exception in thread "main" java.util.NoSuchElementException: No line found
^C
C:\Test>
Are there any way to prevent CTRL+Z and CTRL+V from being read by the scanner? Thank you in advance for any help/explanations.
I tried surrounding the line input = scanner.nextLine(); with try/catch block. Here is my attempt.
try {
input = scanner.nextLine();
} catch(NoSuchElementException e) {
scanner = new Scanner(System.in);
System.out.printf("caught NoSuchElementException\n");
}
I got an infinite loop.
Say something: pressing ctrl+z...
Uppercase: PRESSING CTRL+Z...
Say something: caught NoSuchElementException
Uppercase: PRESSING CTRL+Z...
Say something: caught NoSuchElementException
Uppercase: PRESSING CTRL+Z...
Say something: caught NoSuchElementException
Uppercase: PRESSING CTRL+Z...
...
ctrl+z in windows or ctrl-d in Linux are DOS commands for the end of input. So, if you deploy your program in Linux, it will behave the same for the input of ctrl-d. You should handle this by calling method scanner.hasNextLine() which returns true only if there is input. I have attached the modified program, it runs. You may refer.
public class ControlPlusZ {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String input = "";
while(true) {
System.out.printf("Say something: ");
if(scanner.hasNextLine()) {
System.out.println(scanner.hasNextLine());
input = scanner.nextLine();
String output = input.trim().toUpperCase();
if(output.equals("Q")) {
break;
}
System.out.printf("Uppercase: %s\n", output);
}
else {System.out.println("Closing scanner");
break;}}
scanner.close();
}
}
Related
I have come across an issue when running the following code under Netbeans Gradle Java Application.
import java.util.Scanner;
import java.util.concurrent.TimeUnit;
public class Main {
private static int imgBundle;
private static int flacBundle;
private static int vidBundle;
public static void main(String[] args) {
takeInput();
}
private static void takeInput() {
Scanner input = new Scanner(System.in);
System.out.print("Please enter the number of Image format for the order: ");
imgBundle = input.nextInt(); // where the error occurred
System.out.print("Please enter the number of Audio format for the order: ");
flacBundle = input.nextInt(); // where the error occurred
System.out.print("Please enter the number of Video format for the order: ");
vidBundle = input.nextInt(); // where the error occurred
System.out.println("Your Order Input:");
System.out.println(imgBundle + " IMG");
System.out.println(flacBundle + " FLAC");
System.out.println(vidBundle + " VID");
System.out.println("");
System.out.println("Calculating...Please wait...");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
}
}
An Error occurred
Exception in thread "main" java.util.NoSuchElementException
at java.base/java.util.Scanner.throwFor(Scanner.java:937)
at java.base/java.util.Scanner.next(Scanner.java:1594)
at java.base/java.util.Scanner.nextInt(Scanner.java:2258)
at java.base/java.util.Scanner.nextInt(Scanner.java:2212)
at BundlesCalculator.Main.takeInput(Main.java:65)
at BundlesCalculator.Main.main(Main.java:43)
However, I wrote the same code in a simple Java Application without Gradle, there is no issue occurred.
I just wonder what did I do incorrectly?
Scanner will throw that exception if there is no more input to be read. This can happen if your input file is empty, or it doesn't contain enough data for all the nextInt() calls.
If input is from the terminal, you provided end-of-file (Ctrl-Z on Windows, Ctrl-D on Linux) before all the input was read.
I'm working on a Windows 7 machine.
I'm working on an application which is a front for the GHCi interpreter for Haskell. The user will input a command, then Java will execute the command via the exec() method on Runtime, and then the application will display the text that would display if the user was just running GHCi using command prompt.
Right now, I'm running into issues with the loop that prints the output.
Here is the code I have right now.
public class GHCiTest {
public static Scanner rd, sc;
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
try {
System.out.println("Starting... ");
Process p = Runtime.getRuntime().exec("ghci");
PrintStream hugsin = new PrintStream(p.getOutputStream());
InputStream hugsout = p.getInputStream();
sc = new Scanner(hugsout);
rd = new Scanner(System.in);
String rdnextline;
while (true){
while (sc.hasNextLine()){
System.out.println(sc.nextLine());
}
System.out.println("yay");
rdnextline = rd.nextLine();
if (rdnextline == "quit"){break;}
hugsin.println(rdnextline);
hugsin.flush();
}
System.out.println(" ... successful completion.");
}
catch(IOException e) {
e.printStackTrace();
}
}
}
I know that the initial starting of GHCi is working, because the program is printing out "GHCi, version 7.10.3: http://www.haskell.org/ghc/ :? for help". However, the issue appears to be the while(sc.hasNextLine()) loop, which is supposed to read the output of the command prompt and output it until there's nothing left, as it won't break out of the loop and proceed to read the user input. I know this because the program isn't printing the "yay" flag I put in after the loop.
Receive output of ghci in another thread like this.
System.out.println("Starting... ");
Process p = Runtime.getRuntime().exec("ghci");
PrintStream hugsin = new PrintStream(p.getOutputStream());
InputStream hugsout = p.getInputStream();
Scanner rd = new Scanner(System.in);
new Thread(() -> {
try (Reader r = new InputStreamReader(hugsout)) {
int ch;
while ((ch = r.read()) != -1)
System.out.print((char)ch);
} catch (IOException e ) {}
}).start();
Scanner sc = new Scanner(hugsout);
String rdnextline;
while (true) {
rdnextline = rd.nextLine();
hugsin.println(rdnextline);
hugsin.flush();
if (rdnextline.equals("quit")) {
break;
}
}
System.out.println(" ... successful completion.");
Your loop won't exit until the end of the stream has been reached:
while (sc.hasNextLine()){
System.out.println(sc.nextLine());
}
The end of the stream is the end of your process. So, your Java program is waiting for the sub process to run to completion, and terminate. Once that happens, the loop will end, and the Java program will send the desired commands to the process.
Sorry, I mean, try to send the desired commands to the process; it won't succeed because the process has terminated.
If the GHCi process outputs a "prompt" of some kind, you could try to break your while(...) { print } at that moment, get input from the user, send that to the process, and then loop back and re-enter your while(...) { print }, waiting for the next prompt.
Assuming the prompt does not end with a newline, but rather appears at the start of a line where the user input gets typed, you cannot use a while(sc.hasNextLine()) { ... } type of loop, because the prompt is not a complete line. You might have to resort to reading character by character, looking for the prompt sequence in the last "n" characters.
Looks like you can change the prompt in GHCi. See here for details. If you change the prompt to end with a newline, you could still read the stream in lines.
while (sc.hasNextLine()){
String line = sc.nextLine();
if (line.equals("YourPromptHere"))
break;
System.out.println(line);
}
(Alternately, you might be able to do something with threads to allow both parts to run without blocking each other. Of course, threading comes with its own issues and complexity.)
EDIT
I had a blinding flash of the obvious. Assuming GHC's prompt looks like this ...
GHCi, version 7.10.3
yada, yada, yada ...
Main> _
... you could set the scanner's delimiter to be the prompt string Main>.
// Set scanner delimiter to GHCi's Prompt string
sc = new Scanner(hugsout).setDelimiter("^Main> ");
while (sc.hasNext()) {
// Echo GHCi's output upto the delimiter (prompt)
System.out.println(sc.next());
// Read user input & transfer to GHCi.
System.out.print("Replacement Prompt> ");
rdnextline = rd.nextLine();
if (rdnextline == "quit") {
break;
}
hugsin.println(rdnextline);
hugsin.flush();
}
Note: This does not take into account the secondary prompt, used when GHCi expects more input to complete the command. You could use a regex something like "^Main> |\bAlt> " that matches either prompt, but you would not be able to tell which prompt the delimiter matched.
The first subexpression "^Main> " matches the start of a line, followed by "Main> ", where as the second subexpression "\bAlt> " only matches a word boundary followed by "Alt> ". This is because the output stream of the GHCi, would look like "\nMain> Alt> " with a long pause before the Alt>; the "newline" before Alt> would normally come from the echoing of the Enter keypressed on the input stream.
Background info:
I am a high school student who is currently learning Java and as so if my code has an obvious flaw in it/ I accidentally reinvent the wheel with the code, I apologize.
Recently I have been working on writing an esoteric language and decided that I wanted to write it as an interpreter that translates the code to Java and then ran the code. My first step towards this was an attempt to create a mini-program that compiled and ran a java program. Most of the code from that was scrounged from another article, which is the third or fourth article I've looked threw:
how to compile & run java program in another java program?
I used the code from the third answer on that thread and initially thought that it worked. Unfortunately, when I tried running the code using the filename of the class for the program to be compiled and run within itself, the program failed.
Here is the modified code:
/**
*Functions printLines, Run, and parts of main came from stacks overflow
*originaly but modifications have been made
*https://stackoverflow.com/questions/4842684/how-to-compile-run-java-program-in-another-java-program
*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Scanner;
public class JTest
{
private static void printLines(String name, InputStream ins) throws Exception
{
String line = null;
BufferedReader in = new BufferedReader(new InputStreamReader(ins));
while ((line = in.readLine()) != null)
{
//System.out.println(name + " " + line);
System.out.println(line);
}
}
private static int run(String command) throws Exception
{
System.out.println(command);//prints command
Process pro = Runtime.getRuntime().exec(command);
printLines(command, pro.getInputStream());
printLines(command + " stderr:", pro.getErrorStream());
pro.waitFor();
// System.out.println(command + " exitValue() " + pro.exitValue());
return pro.exitValue();
}
public static void main(String args[])
{
System.out.println("Enter the name of the file you want to run: ");
Scanner cin = new Scanner(System.in);
String jFileName = cin.nextLine();
try
{
int k = run("javac " + jFileName + ".java");
if (k==0)
k=run("java " + jFileName);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
I also used another class:
public class Cout
{
public static void main(String args [])
{
System.out.println("Hello World");
}
}
In my initial test...
Output:
Enter the name of the file you want to run:
Input:
Cout
Output:
javac Cout.java
java Cout
Hello World
Here's what Happened when I tried to run JTest from JTest...
Output:
Enter the name of the file you want to run:
Input:
JTest
Output:
javac JTest.java
java JTest
Enter the name of the file you want to run:
Input:
Cout
After I entered this, nothing more was outputted onto the terminal window which leads to my main question:
Why didn't my code run the Cout class and how do I fix it? (Preferably in a way that makes my code compatible with both linux and windows) Or is there a resource someone could point me towards?
Your main issue is understanding input and output streams.
Every process has three standard streams: standard input, standard output and standard error.
When you normally run a program from a command shell, be it Windows CMD or Linux terminal/console, the standard input is attached to the terminal's input stream, and the standard output and error to the console output.
When you run a process from within Java, especially when you use Runtime.exec rather than use a ProcessBuilder, the standard streams are piped from and two the calling program.
What you type into your "front" program doesn't automatically go to the "back" program. The "back" program calls nextLine on a scanner on System.in. Its System.in is redirected to the "front" program through Process.getOutputStream(). It is waiting for something to come through from that pipe. But your "front" program doesn't write anything to that stream. The only streams it has taken care of are the standard output and standard error - the output from the "back" program which is input from the point of view of the "front" program.
So the "back" program will sit and wait and do nothing. And your "front" program at this stage is trying to read its output. It will not stop reading it until the "back" program terminates or closes its standard output. Which of course it doesn't do.
So the two processes are deadlocked. Each of them is waiting for something from the other process.
In fact, there is another possible problem with the way you handle your streams. For example, if the program has errors, those errors will be placed in the standard error stream. If the program terminates, good. But if not, you'll never get to reading the standard error, because you'll still be endlessly waiting for the "standard output" from that program, which may not exist at all.
A possible solution to all this is to have separate threads handling each of the streams.
One thread will need to read the console input ("front" program System.in), and pass anything it reads to the getOutputStream() (standard input of "back" program).
One thread will need to read the "back" program's standard output (getInputStream()), and send everything to its own System.out.
One thread will need to do the same for the error stream and System.err.
But the complication is that when the "back" program terminates, you need to have those threads stop, so that you can read your own System.in again and run another command. The output-handling threads are relatively easy - when the process terminates, they will see "end of file" and they can terminate then. But the "input" reading thread will need to have a mechanism that interrupts it when the "back" program terminated.
BTW, if you use ProcessBuilder to build your process, you'll have better control of the redirection of your input and output. You could let your program write its output and error messages directly to console. You'll still need to design the input properly - lines that are intended for the "front" program should not be consumed by mistake by the "back" program, so you can't do without redirection for input.
It works for me under Fedora 23.
Here is my output:
$ java JTest
Enter the name of the file you want to run:
Cout
javac Cout.java
java Cout
Hello World
I have both JTest.java and Cout.java in the current directory when I run them.
After looking at the answers above, I realized that I forgot that I could call the main method to create a bit of a workaround. So while I will need to create a variable string at some point, here is the code along with its input and Output.
Class JTest
/**
*Functions printLines, Run, and parts of main came from stacks overflow
*originaly but modifications have been made
*http://stackoverflow.com/questions/4842684/how-to-compile-run-java-program-in-another-java-program
*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Scanner;
public class JTest
{
private static void printLines(String name, InputStream ins) throws Exception
{
String line = null;
BufferedReader in = new BufferedReader(new InputStreamReader(ins));
while ((line = in.readLine()) != null)
{
System.out.println(line);
}
}
private static int run(String command) throws Exception
{
Process pro = Runtime.getRuntime().exec(command);
printLines(command, pro.getInputStream());
printLines(command + " stderr:", pro.getErrorStream());
pro.waitFor();
return pro.exitValue();
}
public static void main(String args[])
{
System.out.println("Enter the name of the file you want to run: ");
Scanner cin = new Scanner(System.in);
String jFileName = cin.nextLine();
try
{
String arg[] = { "" } ;
int binary = cin.nextInt();
int k = run("javac " + jFileName + ".java");
if (k == 0)
if (binary == 1)
JTest.main(arg);
else
Foo.main(arg);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
Class Foo
import java.util.Scanner;
public class Foo
{
public static void main(String args [])
{
Scanner cin = new Scanner(System.in);
int bar = cin.nextInt();
System.out.println("Your number times 2 is: " + (bar * 2));
}
}
Input Output Dialogue
Output:
Enter the name of the file you want to run:
Input:
JTest
1
Output:
Enter the name of the file you want to run:
Input:
JTest
1
Output:
Enter the name of the file you want to run:
Input
Foo
0
4
Output:
Your number times 2 is: 4
As the program demonstrates, both input and output work fine.
I am trying to develop an online Java IDE. I am not able to get input from another java program.
The second program: HelloWorld.java
class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello world..................");
Scanner sc = new Scanner(System.in);
System.out.println("Enter Name");
String name = sc.nextLine();
System.out.println("you entered " + name);
sc.close();
}
}
public class Demo {
public static void main(String[] args) {
Process pro = Runtime.getRuntime().exec(javac HelloWorld.java);
Process pro1 = Runtime.getRuntime().exec(java HelloWorld);
}
}
The problem is that when I compile and run the above program I am getting "Enter Name" of System.out.println("Enter Name"); in HelloWorld.java. However, after that nothing happens.
It is not the same "Runtime". Calling exec starts a new process.
Interaction with a running process should use the input and output stream from executing the process.
e.g use the following:
Process p = Runtime.getRuntime().exec(*******);
InputStream is = p.getInputStream();
InputStream es = p.getErrorStream();
OutputStream os = p.getOutputStream();
start with a simple example of passing param to the process manually and afterwards see how you can connect streams from different processes
import java.io.*;
public class ConsoleDemo {
public static void main(String[] args) {
String str;
Console con;
con = System.console();
if (con == null)
return;
str = con.readLine("Enter a string : ");
con.printf("Here is your string %s", str);
}
}
I copied this code from the book, which says that I would get a prompt on the screen for entering a string, but my IDE just gives the message that the execution has termination, without giving me a prompt.
Eclipse nor Netbeans supports the use of Console. The Console.istty() method will return false and you will not have a console to use.
You can change your code to the following and achieve the same result and be able to run it from within the IDE.
import java.io.*;
public class ConsoleDemo {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.println("Enter a String and press enter");
System.out.println("You entered the String: " + scan.nextLine()
}
}
What IDE are you using? This code works just fine when you run it from the command line, so the problem clearly lies with the configuration of your IDE.
Use the following commands to compile and run your code from the command line:
javac ConsoleDemo.java
java ConsoleDemo
Edit: as this link suggests, using System.Console doesn't always work in IDEs. Alternatively you can just use System.in.
Your code is working from both Eclipse and Command Prompt.
Try this way as well if you are using Java 5 or +
Scanner in = new Scanner(System.in);
System.out.print("Enter a String : ");
String string = in.nextLine();
System.out.println("Here is your String : " + string);
By default, eclipse does not associate console with the JVM. You may have to configure it. But if you run it in command line, it will have console definitely and hence it will run without any problem.
It is because your IDE runs this code by javaw.exe (windowless -> no console) not java.exe (with console window) command, so System.console() returns null.
Standard solution is to read data from input stream which is represented by System.in so you can use for instance Scanner like
Scanner keybord = new Scanner(System.in);
String line = keybord.readLine();