I would like to understand why a snippet of code does not throw a NullPointerException.
Consider the following code:
public class Agent {
public List files = new ArrayList();
public void deliver() {
if( files != null && files.iterator().hasNext() ) {
File file = (File)files.iterator().next();
}
files = new ArrayList();
}
}
The deliver
method is called repeatedly, whilst the following code runs in a separate thread:
public void run() {
agent.files = null;
}
There is only a single agent
instance.
A NullPointerException is never thrown.
However, when the deliver
method pauses, even for 0 milliseconds, a NullPointerException is thrown as expected:
public void deliver() {
if( files != null ) {
Thread.currentThread().sleep( 0 );
if( files.iterator().hasNext() ) {
File file = (File)files.iterator().next();
}
}
files = new ArrayList();
}
My understanding was that there is, in theory, a race condition between checking for files == null
and calling files.iterator().hasNext()
. In practice, I cannot trigger the race condition without introducing the pause (i.e., splitting the null check from the subsequent method call).
Why does the first deliver
method not throw an exception when the null check and usage are combined in the same statement?
NullPointerException is thrown when a reference variable is accessed (or de-referenced) and is not pointing to any object. This error can be resolved by using a try-catch block or an if-else condition to check if a reference variable is null before dereferencing it.
NullPointerException is thrown when program attempts to use an object reference that has the null value. These can be: Invoking a method from a null object. Accessing or modifying a null object's field.
It is generally a bad practice to catch NullPointerException. Programmers typically catch NullPointerException under three circumstances: The program contains a null pointer dereference. Catching the resulting exception was easier than fixing the underlying problem.
NullPointerException is a runtime exception and it is thrown when the application try to use an object reference which has a null value. For example, using a method on a null reference.
Two things:
Thread.sleep(0) still halts execution (potentially more than 0 milliseconds). Basically, even a 0 sleep causes execution on that thread to halt briefly, and then restart. This gives the other thread a chance to run and finish, which is why you're able to trigger the race condition.
files should be volatile
, otherwise the JVM is permitted to optimize in such a way that you may never notice that it's changing value, because it doesn't think it needs to maintain consistency between the threads.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With