The confusion around whether or not Java has pointers comes from people comparing it with C or C++. In Java, you can't dereference a pointer to an Object and get some sort of Object value. Similarly, you can't perform an "address of" operation on a primitive value and get a pointer to that value. Similarly, you can't pass-by-reference (in the sense of the parent article) or do pointer arithmetic in Java.
While Java technically has pointers (in the sense that it has pointer types), it has dulled them so that you can't hurt yourself with them the same way that C (and C++) permit.
Correct me if I'm wrong (my Java's rusty), but isn't the most common NPE scenario when a class has a member variable that's a class and has to be initialized in the ctor or elsewhere, but the programmer forgets to.
The alternative to this seems to be to require every class to have a no-arg ctor in order to be a member variable of another class. C++ takes this route, and it has the irritating effect of making iostreams, for example, hard to work with.
The best way to deal with this by a substantial margin is to simply not have uninitialized variables, ever, which means you don't need null in the first place (you can replace the functionality with optionals if you really want to, but usually it's not necessary). When I write Java, I declare fields final wherever possible for this and other reasons.
Final is a useful keyword -- a way to make the compiler flag up risky code. :)
The problem (the rest of the time), though, is that if you're writing object-oriented code, some values are simply null. Some data points are unknown, or some properties won't have values for some instances.
If you create an new object but it hasn't been persisted yet, it has a null ID.
If you're working with Categories (of something), some may have a parentCategory and some may not (null).
You can set a placeholder of some kind -- e.g., "-1" means no ID, NO_PARENT is a special Category to return from getParentCategory() if there's no parent, etc.. But then you still need extra code to handle these not-actually-valid values, and when your code is bad, instead of fast-failing with a NullPointerException... things will work, but weirdly. You'll get more confusing errors, further away from the actual bad code.
The Apache Commons way to deal with null is something of a hack, but it works -- library methods for common actions with built-in null handling.
E.g., StringUtils.isBlank(s) is true if s is null, or empty, or only whitespace.
ObjectUtils.isEquals(o1, o2) is true if both are null, false if only one is null, or true if o1.equals(o2).
CollectionUtils.isEmpty(c) returns true if the collection is null, or empty.
I haven't much explored other OO-based approaches to null that are less annoying than Java's handling -- so I'm always curious to hear about smarter approaches.
OP mentioned one of the other approaches..."Optional". An `Optional<String>` will be a non-null reference to either a present value, or an absent value. It's really just modelling null at a non-syntax level, and encourages checking whether there is a value explicitly (i.e. it's self documenting that you need to check if the value is present before using it).
Proponents of Optional will then say that every non-Optional reference must never be null, through static/runtime assertions (like @Nonnull, checkNotNull(), etc)
It's a well know fact that Java has pointers given that you have NullPointerException as an exception.