Nulls can be particularly pernicious in Java because of auto-unboxing.
E.g., imagine you got a NPE from this:
String summary = getUserSummary( user.getId() );
...you'd think "user" must be null, right? But it's quite possible that user.id is a Long, the current value is null, and getUserSummary() requires a long primitive argument.This compiles just fine, and at runtime the Long object will be auto-unboxed to a primitive long... unless it's null.
Surprise!
But things like Optional do help; doing a code review for the things that may be null will fix these kinds of mismatches (and you'll avoid relying on auto-unboxing). The above code is broken -- either user.getId() can never be null (in which case it should be a primitive already) or it might sometime be null, in which case this code must not allow auto-unboxing.