A NullPointerException (NPE) is thrown when code uses a reference that holds null as if it pointed at an object: invoking a method on it, reading or writing a field, indexing it as an array, or unboxing it into a primitive. Since Java 14, the message usually names the exact expression that was null, for example “Cannot invoke "String.length()" because "name" is null”, which turns most occurrences into a short investigation: where was that variable supposed to be assigned?
map.get(key) for an absent key, a repository or finder returning null for “no such record”, getParameter for a missing request parameter.order.getCustomer().getAddress() where the customer exists but the address does not.Integer or Boolean that is null converted to int/boolean, in a return statement, arithmetic, or a ternary, often far from where the null originated.Optional for genuinely optional results from your own APIs, so callers are forced by the type to handle absence; and check Map lookups with getOrDefault or containsKey when a key may be absent.Objects.requireNonNull(arg, "arg") at public entry points turns a confusing deep NPE into an immediate, named failure at the caller, where the mistake actually is.Why does my older Java not show which variable was null? Helpful NPE messages arrived in Java 14 (JEP 358) and are on by default from Java 15. On older runtimes the stack trace and line number are all you get, and a debugger or logging at the line is the way to identify the null reference.
What does “because the return value of ... is null” mean? A method in the chain returned null and the next operation dereferenced it. The named method is the producer to inspect; its contract either allows null (handle it) or has a bug (fix it).
Is Optional the answer to all NPEs? No. Optional suits return values of your own methods. It does not help with fields, parameters, or third-party APIs, and using it for those creates awkward code. Contracts and boundary checks cover the rest.