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.
public ImmutableMap<String, Long> getSessionTime(HttpServletRequest request) {
return Optional.ofNullable(request.getSession(false))
.map(s -> ImmutableMap.of("lastAccessedTime", s.getLastAccessedTime()))
.orElseThrow(IllegalStateException::new);
}
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. Session s;
if ((s = request.getSession(false) != null)
return ImmutableMap.of(....);
else
throw new IllegalStateException();
Maybe I'm weird but I find the old fashioned version far easier to read than the new form. public ImmutableMap<String, Long> getSessionTime(HttpServletRequest request) {
return request.getSession(false)
.map(s -> ImmutableMap.of("lastAccessedTime", s.getLastAccessedTime()))
}
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.
[1] https://code.google.com/p/guava-libraries/wiki/UsingAndAvoid...
Due to backwards compatibility concerns, no existing Java APIs that may currently return null can ever be changed to return Optionals instead, so nulls need to be dealt with regardless. Also, there's technically nothing stopping an Optional value from actually being null itself, or from developers calling Optional.get() without checking isPresent(), just like they might currently use a reference without checking for null.
I personally really wish jsr305 had been adopted in Java8, and their existing APIs retrofitted with these annotations.
http://www.oracle.com/technetwork/articles/java/java8-option... describes Optional, and compares it to how in Groovy, the safe navigation and elvis operators allow you to write code like this:
String version = computer?.getSoundcard()?.getUSB()?.getVersion() ?: "UNKNOWN";
With Java 8 Optionals, this instead becomes: String version = computer.flatMap(Computer::getSoundcard)
.flatMap(Soundcard::getUSB)
.map(USB::getVersion)
.orElse("UNKNOWN");
which is not only much longer and arguably uglier, but also forces developers to suddenly have to worry about applying lambdas using flatmap vs map, where conceptually you're really just dealing with method calls.New languages like Kotlin solve this much better in my opinion by introducing nullable vs nonnullable types. While Java can unfortunately never adopt this due to backwards compatibility issues, @Nullable and @Nonnull will do most of the time, and hopefully we'll see operators like ?. and ?: in future versions of Java.
With option, you clearly declare what is safe, and what isn't, and the compiler won't let you screw up. You can decide which layer of your code handles the empty case, and lots of unnecessary ifs go away from the bytecode itself, so the app will run faster, and you know when you have to even consider the null case.
Now, doing that in Groovy is rather silly, because your language is dynamic and your types are optional, so all of this compile time safety would not provide any value anyway. Option is just the way you'd solve the problem in the strongly typed way. It's how you handle it in Scala, for instance, and how Haskell would deal with it.
As far as using flatmaps and maps to work with optionals, yes, it's a chore. I'd argue it's borderline abuse of the stream operators, as treating Option as a collection is ugly. That said, putting yourself in a situation where you chain 3 optional getters is also object design from hell, so one should avoid putting themselves in that position altogether.
In Scala, instead of flatmapping single optionals, we often getOrElse(), or use pattern matching as an extractor. Now that's a feature I would like to see Java 'steal' from the Scalas and Erlangs of the world, but I do not see that happening.
The elvis op is called the null coalescing op in other languages. [1] Groovy's promoter chose the elvis name to fit in with marketing the Groovy and G-String names.
PHP also uses the ?: symbol but other languages use different ones, e.g. C# uses ?? and Perl uses //