Assuming that nobody screws up and assigns null to an Optional return result/variable instead of Optional.empty(), or calls Optional.get() without remembering to check ... in other words, it's very much like @Nullable when using a compiler that understands it, except it causes problems with overloading and reflection as noted above due to generics type erasure.
If you want code that won't compile due to @Nullable violations I think the Checker framework can give you that, or you can use an IDE that flags violations like IntelliJ and just treat any static analysis warning in that category like a compile failure for your own purposes. The nice think about nullity annotations is that the newest JVM languages like Ceylon and Kotlin are building nullity into their type systems, so if you annotate an API in this way, code written in these new languages will know automatically that the reference can be null and the compiler won't let you access it at all until you tested or asserted away the nullness. The upgrade path for Kotlin especially is looking like it could be quite strong, so I think I'll be sticking with @Nullable for now in the hope that later on we get "real" type system integration via newer languages.
I don't think @NotNull/@Nullable go away completely, but the use of optional makes dealing with nullables much easier. I think this is a much cleaner ways to deal with possible nulls:
If/When HttpServletRequest is updated to support Optional it can return it directly instead of the caller having to do it, and that is when Java will really see the upside.
The above would not work because the call is returning another optional. The null is forced to be dealt with instead of allowing it to lead to programmer error[1]. The construct makes the programmer either call either orElse(), orElseGet(), or orElseThrow(). The programmer could also just return the optional and let the caller deal with it.
Of course this is a trivial example where the programmer is likely expecting null, but many times null can be returned and it is not always clear.
If you want code that won't compile due to @Nullable violations I think the Checker framework can give you that, or you can use an IDE that flags violations like IntelliJ and just treat any static analysis warning in that category like a compile failure for your own purposes. The nice think about nullity annotations is that the newest JVM languages like Ceylon and Kotlin are building nullity into their type systems, so if you annotate an API in this way, code written in these new languages will know automatically that the reference can be null and the compiler won't let you access it at all until you tested or asserted away the nullness. The upgrade path for Kotlin especially is looking like it could be quite strong, so I think I'll be sticking with @Nullable for now in the hope that later on we get "real" type system integration via newer languages.