actually that would be a bad idea.
considering you want to handle multiple options at once.
the code would get really messy with flatMap/map
another way would be (now consider more options and it will be way more ugly or considering a list of optional where every optional needs to be present to calculate something):
if (opt1.isPresent() && opt2.isPresent() && opt3.isPresent()) {
int i1 = opt1.get();
int i2 = opt2.get();
int i3 = opt3.get();
}
of course scala has a better way of handling that:
> actually that would be a bad idea. considering you want to handle multiple options at once.
The proposal is to rename the method[0], not to remove it entirely. So the code you're showing would still be possible, only clearer that it's not innocuous (the body relies very very strongly on the conditional)
[0] not sure why adding an override to #orElseThrow to throw a default exception is not on the table
throwing a Exception would actually make the code as horrible as it already was. You would either need a static method that transforms the exception into a runtime exception or you would need a catch block that never occurs
This pattern is nice, but it makes a lot of IDE's shit the bed completely. I'd really love to see a stronger relationship between Optional and Stream. Right now using both together is very ugly and the function name space is super fucked up, where there is an Optional.map and a Stream.map and you could have them nested or chained. I think there is some resolution in JDK9 for the latter issue though.
Yeah actually the most patterns I miss in Java are actually pattern matching and generators. Everything else is actually "fine", I mean the var/val reduce some ugliness but that is just a trivial thing.
Scala has grown organically and has a lot of things that are no longer idiomatic. Wartremover makes Option#get a compile error, and many recommend using it on new codebases.
Having the get() method makes the entire purpose of Optional useless. All it does is make your null-checking code even more verbose. If you need to extract the value, the orElse method should be suitable on all cases. Deprecating get() should be an instant decision, since other than backwards compatibility it has nothing to add to the Optional class. Including it in the first place was as much of a mistake as the null pointer.
With null, the actual error can show up somewhere completely different in your code making it hard to trace where the null value came from. With .get() the errors happens at exactly the point where I told the compiler: "trust me, this isn't empty!" but was wrong.
1. Assume parameters aren't null, and then everything breaks and you fix it.
2. Assume ANY object can be null, and check them all, in every single method, and create correct handling in each case. Basically no one does this.
3. Try to figure out which things can be null or not depending on context. Sometimes you are still wrong, and get NPEs. This is what people actually do.
By defensive programming, do you mean #2? Because that kinda sucks compared to just using Optionals.
Yeah, even when using get() with Optional it's a great way to give semantics to the function that require you to stop for a second. Annotations don't really cut it for most IDEs/Lints.
I do option (2) for every parameter in every non-private method in my Java code. I have a template in my IDE to write the check; all I do is invoke the template, type the variable name, and hit enter. I even document the throw in the javadoc comments. It's not hard, and it's the right thing to do.
Defensive programming in the form of checking all parameters and all return values from library methods for null? Sure, good idea. But then you need a way to distinguish between things that should never be null and things that genuinely might not be present. So Optional is one of the pieces you need to enable this kind of style.
Enums don't have (dynamic) data members, do they? Sometimes you want a representation of e.g. "user's email address, or nothing if they haven't set one". More, you want that often enough that it's worth having a single generic way to represent it rather than having to construct a custom NullObject for each case.
Sometimes, you _know_ that something will be valid. Rust has an unwrap method that does the same as get does, and legitimate uses of it come in cases like this:
use std::net::Ipv4Addr;
fn main() {
let addr: Ipv4Addr = "0.0.0.0".parse().unwrap();
}
Here, I _know_ that the call to `parse()` will always succeed. More verbose handling isn't helpful.
(We almost changed unwrap to assert to make it even more clear, but not everyone agreed that it was more clear)
In this specific case, sure. But it's not really about this specific case; it's about the general idea of "I know that this won't fail, even though you, the compiler, do not." Unless you have full-on dependent types, (and even then), there's going to be times where that's true; it's the nature of type systems. They have to be conservative, there will always be valid programs that are not expressible.
I feel like that's just a special case of casting and so should be handled by casting. You can always cast Optional to Some, can't you? It's verbose and dangerous-looking but it should be verbose and dangerous-looking in my book.
It depends on the language. In a language like Rust, direct casts mean "reinterpret these bits", and the two are represented differently, so that wouldn't work. In a less low-level language, then sure, maybe a cast would work for this case. I'm not sure that it's any more verbose or scary looking, though.
> In a language like Rust, direct casts mean "reinterpret these bits", and the two are represented differently, so that wouldn't work.
What's the representation of an optional then? Doesn't make use of some generic concept like subclasses or unions? Surely you have a generic syntax for "assume this union is this particular member" or "assume this base class is this particular subclass" or the like?
> I'm not sure that it's any more verbose or scary looking, though.
I guess the point is that I want all cast-like operations to look alike (or at least to have a way to consistently distinguish them from ordinary methods) so that I can flag them all up consistently in code reviews, linters etc.
It's a tagged union. Sometimes the tag can be elided, sometimes not. If you did a direct cast, you'd lose the tag. More specifically though, layout is undefined, so you don't know if the tag is first or last, strictly speaking.
> It's a tagged union. Sometimes the tag can be elided, sometimes not. If you did a direct cast, you'd lose the tag. More specifically though, layout is undefined, so you don't know if the tag is first or last, strictly speaking.
Do you not have a generic syntax for unwrapping a tagged union, forcibly assuming that it's one particular component? That seems like something users would want.
Maybe your issue is that the `get` method in Java sounds pretty innocuous, but in Rust the `unwrap` method is notorious. Every Rust user knows that it can panic. Requiring a match would increase verbosity and decrease clarity.
What if we decide that adding IP literals to the language isn't worth the complexity?
In practice, "add a new language feature" isn't a real solution for programmers who need to get the job done. Static type systems always have limitations. You need to be able to circumvent the type system if it isn't expressive enough for your use case.
> Having the get() method makes the entire purpose of Optional useless.
It doesn't quite, though it is way too short and convenient.
> If you need to extract the value, the orElse method should be suitable on all cases.
orElse is incorrect if you have specific expectations. get is an assertion, and used in that manner it's perfectly sensible and orElse is not. Plus orElse can send the wrong signal.
> Including it in the first place was as much of a mistake as the null pointer.
The only language I know which has optionals and doesn't have something equivalent to .get() is Elm, and even there you can trivially pattern-match and call Debug.crash in the Nothing case.
You should never have concrete expectations or make assertions on an unknown, that's the entire point of any implementation of Option.
Option.get leads to false confidence. I've had many arguments over use .get (in Scala) where another developers argument is "we check that it's defined higher up in the code". At that point a harmless looking refactor by someone else can introduce NPEs.
Option.get is important. It lets you work around the type system in cases where the type system wasn't expressive enough. Given that all type systems are imprecise, this functionality is essential.
I'm all for strong type systems, but I also acknowledge their limitations.
If someone has managed to bork the code with a harmless looking refactor, an NPE is what you want. The code is no longer working as designed and needs to be fixed.
I disagree. I'd rather getWhenPresent than orElse if the code has nothing to do with a missing value. If someone needs the value and uses orElse without isPresent, their code will break in new and unexpected ways rather than in the obvious one.
(An even better solution is SWIFT's approach to nullable types, but that boat has sailed; intellij etc could however implement a static checker for bare Optional-getting)
How does orElse() cause new problems and/or break code? It is the same as get but forces you to think about the not available option...?
I think the options orElse/orElseGet and orElseThrow are enough to replace every get() method, and they'll force you to think about the missing scenario.
If you want to do something in case it is present, use ifPresent(lambda).
In case you want to return something, use orElse/orElseGet or orElseThrow, or just return the Optional itself.
> I think the options orElse/orElseGet and orElseThrow are enough to replace every get() method, and they'll force you to think about the missing scenario.
orElseThrow doesn't force you to think about the missing scenario, only to think about which exception you want to throw, which in many case you don't care for.
If orElseThrow had an override throwing NoSuchElementException by default it would be a perfect replacement, alas it does not.
Of course it does, you actively choose to throw something! That is, in some cases, perfectly acceptable. All three methods tell you there is something else in case you don't have a value in the optional. get() doesn't.
Java Optional was inspired by Scala Option was it not? And I haven't seen anyone complain about Scala Option having exactly the same get() method for ages.
It does, but the scala community is very familiar with the functional ("lambda") approach of leaving values in an optional context while transforming it.
The issue here stems from the existing community's culture, one especially full of trivially safe getters.
Well, maybe they need to learn the lesson the hard way, because when they start doing `foo.getBar().map(this::toString).orElse("Bar not found");` they will realize (hopefully) that this looks much more like Scala than classic Java.
The ScalaZ folks use their own Maybe type instead so as not to have a get() method. Wartremover makes Option#get() a compile failure. Where I work "Option#get" is an automatic failure in codereview. For political reasons I doubt it will ever be removed in the Scala standard library, but there is certainly a substantial contingent that objects to it.
I think it has to do with the mindset of people working with Java vs Scala. Specifically, Scala folks are taught to reach for functional concepts(map, flatMap, etc) first whereas these concepts are still new to Java land.
I believe less Scala developers do "IDE-driven-development", where they just briefly look at the auto-complete to find a methods that vaguely appears to do what they want.
You're right, actually -- it's not more readable. Java developers already understand nulls, comparisons, and if statements.
However, the second version is a lot more brittle than the first. It's relatively easy to change the code and still get it to compile, whereas you'll have a lot more trouble doing that with the first. For example:
1. If you forget to check 'order' for null, it'll still compile fine, because null is a valid value for type 'Order'. But if you try to feed an Optional<Order> to OrderEngine, it won't compile.
2. If you forget to check 'result' for null, it'll still compile fine, and then throw an NPE when you run 'result.succeeded()'. Again, if you try to call check ProcessResult::succeeded in the first example, it won't compile unless you deal with the empty-result case specifically.
3. Say that later on you want to get your stored values back out of the database... and you find a null in there. Where did it come from? If you forget to check 'result' for null and don't do the 'succeeded()' check, you can put a null in the database. Then your program will work fine until you try to call a method on it, at which point it throws an NPE far, far away from the point where you store it. By using Optional and dealing with the empty case, your code won't compile if you try to store null in the DB.
So unfortunately it will be less readable until Java devs adjust themselves to using this new type, but the benefits do exist.
I agree but admit it might be down to my lack of experience with functional programming.
Background: many moons ago when I was still in school and VB was a valid choice of programming language I thought I new object oriented programming since my VB skills was decent (for a student) and VB had objects.
I have learned a lot since then and suspect something similar is happening and will happily admit that good stuff can be waiting for me as soon as it "clicks" when I get time to sit down with it or get a colleague who knows it and explain it (or when someone on HN gives me a good explanation : )
I will never use Java's Optional. I'm baffled why it even exists. Further, I remain unclear on the value (haha) of the @Nullable and @NotNull annotations. If it's not baked into the language, why bother?
I've been using NullObject since (checking...) 1996. This is The Correct Answer.
Java's Optional is exactly unlike a NullObject. Optional is not a Proxy. Being untyped, not being an implementation of the interface, it can't be used interchangeably.
It's NullObjects all the way down. Makes more sense when designs favor compositions over inheritance.
Optional is the wrapper no one needed. For syntactic sugar, static library methods worked just fine.
Urgh. Sure that's one option, but I don't want to have to subclass HashMap every time I want to store something different in it. Also sometimes I want generic code that uses a map.
> I remain unclear on the value (haha) of the @Nullable and @NotNull annotations. If it's not baked into the language, why bother?
What's the difference between "baked into the language" and a language with built-in support (added in Java 8) for pluggable, inferrable type systems (of which @NotNull is just one, pretty basic, example)?
In principle and practice, I oppose all use of annotations. It's metaprogramming (aka magic).
Being the new COBOL, Java is best when it just works. Anyone who can use annotations responsibly will be happier choosing a grown up language like Clojure.
In truth, I don't have an answer for why method?method?property syntax is better than using annotations. Because I tend to use NullObjects and avoid method chaining, to me it's a false choice.
> I oppose all use of annotations. It's metaprogramming (aka magic).
Don't conflate annotations (a compile time construct) with how they can be used. They can be used in many ways. When used as runtime metadata they can be "magic". But @Nullable/@NonNull is (or rather, can be used as) one of Java 8's pluggable type systems, inferred and and checked at compile time[1].
So Optional.get() is similar to Rust's Option.unwrap(), right? A method with a short name, which newbies often use just more than they should, and which should only be used when it's a bug if the Optional/Option doesn't contain a valid value at that point?
(I still don't quite get the point of Optional; you're replacing a direct pointer with a pointer to a pointer, but the outermost pointer can still be null, so you are still vulnerable to a NullPointerException, and now you have two "not present" values to check for: null and !isPresent().)
> the outermost pointer can still be null, so you are still vulnerable to a NullPointerException
This is true, but there is a distinction: if your Optional value is null, for any reason, then it's a programming error and should be fixed. If a non-Optional value is null, there's no telling whether it's "allowed" to be null or not. So I never null-check my Optionals in Java -- I'd rather they fail so I can be alerted to them.
Sure, to be sure the type system needs to support non-nullable references. However, even without those, proper use of Optionals means getting a null result becomes an assertable bug in all cases, not a potentially valid code path signalling "not available" that should be checked.
It provides a migration path that allows deprecating null entirely. The next step is to deprecate methods like Map#get in favour of versions that return Optionals, ultimately arriving at a language where null can never happen when doing non-deprecated things. It's a multi-decade project but I don't see any other way to get rid of null while maintaining Java backward compatibility.
The point (or the reason why I use it) is to express the possibility of absent values, same as Rust, Haskell, etc. That the language let's you have null references is another (bigger) problem.
This kind of thing is so frustrating because enormous effort has been put into solving exactly one VARIANT of a pretty general problem. The general case is: at a particular point in the code, is $THIS_DATA usable or not, for some appropriate definition of “usable” in that code?
And if “usable” has any additional meaning besides “is not null”, this entire machinery is useless because one STILL has to figure out the state of the data!
For example, what if you are sanitizing input from a user and there is a “wall” in your code beyond which a string is considered safe (e.g. decoded, evaluated by regex, or whatever is supposed to happen)? Or, what if “usable” means that a server has been connected to, or a database opened, or a calculation completed, or whatever else you want to say? What if it’s a numerical denominator and you want it to be nonzero? The list could go on and on, and none of these architectures deals with ANY of those possibilities.
> And if “usable” has any additional meaning besides “is not null”, this entire machinery is useless because one STILL has to figure out the state of the data!
That's inaccurate. In fact Optional makes this situation (having to check if data is not null and valid) even easier, because you can simply filter/map the value without having to first check that it is non-null. For example:
Love it!! As a Java 7 developer transitioning to Streams this made no sense to me and ended up doing the optional.isPresent() -> optional.get() ...
Took me to learn a pure functional language (Scala) to come back and start using map, filter, etc ... Not because Java 8 doesn't support it, but because a functional language community just has that mindset. There are many Java 8 developers using streams() and optionals with an imperative programming mindset still.
Not sure `getWhenPresent()` is better. Maybe `unsafeGet()`? That's a pattern found a lot on functional structures such as `IO` or `Task`.
There could be a discussion to remove `get` altogether, but I don't think it would be a good idea. I don't use the Java type, but `scala.Option` and I think `get` is occasionally helpful in unit tests, scripts, etc.
Microservices are often basically equivalent with RPC calls. So they have a lot of potential failure modes like service down, network partitioned, timeout, etc.
So each of them has a potential for an unexpected and transient failure that may be returned either via an exception or via a null result.
In my own experience with systems built on top of multiple services (not micro in my case but enough services...) unexpected nulls or incorrectly handled exceptions from transient/network failures in the services depended on is a common mechanism that surfaces bugs in production code.
And these bugs rarely show up in testing unless someone went out of their way to simulate the failure(s). Optionals have been a good way for us to convey that possibility to the calling code and force the consumer to consider the possibility and plan an appropriate response (we're big fans of fail-fast).
Yep! It's the fallout from people that didn't learn the lessons in the great SOA/ESB era :P
I can't remember who said this originally, but it was something like "The first rule of distributing your application is don't." The implication is you should distribute by business concern, not by tech concern.... which could be done with microservices, but it's not how they're being used right now.
It's a balancing act. Where microservices do shine compared to a large "monolith" is during a go-live - way less headache/risk and if shtf way easier to roll everything back. Anyone dealing with large-scale customer-facing systems will appreciate that.