I found out ways to terminate (shut-down or stop) my Java programs. I found two solutions for it.
using return;When I want to quit or terminate my program execution , I add this.
using System.exit() ; Sometimes I used it. I read about System.exit() from this question.
So, I know a little on both them. But I am still confused as to how they actually work. Please check below codes...
public class Testing {
public static void main(String... str) {
System.out.println(1);
System.exit(0);
System.out.println(2);
return;
}
}
I am sure that 2 will not appear. I would like to know is why return; or other codes can write below the statement of System.exit(0); and what was real definition for return; (because it is strange thing for me return without any variables or values) ?
Calling System.exit(0) (or any other value for that matter) causes the Java virtual machine to exit, terminating the current process. The parameter you pass will be the return value that the java process will return to the operating system. You can make this call from anywhere in your program - and the result will always be the same - JVM terminates. As this is simply calling a static method in System class, the compiler does not know what it will do - and hence does not complain about unreachable code.
return statement simply aborts execution of the current method. It literally means return the control to the calling method. If the method is declared as void (as in your example), then you do not need to specify a value, as you'd need to return void. If the method is declared to return a particular type, then you must specify the value to return - and this value must be of the specified type.
return would cause the program to exit only if it's inside the main method of the main class being execute. If you try to put code after it, the compiler will complain about unreachable code, for example:
public static void main(String... str) {
System.out.println(1);
return;
System.out.println(2);
System.exit(0);
}
will not compile with most compiler - producing unreachable code error pointing to the second System.out.println call.
System.exit() is a method that causes JVM to exit.
return just returns the control to calling function.
return 8 will return control and value 8 to calling method.
Because System.exit() is just another method to the compiler. It doesn't read ahead and figure out that the whole program will quit at that point (the JVM quits). Your OS or shell can read the integer that is passed back in the System.exit() method. It is standard for 0 to mean "program quit and everything went OK" and any other value to notify an error occurred. It is up to the developer to document these return values for any users.
return on the other hand is a reserved key word that the compiler knows well.
return returns a value and ends the current function's run moving back up the stack to the function that invoked it (if any). In your code above it returns void as you have not supplied anything to return.
System.exit() terminates the JVM.
Nothing after System.exit() is executed.
Return is generally used for exiting a method. If the return type is void, then you could use return;
But I don't think is a good practice to do it in the main method.
You don't have to do anything for terminate a program, unless infinite loop or some strange other execution flows.
So return; does not really terminate your java program, it only terminates your java function (void). Because in your case the function is the main function of your application, return; will also terminate the application. But the return; in your example is useless, because the function will terminate directly after this return anyway...
The System.exit() will completly terminate your program and it will close any open window.
Well, first System.exit(0) is used to terminate the program and having statements below it is not correct, although the compiler does not throw any errors.
a plain return; is used in a method of void return type to return the control of execution to its parent method.
What does return; mean?
return; really means it returns nothing void. That's it.
why return; or other codes can write below the statement of System.exit(0);
It is allowed since compiler doesn't know calling System.exit(0) will terminate the JVM. The compiler will just give a warning - unnecessary return statement
Related
Consider this function :
public boolean foo(){
System.exit(1);
//The lines beyond this will not be read
int bar = 1; //L1
//But the return statement is required for syntactically correct code
return false; //L2
//error here for unreachable code
//int unreachable = 3; //L3
}
Can someone please explain why L1 and L2 visibly not reachable does not give warnings but L3 does.
Because as far as the compiler is concerned, System.exit() is just another method call.
The fact that what it does is end the process can only be found out from the implementation (which is native code, not that it makes any difference).
If you have to put System.exit() in your code (usually it's best to avoid it, unless you want to return a code other than 0), it should really be in a method that returns void, main() for example. It's nicer that way.
As for the reachability, the explanation is the same: return is a keyword of the Java language, so the compiler or the parser the IDE uses can tell that it's theoretically impossible for code after the return statement to be executed. These rules are defined here.
The Java compiler doesn't know anything about System.exit. It's just a method as far as it's concerned - so the end of the statement is reachable.
You say that L1 and L2 are "visibly not reachable" but that's only because you know what System.exit does. The language doesn't - whereas it does know what a return statement does, so it knows that L3 really isn't reachable.
I sometimes think it would be useful to be able to declare that a method isn't just void, but never terminates normally - it never just returns (although it may throw an exception). The compiler would then be able to use that information to make the end of any calling expression unreachable, preventing this sort of thing from being a problem. However, that's just my dreams around language design - Java doesn't have anything similar, and it would be a very bad idea for the compiler to "know" that particular JRE methods will never return normally, when that concept can't be expressed directly within the language.
Instead, the compiler is bound by the rules of section 14.21 of the JLS, including:
The first statement in a non-empty block that is not a switch block is reachable iff the block is reachable.
Every other statement S in a non-empty block that is not a switch block is reachable iff the statement preceding S can complete normally.
...
An expression statement can complete normally iff it is reachable.
(A method call is an expression statement.)
Then from section 8.4.7:
If a method is declared to have a return type, then a compile-time error occurs if the body of the method can complete normally (§14.1).
and in 14.1:
Unless otherwise specified, a statement completes normally if all expressions it evaluates and all substatements it executes complete normally.
So the call to System.exit() can complete normally as far as the compiler is concerned, which means the body of the foo method can complete normally, which leads to the error.
Me: "Can anything be executed after a return statement?"
Java: "NO."
Me: "Can anything be executed after I call System.exit?"
Java: "That's a method, I don't know what it does - it's not a reserved keyword, it doesn't affect program flow as far as I know" (and it may not even work (I don't know if exit can throw exceptions (or future variants of it)))
From the language standpoint, there are only 2 ways to escape current scope: return and throw. Method calls are never considered the same way, even if they consist of the only line of code:
void method() {
throw new RuntimeException();
}
Even more. In theory, any method call can cause RuntimeException to be thrown. In this case, compiler should probably give you warnings for absolutely any method call which is not inside a try block:
...
method(); // WARNING: may throw in theory
anotherMethod(); // WARNING: possible unreachable code, also may throw
anotherMethod2(); // WARNING: possible unreachable code, also may throw
// etc
...
For your question logic is the same.
If a method is declared to return a non-void value, then it must contain a return statement somewhere, even if it's never reached (like in the code in the question).
From the compiler's point of view, System.exit() is just another method call, with nothing special about it that indicates that the program ends as soon as it's reached. Only you, as the programmer, know this fact - but it's something outside of the compiler's knowledge.
About the second part of your question - nothing can go after a return statement in a block of code inside a method, as that will always be unreacheable code. That explains why the compiler complains about the L3 line.
I know this does not make sense, and still this is how the Java compiler works, when you're calling a method.
The compiler does not know at this point what Sytem.exist does (why should rt.jar be different than other jars you compile with , in that sense?).
This is in contrast for example to the next piece of code -
public int test() {
throw new NullPointerException("aaaa");
}
Where the compiler can tell that an exception is always thrown, and therefore no return is needed.
The compiler checks whether some code is reachable only with respect to the return keyword (also throw and break(in case of loops), in general). For the compiler the exit method call is just another call, it doesn't know its meaning, so it doesn't know that the code afterwards will never be reached.
It's possible that the static code analysis tool is not taking into account that the application is terminating.
Consider this function :
public boolean foo(){
System.exit(1);
//The lines beyond this will not be read
int bar = 1; //L1
//But the return statement is required for syntactically correct code
return false; //L2
//error here for unreachable code
//int unreachable = 3; //L3
}
Can someone please explain why L1 and L2 visibly not reachable does not give warnings but L3 does.
Because as far as the compiler is concerned, System.exit() is just another method call.
The fact that what it does is end the process can only be found out from the implementation (which is native code, not that it makes any difference).
If you have to put System.exit() in your code (usually it's best to avoid it, unless you want to return a code other than 0), it should really be in a method that returns void, main() for example. It's nicer that way.
As for the reachability, the explanation is the same: return is a keyword of the Java language, so the compiler or the parser the IDE uses can tell that it's theoretically impossible for code after the return statement to be executed. These rules are defined here.
The Java compiler doesn't know anything about System.exit. It's just a method as far as it's concerned - so the end of the statement is reachable.
You say that L1 and L2 are "visibly not reachable" but that's only because you know what System.exit does. The language doesn't - whereas it does know what a return statement does, so it knows that L3 really isn't reachable.
I sometimes think it would be useful to be able to declare that a method isn't just void, but never terminates normally - it never just returns (although it may throw an exception). The compiler would then be able to use that information to make the end of any calling expression unreachable, preventing this sort of thing from being a problem. However, that's just my dreams around language design - Java doesn't have anything similar, and it would be a very bad idea for the compiler to "know" that particular JRE methods will never return normally, when that concept can't be expressed directly within the language.
Instead, the compiler is bound by the rules of section 14.21 of the JLS, including:
The first statement in a non-empty block that is not a switch block is reachable iff the block is reachable.
Every other statement S in a non-empty block that is not a switch block is reachable iff the statement preceding S can complete normally.
...
An expression statement can complete normally iff it is reachable.
(A method call is an expression statement.)
Then from section 8.4.7:
If a method is declared to have a return type, then a compile-time error occurs if the body of the method can complete normally (§14.1).
and in 14.1:
Unless otherwise specified, a statement completes normally if all expressions it evaluates and all substatements it executes complete normally.
So the call to System.exit() can complete normally as far as the compiler is concerned, which means the body of the foo method can complete normally, which leads to the error.
Me: "Can anything be executed after a return statement?"
Java: "NO."
Me: "Can anything be executed after I call System.exit?"
Java: "That's a method, I don't know what it does - it's not a reserved keyword, it doesn't affect program flow as far as I know" (and it may not even work (I don't know if exit can throw exceptions (or future variants of it)))
From the language standpoint, there are only 2 ways to escape current scope: return and throw. Method calls are never considered the same way, even if they consist of the only line of code:
void method() {
throw new RuntimeException();
}
Even more. In theory, any method call can cause RuntimeException to be thrown. In this case, compiler should probably give you warnings for absolutely any method call which is not inside a try block:
...
method(); // WARNING: may throw in theory
anotherMethod(); // WARNING: possible unreachable code, also may throw
anotherMethod2(); // WARNING: possible unreachable code, also may throw
// etc
...
For your question logic is the same.
If a method is declared to return a non-void value, then it must contain a return statement somewhere, even if it's never reached (like in the code in the question).
From the compiler's point of view, System.exit() is just another method call, with nothing special about it that indicates that the program ends as soon as it's reached. Only you, as the programmer, know this fact - but it's something outside of the compiler's knowledge.
About the second part of your question - nothing can go after a return statement in a block of code inside a method, as that will always be unreacheable code. That explains why the compiler complains about the L3 line.
I know this does not make sense, and still this is how the Java compiler works, when you're calling a method.
The compiler does not know at this point what Sytem.exist does (why should rt.jar be different than other jars you compile with , in that sense?).
This is in contrast for example to the next piece of code -
public int test() {
throw new NullPointerException("aaaa");
}
Where the compiler can tell that an exception is always thrown, and therefore no return is needed.
The compiler checks whether some code is reachable only with respect to the return keyword (also throw and break(in case of loops), in general). For the compiler the exit method call is just another call, it doesn't know its meaning, so it doesn't know that the code afterwards will never be reached.
It's possible that the static code analysis tool is not taking into account that the application is terminating.
This question already has answers here:
Why is main() in java void?
(4 answers)
Closed 5 years ago.
With respect to C/C++ main() must always return an integer(zero to indicate success and non-zero to indicate failure). I can understand this as the program is run it becomes a process and every process should have an exit status, which we obtain by doing echo $? from shell after the process gets over.
Now I don't understand why is the main method does not return anything in Java? Has it got anything to do with the fact that the program is run on JVM and the JVM process is reposnsible for the returning of exit status?
Please clarify.
Thanks,
Roger
Designed when multi-threading was already a common thing, java said (by design) "good bye" to the idea that when 'main' returns the program is done. That's why there's no return value. As the others said use System.exit when you want to exit with return code.
If the main method of a single threaded java application terminates, the application will terminate with exit code 0. If you need another exit code, maybe to indicate an error, you can place
System.exit(yourNumberHere);
anywhere in the code (especially outside of the main method).
This is different for multi-threaded applications , where you either have to use System.exit from the inside of kill -9 from the outside to stop the JVM.
Here's a quick example where termination of main doesn't stop the application (a typical service or daemon behaviour):
public static void main(String args[]) {
Thread iWillSurvive = new Thread(new Runnable() {
public void run() {
while(true) {
// heat the CPU
}
}
});
iWillSurvive.start();
}
Remark: Sure, a thread will terminate when it's run method (or the main method in case of the main thread) terminates. And in this case, when all threads have terminated, the JVM will terminate with exit code 0 (which brings us back to the initial question). Hope everybody is happy now.
Java has System.exit(int) for that purpose.
Basically, a Java program will exit with exit code 0, if program flow reaches the end of the main method (roughly; it gets weirder with Swing and threading, but this should suffice).
If you stick a call to System.exit() somewhere (anywhere, actually) or Runtime.getRuntime().exit() which is what System.exit() calls, then the program ends immediately and prematurely.
You could picture it like Java would implicitly add System.exit(0) at the very end of the main method but there may be more subtle differences. I don't have the complete details of JVM shutdown in my head right now, though.
A minor niggle - in C++, you do not need to return anything from main:
int main() {
}
is a perfectly legal C++ program - it acts as if you had:
return 0;
as the last statement in main.
exit value is useful for scripting like bash script or command line operations.
So in these cases use System.exit().
I suspect the reason for C/C++ returning int is because that's the convention for indicating function/method/program success/failure in those language.
With the introduction of Exceptions in Java, instead of zero for success and non-zero values for failure, it uses an exception hierarchy for failures, and successes were simply when no exceptions were thrown, thus eliminating the need to return a value.
Most programs I write these days have some form of user interface and little that they could usefully return, and even less likelyhood that anything would every need that status code.
So why force all programs to return one? As others have said, you can return a status code should you wish to...
Possibly it could be because System.exit(int exitCode) didn't return a value.
I like to know why only void return type for main method in java.
public static void main(String [] args)
Why there is no other return types other than void for main method.
Thanks
The short answer is: Because that's what the language specification says.
In today's commonly used operating systems (Windows and Unix families), the only "return value" from a process is an exit status, which is a small number (usually 8-bit). This value can be returned from a Java program using the System.exit(int) method:
public static void exit(int status)
Terminates the currently running Java Virtual Machine. The argument serves as a status code; by convention, a nonzero status code indicates abnormal termination.
What were you expecting to return?
In C you typically return an int exit code. However, in a multithreaded system this doesn't make much sense. Typically a Java program will start a number of threads. The main thread will often return more or less immediately.
System.exit can be used to exit with a specific exit code.
It seems like an arbitrary decision, probably considering that not all operating systems are unixy in the sense that they allow a program to return an exit code.
Java could have been specified like C with an int return code from main. Multi-threading does not matter because there is only one thread that originally starts main and its return value could be the one to be returned to the OS by the JVM, regardless of when the other threads return and what they do.
This is far-fetched but if someone built a JVM that can run multiple Java programs each with its own main, it could be designed to return the value returned by the last main to be invoked.
The most reasonable rationale is that the JVM itself may need to return an exit code for reasons of its own, however, this rationale is belied by the provision of System.exit(int) which exactly overrides the JVM's return code. Given this, there is no reason to similarly allow main to return an int too, just as if the last thing that main did was System.exit(n)
All in all, sounds like an arbitrary decision.
Firstly, because there is nothing to return values to. Mainstream operating systems (e.g. Windows, UNIX, Linux, etc) do not allow commands to "return" values. (Though arguably, the exit code is a return value, but it is restricted to an integer and there are various OS-specific caveats; e.g. on how many of the bits can come from the application.)
Secondly, because Java does not allow you to overload methods that differ only on the return type.
Thirdly, as #Tom points out, if the exit code was the return value of main, it would be difficult to deal with other threads calling System.exit(rc).
Java specifies that an application entry point must be public static, named main, returns void, and takes a String[] as a parameter. This is just the way it is.
That said, you can technically define a main method that doesn't meet those criterias, but they won't be a valid application entry point.
public class MainMain {
public static void main(String args[]) { // application entry point
System.out.println(main());
}
private static String main() { // just a method named main
return "Hello world!";
}
}
You should probably reserve main only for valid Java application entry points, but there's nothing preventing you from writing a code like the above.
Because you run main from JVM Hello.main, we can't return value to JVM. It simply gives run time exception.
A reasonable middle way (between having a void signature, but also needing to return a value to the OS) to me then seems to be: To throw a Runtime exception in main for all return values that correspond to an error, with an appropriate message in that exception.
Of course, this helps only to differentiate between error and non-error exits at the OS level (say, a shell script etc.) but in many cases, this is actually all that is needed, and probably the most common use of these environment return values; either run or don't run the next command if this command fails.
Given the following code sample:
public class WeirdStuff {
public static int doSomething() {
while(true);
}
public static void main(String[] args) {
doSomething();
}
}
This is a valid Java program, although the method doSomething() should return an int but never does. If you run it, it will end in an infinite loop. If you put the argument of the while loop in a separate variable (e.g. boolean bool = true) the compiler will tell you to return an int in this method.
So my question is: is this somewhere in the Java specification and are there situation where this behavior might be useful?
I'll just quote the Java Language Specification, as it's rather clear on this:
This section is devoted to a precise explanation of the word "reachable." The idea is that there must be some possible execution path from the beginning of the constructor, method, instance initializer or static initializer that contains the statement to the statement itself. The analysis takes into account the structure of statements. Except for the special treatment of while, do, and for statements whose condition expression has the constant value true, the values of expressions are not taken into account in the flow analysis.
...
A while statement can complete normally iff at least one of the following is true:
The while statement is reachable and the condition expression is not a constant expression with value true.
There is a reachable break statement that exits the while statement.
...
Every other statement S in a nonempty block that is not a switch block is reachable iff the statement preceding S can complete normally.
And then apply the above definitions to this:
If a method is declared to have a return type, then every return statement (§14.17) in its body must have an Expression. A compile-time error occurs if the body of the method can complete normally (§14.1).
In other words, a method with a return type must return only by using a return statement that provides a value return; it is not allowed to "drop off the end of its body."
Note that it is possible for a method to have a declared return type and yet contain no return statements. Here is one example:
class DizzyDean {
int pitch() { throw new RuntimeException("90 mph?!"); }
}
Java specification defines a concept called Unreachable statements. You are not allowed to have an unreachable statement in your code (it's a compile time error). A while(true); statement makes the following statements unreachable by definition. You are not even allowed to have a return statement after the while(true); statement in Java. Note that while Halting problem is undecidable in generic case, the definition of Unreachable Statement is more strict than just halting. It's deciding very specific cases where a program definitely does not halt. The compiler is theoretically not able to detect all infinite loops and unreachable statements but it has to detect specific cases defined in the spec.
If you are asking if infinite loops can be useful, the answer is yes. There are plenty of situations where you want something running forever, though the loop will usually be terminated at some point.
As to your question: "Can java recognized when a loop will be infinite?" The answer is that it is impossible for a computer to have an algorithm to determine if a program will run forever or not. Read about: Halting Problem
Reading a bit more, your question is also asking why the doSomething() function does not complain that it is not returning an int.
Interestingly the following source does NOT compile.
public class test {
public static int doSomething() {
//while(true);
boolean test=true;
while(test){
}
}
public static void main(String[] args) {
doSomething();
}
}
This indicates to me that, as the wiki page on the halting problem suggests, it is impossible for there to be an algorithm to determine if every problem will terminate, but this does not mean someone hasn't added the simple case:
while(true);
to the java spec. My example above is a little more complicated, so Java can't have it remembered as an infinite loop. Truely, this is a weird edge case, but it's there just to make things compile. Maybe someone will try other combinations.
EDIT: not an issue with unreachable code.
import java.util.*;
public class test {
public static int doSomething() {
//while(true);
while(true){
System.out.println("Hello");
}
}
public static void main(String[] args) {
doSomething();
}
}
The above works, so the while(true); isn't being ignored by the compiler as unreachable, otherwise it would throw a compile time error!
Yes, you can see these 'infinite' loops in some threads, for example server threads that listen on a certain port for incoming messages.
So my question is: is this somewhere in the Java specification
The program is legal Java according to the specification. The JLS (and Java compiler) recognize that the method cannot return, and therefore no return statement is required. Indeed, if you added a return statement after the loop, the Java compiler would give you a compilation error because the return statement would be unreachable code.
and are there situation where this behavior might be useful?
I don't think so, except possibly in obscure unit tests.
I occasionally write methods that will never return (normally), but putting the current thread into an uninterruptible infinite busy-loop rarely makes any sense.
After rereading the question....
Java understands while(true); can never actually complete, it does not trace the following code completely.
boolean moo = true;
while (moo);
Is this useful? Doubtful.
You might be implementing a general interface such that, even though the method may exit with a meaningful return value, your particular implementation is a useful infinite loop (for example, a network server) which never has a situation where it should exit, i.e. trigger whatever action returning a value means.
Also, regarding code like boolean x = true; while (x);, this will compile given a final modifier on x. I don't know offhand but I would imagine this is Java's choice of reasonable straightforward constant expression analysis (which needs to be defined straightforwardly since, due to this rejection of programs dependent on it, it is part of the language definition).
Some notes about unreachable statements:
In java2 specs the description of 'unreachable statement' could be found. Especially interesting the following sentence:
Except for the special treatment of while, do, and for statements whose condition expression has the constant value true, the values of expressions are not taken into account in the flow analysis.
So, it is not obviously possible to exit from while (true); infinite loop. However, there were two more options: change cached values or hack directly into class file or JVM operating memory space.