Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
How can I handle StackOverflowError in Java?
I'm not sure what you mean with "handle".
You can certainly catch that error:
public class Example {
public static void endless() {
endless();
}
public static void main(String args[]) {
try {
endless();
} catch(StackOverflowError t) {
// more general: catch(Error t)
// anything: catch(Throwable t)
System.out.println("Caught "+t);
t.printStackTrace();
}
System.out.println("After the error...");
}
}
but that is most likely a bad idea, unless you know exactly what you are doing.
You probably have some infinite recursion going on.
I.e. a method that calls itself over and over
public void sillyMethod()
{
sillyMethod();
}
One to handle this is to fix your code so that the recursion terminates instead of continuing forever.
Take a look at Raymond Chen's post When debugging a stack overflow, you want to focus on the repeating recursive part. An extract:
If you go hunting through your defect tracking database trying to see whether this is a known issue or not, a search for the top functions on the stack is unlikely to find anything interesting. That's because stack overflows tend to happen at a random point in the recursion; each stack overflow looks superficially different from every other one even if they are the same stack overflow.
Suppose you're singing the song Frère Jacques, except that you sing each verse a few tones higher than the previous one. Eventually, you will reach the top of your singing range, and precisely where that happens depends on where your vocal limit lines up against the melody. In the melody, the first three notes are each a new "record high" (i.e., the notes are higher than any other note sung so far), and new record highs appear in the three notes of the third measure, and a final record high in the second note of the fifth measure.
If the melody represented a program's stack usage, a stack overflow could possibly occur at any of those five locations in the program's execution. In other words, the same underlying runaway recursion (musically represented by an ever-higher rendition of the melody) can manifest itself in five different ways. The "recursion" in this analogy was rather quick, just eight bars before the loop repeated. In real life, the loop can be quite long, leading to dozens of potential points where the stack overflow can manifest itself.
If you are faced with a stack overflow, then, you want to ignore the top of the stack, since that's just focusing on the specific note that exceeded your vocal range. You really want to find the entire melody, since that's what's common to all the stack overflows with the same root cause.
You might want to see if the "-Xss" option is supported by your JVM. If so, you might want to try setting it to a value of 512k (default is 256k under 32-bit Windows and Unix) and see if that does anything (other than make you sit longer until your StackOverflowException). Note that this is a per-thread setting, so if you've got a lot of threads running you also might want to bump up your heap settings.
The correct answer is the one already given. You likely either a) have a bug in your code leading to an infinite recursion which is usually quite easy to diagnose and fix, or b) have code which can lead to very deep recursions for example recursively traversing an unbalanced binary tree. In the latter situation, you need to alter your code to not allocate the information on the stack (i.e. to not recurse) but to instead allocate it in the heap.
For example, for an unbalanced tree traversal, you could store the nodes that will need to be revisited in a Stack data structure. For an in order traversal you would loop down the left branches pushing each node as you visited it until you hit a leaf, which you would process, then pop a node off the top of the stack, process it, then restart your loop with the right child (by just setting your loop variable to the right node.) This will use a constant amount of stack by moving everything that was on the stack to the heap in the Stack data structure. Heap is typically much more plentiful than stack.
As something that is usually an extremely bad idea, but is necessary in cases where memory use is extremely constrained, you can use pointer reversal. In this technique, you encode the stack into the structure you are traversing, and by reusing the links you are traversing, you can do this with no or significantly less additional memory. Using the above example, instead of pushing nodes when we loop, we just need to remember our immediate parent, and at each iteration, we set the link we traversed to the current parent and then the current parent to the node we are leaving. When we get to a leaf, we process it, then go to our parent and then we have a conundrum. We don't know whether to correct the left branch, process this node, and continue with the right branch, or to correct the right branch and go to our parent. So we need to allocate an extra bit of information as we iterate. Typically, for low-level realizations of this technique, that bit will be stored in the pointer itself leading to no additional memory and constant memory overall. This is not an option in Java, but it may be possible to squirrel away this bit in fields used for other things. In the worst-case, this is still at least 32 or 64 times reduction in the amount of memory needed. Of course, this algorithm is extremely easy to get wrong with completely confusing results and would raise utter havoc with concurrency. So it's almost never worth the maintenance nightmare except where allocating memory is untenable. The typical example being a garbage collector where algorithms like this are common.
What I really wanted to talk about, though, is when you might want to handle the StackOverflowError. Namely to provide tail call elimination on the JVM. One approach is to use trampoline style where instead of performing a tail call you return a nullary procedure object, or if you are just returning a value you return that. [Note: this requires some means of saying a function returns either A or B. In Java, probably the lightest way to do this is to return one type normally and throw the other as an exception.] Then whenever you call a method, you need to do a while loop calling the nullary procedures (which will themselves return either a nullary procedure or a value) until you get a value. An endless loop will become a while loop that is constantly forcing procedure objects that return procedure objects. The benefits of trampoline style is that it only uses a constant factor more stack than you would use with an implementation that properly eliminated all tail calls, it uses the normal Java stack for non-tail calls, the translation simple, and it only grows the code by a (tedious) constant factor. The drawback is you allocate an object on every method call (which will immediately become garbage) and consuming these objects involves a couple of indirect calls per tail call.
The ideal thing to do would be to never allocate those nullary procedures or anything else in the first place, which is exactly what tail call elimination would accomplish. Working with what Java provides though, what we could do is run the code as normal and only make these nullary procedures when we run out of stack. Now we still allocate those useless frames, but we do so on the stack rather than the heap and deallocate them in bulk, also, our calls are normal direct Java calls. The easiest way to describe this transformation is to first rewrite all multi-call-statement methods into methods that have two call statements, i.e. fgh() { f(); g(); h(); } becomes fgh() { f(); gh(); } and gh(){ g(); h(); }. For simplicity, I'll assume all methods end in a tail call, which can be arranged by just packaging the remainder of a method into a separate method, though in practice, you'd want to handle these directly. After these transformations we have three cases, either a method has zero calls in which case there is nothing to do, or it has one (tail) call, in which case we wrap it in a try-catch block in the same we will for the tail call in the two call case. Finally, it may have two calls, a non-tail call and a tail call, in which case we apply the following transformation illustrated by example (using C#'s lambda notation which could easily be replaced with an anonymous inner class with some growth):
// top-level handler
Action tlh(Action act) {
return () => {
while(true) {
try { act(); break; } catch(Bounce e) { tlh(() => e.run())(); }
}
}
}
gh() {
try { g(); } catch(Bounce e) {
throw new Bounce(tlh(() => {
e.run();
try { h(); } catch(StackOverflowError e) {
throw new Bounce(tlh(() => h());
}
});
}
try { h(); } catch(StackOverflowError e) {
throw new Bounce(tlh(() => h()));
}
}
The main benefit here is if no exception is thrown, this is the same code as we started with just with some extra exception handlers installed. Since tail calls (the h() call) don't handle the Bounce exception, that exception will fly through them unwinding those (unnecessary) frames from the stack. The non-tail calls catch the Bounce exceptions and rethrow them with the remaining code added. This will unwind the stack all the way up to the top level, eliminating the tail call frames but remembering the non-tail call frames in the nullary procedure. When we finally execute the procedure in the Bounce exception at the top-level, we will recreate all the non-tail call frames. At this point, if we immediately run out of stack again, then, since we don't reinstall the StackOverflowError handlers, it will go uncaught as desired, since we really are out of stack. If we get a little further, a new StackOverflowError will be installed as appropriate. Furthermore, if we do make progress, but then do run out of stack again, there is no benefit re-unwinding the frames we already unwound, so we install new top-level handlers so that the stack will only be unwound up to them.
The biggest problem with this approach is that you'll probably want to call normal Java methods and you may have arbitrarily little stack space when you do, so they may have enough space to start but not finish and you can't resume them in the middle. There are at least two solutions to this. The first is to ship all such work to a separate thread which will have it's own stack. This is pretty effective and pretty easy and won't introduce any concurrency (unless you want it to.) Another option is simply to purposely unwind the stack before calling any normal Java method by simply throwing a StackOverflowError immediately before them. If it still runs out of stack space when you resume, then you were screwed to begin with.
A similar thing can be done to make continuations just-in-time too. Unfortunately, this transformation isn't really bearable to do by hand in Java, and is probably borderline for languages like C# or Scala. So, transformations like this tend to be done by languages that target the JVM and not by people.
I guess you can't - or it at least depends on the jvm you use. Stack overflow means, that you have no room to store local variables and return adresses. If your jvm does some form of compiling, you have the stackoverflow in the jvm as well and that means, you can't handle it or catch it. The jvm has to terminate.
There could be a way to create a jvm that allows for such behavior, but it would be slow.
I have not tested the behavior with the jvm, but in .net you just can't handle the stackoverflow. Even try catch won't help. Since java and .net rely on the same concept (virtual machines with jit) I suspect java would behave the same. The presence of a stackoverflow-exception in .NET suggests, there might be some vm that does enable the program to catch it, the normal does not though.
Most chances to get StackOverflowError are by using [long/infinite] recursions in a recursive functions.
You can avoid Function recursion by changing your application design to use stackable data objects. There are coding patterns to convert recursive codes to iterative code blocks. Have a look at below answeres:
way-to-go-from-recursion-to-iteration
can-every-recursion-be-converted-into-iteration
design-patterns-for-converting-recursive-algorithms-to-iterative-ones
So, you avoid memory stacking by Java for your recessive function calls, by using your own data stacks.
On some occasions, you can't catch StackOverflowError.
Whenever you try, you will encounter a new one. Because it is the Java VM. It's good to find recursive code blocks, like Andrew Bullock's said.
The stack trace should indicate the nature of the problem. There should be some obvious looping when you read the stack trace.
If it's not a bug, you need add a counter or some other mechanism to halt the recursion before the recursion goes so deep it causes a stack overflow.
An example of this might be if you're handling nested XML in a DOM model with recursive calls and the XML is nested so deep it causes a stack overflow with your nested calls (unlikely, but possible). This would have to be pretty deep nesting to cause a stack overflow though.
As mentioned by many in this thread, the common cause for this is a recursive method call that doesn't terminate. Where possible avoid the stack overflow and if you this in testing you should consider this in most cases to be a serious bug. In some cases you can configure the thread stack size in Java to be larger to handle some circumstances ( large data sets being managed in local stack storage, long recursive calls) but this will increase the overall memory footprint which can lead to issues in the number of threads available in the VM. Generally if you get this exception the thread and any local data to this thread should be considered toast and not used( ie suspect and possibly corrupt).
Simple,
Look at the stack trace that the StackOverflowError produces so you know where in your code it occurs and use it to figure out how to rewrite your code so that it doesn't call itself recursively (the likely cause of your error) so it won't happen again.
StackOverflowErrors are not something that needs to be handled via a try...catch clause but it points to a basic flaw in the logic of your code that needs to be fixed by you.
java.lang.Error javadoc:
An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch. Most such errors are abnormal conditions. The ThreadDeath error, though a "normal" condition, is also a subclass of Error because most applications should not try to catch it.
A method is not required to declare in its throws clause any subclasses of Error that might be thrown during the execution of the method but not caught, since these errors are abnormal conditions that should never occur.
So, don't. Try to find what's wrong in the logic of your code. This exception ocurrs very often because of infinite recursion.
StackOverFlow error - when you create a method in Java at the time some size of memory will be allocated in the stack memory. If you create a method inside the infinite loop then a memory allocation will be created 'n' times. When the limit for memory allocation is exceeded then the error will occur. The error is called a StackOverFlow error.
If you want to avoid this error please consider the stack memory size during the implementation from the beginning.
/*
Using Throwable we can trap any know error in JAVA..
*/
public class TestRecur {
private int i = 0;
public static void main(String[] args) {
try {
new TestRecur().show();
} catch (Throwable err) {
System.err.println("Error...");
}
}
private void show() {
System.out.println("I = " + i++);
show();
}
}
However you may have a look at the link: http://marxsoftware.blogspot.in/2009/07/diagnosing-and-resolving.html to understand the code snippet, which may raise error
Related
public static Throwable getCause(#Nonnull Throwable t) {
while ((t instanceof ExecutionException || t instanceof CompletionException) && t.getCause() != null) {
t = t.getCause();
}
return t;
}
Is this code dangerous in a sense that the while loop may never end? Just wondering if someone can cause this to go on forever.
If so, what might be a better way to handle this? I'm thinking maybe adding an upper bound limit.
Is this code dangerous in a sense that the while loop may never end? Just wondering if someone can cause this to go on forever.
In short: Theoretically? Yes. But practically? No. Your code is fine as is.
In long:
Theoretically, yes
Sure, one can create a loop in the causal chain just fine. GetCause() is just a method, and not a final one at that; exceptions are just classes, so one can make their own exception and write public Throwable getCause() { return this; }.
Practically, no
... but just because someone could do that, doesn't mean you should deal with it. Because why do you want to deal with that? Perhaps you're thinking: Well, if some programmer is intentionally trying to blow up the system, I'd want to be robust and not blow up even when they try.
But therein lies a problem: If someone wants to blow up a system, they can. It's nearly trivial to do so. Imagine this:
public class HahaHackingIsSoEasy extends RuntimeException {
#Override public Throwable getCause() {
while (true) ;
}
}
And I throw that. Your code will hang just the same, and if you attempt to detect loops, that's not going to solve the problem. And if you try to stop me from doing this, too, by firing up a separate thread with a timeout and then using Thread.stop() (deprecated, and dangerous) to stop me, I'll just write a loop without a savepoint in which case neither stop() nor using JVMTI to hook in as a debugger and stop that way is going to work.
The conclusion is: There are only 2 reliable ways to stop intentionally malicious code:
The best, by far: Don't run the malicious code in the first place.
The distant second best option: Run it in a highly controlled sandbox environment.
The JVM is un-sandboxable from inside itself (no, the SecurityManager isn't good enough. It has absolutely no way to stop (savepoint-less) infinite loops, for example), so this at the very least involves firing up an entirely separate JVM just to do the job you want to do, so that you can set timeouts and memory limits on it, and possibly an entire new virtual machine. It'll take thousands of times the resources, and is extremely complicated; I rather doubt that's what you intended to do here.
But what about unintentional loops?
The one question that remains is, given that we already wrote off malicious code (not 'we can deal with it', but rather 'if its intentionally malicious you cannot stop them with a loop detector'), what if it's an accident?
Generally, the best way to deal with accidents is to not deal with them at all, not in code: Let them happen; that's why you have operations teams and server maintainers and the like (you're going to have to have those, no matter what happens. Might as well use them). Once it happens, you figure it out, and you fix it.
That leaves just one final corner case which is: What if loops in causal chains have a plausible, desired usecase?
And that's a fair question. Fortunately, the answer is a simple: No, there is no plausible/desired usecase. Loops in causal chains do not happen unless there is a bug (in which case, the answer is: Find it, fix it), or there is malicious case (in which case, the answer is: Do not run it and call your security team).
The loop is following the exception hierarchy down to the root cause.
If that one points back to one of the already visited exceptions there is a bigger fail in the causality. Therefore I'd say it will never go into an infinite loop.
Of course it is possible, you can't prevent someone write something like:
public class ExceptionWithCauseAsItself extends ExecutionException {
#Override
public Throwable getCause() {
return this;
}
}
Following the principle of Defensive Programming, the method should not fall into infinite loop even when someone throw something like ExceptionWithCauseAsItself.
Since your case is not only getting the root cause, probably there is no library to fit what you use. I suggest refer to Apache Common Langs ExceptionUtils.getRootCause to get some idea on how to tackle recursive cause structures.
But as suggested by rzwitserloot, it is just impossible to defence when someone just want to messy you up.
So why does ExceptionUtils.getRootCause mention below?
this method handles recursive cause structures
that might otherwise cause infinite loops
Browsing the history, getThrowableList implementation is using ExceptionUtils.getCause, which tried to get cause by introspect different method, and hence it may cause cyclic cause chain.
This behaviour is already rectified in this commit by calling Throwable#getCause instead. So cyclic cause chain should not happen in general.
More reference related to this topic:
Why is exception.getCause() == exception?.
How can I loop through Exception getCause() to find root cause with detail message
Cycles in chained exceptions
I'm surprised at how it is possible to continue execution even after a StackOverflowError has occurred in Java.
I know that StackOverflowError is a sublass of the class Error.
The class Error is decumented as "a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch."
This sounds more like a recommendation than a rule, subtending that catching a Error like a StackOverflowError is in fact permitted and it's up to the programmer's reasonability not to do so. And see, I tested this code and it terminates normally.
public class Test
{
public static void main(String[] args)
{
try {
foo();
} catch (StackOverflowError e) {
bar();
}
System.out.println("normal termination");
}
private static void foo() {
System.out.println("foo");
foo();
}
private static void bar() {
System.out.println("bar");
}
}
How can this be? I think by the time the StackOverflowError is thrown, the stack should be so full that there is no room for calling another function. Is the error handling block running in a different stack, or what is going on here?
When the stack overflows and StackOverflowError is thrown, the usual exception handling unwinds the stack. Unwinding the stack means:
abort the execution of the currently active function
delete its stack frame, proceed with the calling function
abort the execution of the caller
delete its stack frame, proceed with the calling function
and so on...
... until the exception is caught. This is normal (in fact, necessary) and independent of which exception is thrown and why. Since you catch the exception outside of the first call to foo(), the thousands of foo stack frames that filled the stack have all been unwound and most of the stack is free to be used again.
When the StackOverflowError is thrown, the stack is full. However, when it's caught, all those foo calls have been popped from the stack. bar can run normally because the stack is no longer overflowing with foos. (Note that I don't think the JLS guarantees you can recover from a stack overflow like this.)
When the StackOverFlow occurs, the JVM will pop down to the catch, freeing the stack.
In you example, it get rids of all the stacked foo.
Because the stack doesn't actually overflow. A better name might be AttemptToOverflowStack. Basically what it means is that the last attempt to adjust the stack frame errs because there isn't enough free space left on the stack. The stack could actually have lots of space left, just not enough space. So, whatever operation would have depended upon the call succeeding (typically a method invocation), never gets exectued and all that is left is for the program to deal with that fact. Which means that it is really no different from any other exception. In fact, you could catch the exception in the function that is making the call.
As has already been answered, it is possible to execute code, and in particular to call functions, after catching a StackOverflowError because the normal exception handling procedure of the JVM unwinds the stack between the throw and the catch points, freeing stack-space for you to use. And your experiment confirms that is the case.
However, that is not quite the same as saying that it is, in general, possible to recover from a StackOverflowError.
A StackOverflowError IS-A VirtualMachineError, which IS-AN Error. As you point out, Java provides some vague advice for an Error:
indicates serious problems that a reasonable application should not try to catch
and you, reasonably, conclude that should sounds like catching an Error might be OK in some circumstances. Note that performing one experiment does not demonstrate that something is, in general, safe to do. Only the rules of the Java language and the specifications of the classes you use can do that. A VirtualMachineError is a special class of exception, because the Java Language Specification and the Java Virtual Machine Specification provide information about the semantics of this exception. In particular, the latter says:
A Java Virtual Machine implementation throws an object that is an instance of a subclass of the class VirtualMethodError when an internal error or resource limitation prevents it from implementing the semantics described in this chapter. This specification cannot predict where internal errors or resource limitations may be encountered and does not mandate precisely when they can be reported. Thus, any of the VirtualMethodError subclasses defined below may be thrown at any time during the operation of the Java Virtual Machine:
...
StackOverflowError: The Java Virtual Machine implementation has run out of stack space for a thread, typically because the thread is doing an unbounded number of recursive invocations as a result of a fault in the executing program.
The crucial problem is that you "cannot predict" where or when a StackOverflowError will be thrown. There are no guarantees about where it will not be thrown. You can not rely on it being thrown on entry to a method, for example. It could be thrown at a point within a method.
This unpredictability is potentially disastrous. As it can be thrown within a method, it could be thrown part way through a sequence of operations that the class considers to be one "atomic" operation, leaving the object in a partially modified, inconsistent, state. With the object in an inconsistent state, any attempt to use that object could result in erroneous behaviour. In all practical cases you can not know which object is in an inconsistent state, so you have to assume that no objects are trustworthy. Any recovery operation or attempt to continue after the exception is caught could therefore have erroneous behaviour. The only safe thing to do is therefore to not catch a StackOverflowError, but rather to allow the program to terminate. (In practice you might attempt to do some error logging to assist troubleshooting, but you can not rely on that logging operating correctly). That is, you can not reliably recover from a StackOverflowError.
Hello android/Java developers,
When a function call a function and that function call another one and so on, how many calls (stack length) would get me into stack over flow? Is there a general rule of thumb?
The reason i am asking is because I am now which is more efficient(design wise) for my 5 players cards game
Solution 1:
for(int i=0;i<100;i++){
p1.play();
p2.play();
p3.play();
p4.play();
}
Solution 2:
p1.play(); //where p1.play() calls p2.play() and so on until p4 calls p1 again.
// this will go on for 100 times
I prefer solution 2 so if there is a crash I can see all the function calls from p1 at i=0 till p4 at i=100
but with solution 1, the stack is much shorter but when there is a crash I will see on the beginning of the loops a the called function play() where crash happened
What do you suggest? I know it is kinda 2 questions in 1 but they are very related
Thank you all
In my experience, a stack overflow in Java is almost always due to a programming error. See typical sizes here.
Now, your second solution is, IMO, quite ugly... almost a programming error. Assuming N=100 is (sort of) the duration of your game, it sounds just wrong that the memory consumption (stack size) increases with it. I don't like that solution at all.
when there is a crash I will see on the beginning of the loops a the
called function play() where crash happened
I don't see the real advantage. Why not put a try catch block so that in case of a crash you can print out the iteration number?
There is no general rule of thumb for recursive or nested functions creating a stack overflow. Instead it is dependent on the memory available on the stack, which may vary depending on underlying hardware and operating system allocations.
It is difficult to determine which method of function calls is better for your situation without seeing more of the code. I would side with the former (first) option because it is a little more explicit towards what is happening, and it avoids linking together possible methods and object instances that may not necessarily be dependent on one another. If you are primarily concerned by error reports, you can try adding Logs into your code to allow for more verbose knowledge of what is going on, along with looking at the dump of the stack trace. Hopefully this link can help you as well: http://developer.android.com/tools/debugging/index.html
I think Shivan Dragon is right, there is no fix amount of calls, that will cause an overflow. However you can test it with a really simple recursive function:
public void stackTest(int iteration)
{
System.out.println("Iteration: "+iteration); // or Log
stackTest(iteration+1);
}
And call it like:
stackTest(1);
and then see how far it goes.
I don't think you can say that a general number of x function calls will trigger an overflow of the stack memory. It depends on the functions, their arguments, their return types etc, all are kept on the stack memory, so different functions may take different amounts of (stack) memory.
At any rate, you should never rely on code that gets even remotely close to crashing the stack by trying to take into account how much of the stack is used. Your code should always be waaay clear of overflowing the stack.
Each method's frame in Java has: local variables table and operands stack. This stack size is constant and each method might have different size of it. Due to JVM specification the operand stack size is stored in methods attribute Code in max_stack field:
Code_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 max_stack;
u2 max_locals;
u4 code_length;
u1 code[code_length];
u2 exception_table_length;
{ u2 start_pc;
u2 end_pc;
u2 handler_pc;
u2 catch_type;
} exception_table[exception_table_length];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
This size is calculated during compilation and might be changed by JVM when you hit StackOverflowException. JVM specification:
The following exceptional conditions are associated with Java virtual machine stacks: If the computation in a thread requires a larger Java virtual machine stack than is permitted, the Java virtual machine throws a StackOverflowError. If Java virtual machine stacks can be dynamically expanded, and expansion is attempted but insufficient memory can be made available to effect the expansion, or if insufficient memory can be made available to create the initial Java virtual machine stack for a new thread, the Java virtual machine throws an OutOfMemoryError.
To sum up: it depends how much memory your JVM is permitted to obtain. On different workstations/smartphones you might have different values of available memory. This is why you shouldn't write code which is dependent on such things. If you think that OutOfMemoryException might occur try to solve your problem iterative instead of recursive.
This come down to the principle of recursion vs iteration.
Recursion allows you to write an algorithm in a simple manner; easier to understand and quicker to implement.
Recursive algorithms can be converted to iterative algorithms which will be more memory efficient and more cpu efficient.
So the decision is one of performance vs simplicity/coding effort.
Here is a thread about this topic:
Recursion or Iteration?
Which is faster in Java, and why?
try {
object.doSomething()
} catch (NullPointerException e) {
if (object == null) {
object = new .....;
object.doSomething();
} else throw e;
}
or
if (object == null) {
object = new .....;
}
object.doSomething();
and why?
The code would be called often, and object is only null the first time it's called, so don't take the cost of the thrown NPEinto account (it only happens once).
P.S. I know the second is better because of simplicity, readability, etc, and I'd surely go for that in real software. I know all about the evil of premature optimization, no need to mention it.
I'm merely curious about these little details.
You should absolutely use the latter way, not because it's faster, but because it's more idiomatic. Exceptions should not be used for control flow in your java programs.
this is purely anecdotal, but all the microbenchmarking I have ever done has shown that using exceptions for control flow won't be as performant as conditionals, although it's probably impossible to support this as a generalization and the JVM is very good at optimizing around things like this anyways, so YMMV.
Forget about speed - look at the size of the code in the first snippet versus the second.
Is the simpler option the best one? Easiest to read, takes up less space, etc. You should strive for code simplicity first, and then worry about speed once you've measured something as slow.
Besides, think about what the runtime needs to do in order to determine that it needs to throw a NullPointerException - it has to check if the current reference is null. So even without measuring, it would logically make sense that performing the check yourself is simpler, rather than leaving it up to the JRE to make the check and create a NullPointerException and unwind the stack.
Regardless of speed, the first way is not good programming practice. For example, what if object was not null but object.doSomething() resulted in the NullPointerException?
This is one reason why you should not use exceptions to control program flow!
To answer your question, version 1 is much slower when it explodes because creating Exceptions is quite expensive, but it is not faster than version 2 because the JVM must do the null check itself anyway so you're not saving anytime. The compiler is likely to optimize the code so it's no faster anyway.
Also Exceptions should be reserved for the exceptional. Initial state of null is not exceptional.
Use the lazy initialization pattern:
SomeClass getIt() {
if (it == null)
it = new SomeClass();
return it;
}
...
getIt().someMethod();
Check the The Java Specialists' Newsletter - Issue 187 Cost of Causing Exceptions for some interesting internal details.
a thrown exception (first example) is nearly always slower than normal control flow code (second example)
that aside the second is much cleaner and easier to understand
I'm going to say the second solution is faster. Not because I'm an expert on the JIT or VM but because it makes sense that a single branch-if-equal assembly-level routine is faster than looking up the object in memory, determining that it is null (the same test, I assume), throwing an exception and possibly mucking up the stack.
Can you try/catch a stack overflow exception in java? It seems to be throwing itself either way. When my procedures overflows, I'd like to "penalize" that value.
Seems to work:
public class Test {
public static void main(String[] argv){
try{
main(null);
}
catch(StackOverflowError e){
System.err.println("ouch!");
}
}
}
If you are getting a stack overflow, you are likely attempting infinite recursion or are severely abusing function invocations. Perhaps you might consider making some of your procedures iterative instead of recursive or double-check that you have a correct base case in your recursive procedure. Catching a stack overflow exception is a bad idea; you are treating the symptoms without addressing the underlying cause.
You have to catch an Error, not the Exception
The functional features of Java 8 makes this question incomparably more important. For while we start to use recursion massively, StackOverflowException is something we MUST count for.
The Java 8 lambdas types has no one among them that throws StackOverflowException. So, we have to create such. It is absolutely necessary, without that we won't pass even the IDE control.
For example, Integer -> Integer function type could look as:
#FunctionalInterface
public interface SoFunction <U> {
public U apply(Integer index) throws StackOverflowException;
}
After that we can write a function that will accept lambdas throwing StackOverflowException.
public T get(int currentIndex) throws StackOverflowException{
And only now we can create a recursive lambda:
fiboSequence.setSequenceFunction(
(i) ->
fiboSequence.get(i-2).add(fiboSequence.get(i-1))
);
After that we can call the recursive chain fiboSequence.get(i)and get a result or a StackOverflowException if the whole chain was incomputable.
In the case of use of recursion SO gets absolutely different meaning: you have jumped too deep, repeat it dividing in more shallow steps.
Sometimes it's just required due to the nature of the code to increase the (OS dependent) stack size, which is usually 1m per thread on Linux.
If you are happy that the code is optimized for your use case and still hit this error then increase the stack size for the VM using -Xss2m for example - See the Oracle docs