6 ms·
My Java code has improve dramatically since I started (ab)using Optionals. String foo = Optional.ofNullable(paramater) .filter(...)
by mabbo 11y ago
My Java code has improve dramatically since I started (ab)using Optionals.
String foo = Optional.ofNullable(paramater)
.filter(...)
.map(a -> ...)
.map(b -> ...)
.orElseGet(() -> ...)
.orElse(defaultValue)
Between this kind of thing, and similar playing with Streams, some of the ugliest code I work with is suddenly quite clear, coherent, understandable.
- grokys 11y agoI'm not so up on Java, could someone explain why they chose "->" for lambdas instead of the "=>" that C# and ES6 use, as those languages seem to me like they would be the first place to look for inspiration.
- LoneWolf 11y agoWhile I don't know the reason i like it because for me is easier to type -> than => (portuguese keyboard, TBH dont know the difference from english)
- Glide 11y agoThe - and = are right next to each other on an English keyboard.
- WaxProlix 11y agoAFAIK that's actually non-standard. Haskell and (more importantly, maybe) C++11 use the single-line arrow (->), as do Erlang and various ML dialects (interestingly, F# uses the single-line notation, too, while C# does not). Probably other languages as well.
- kodablah 11y agoIn addition to the other answers, I bet it's easier for a CFG to parse knowing that "->" can't also be "negate and greater than" (since negation is only a prefix op) whereas "=>" can easily be a fat arrow or greater-than-or-equal.
- serge2k 11y agoWhy would that be any harder? The tokens are different.
- kodablah 11y agoTrue, Java does not support => as an alternative for >= so the ambiguity does not exist. It was just a guess, but since it was probably not right, I decided to dig. This mail post[1] explains that the extra equals sign becomes a bit annoying w/ other equal signs in the same expression. 1 - http://mail.openjdk.java.net/pipermail/lambda-dev/2011-September/004021.html http://mail.openjdk.java.net/pipermail/lambda-dev/2011-Septe...
- bigtunacan 11y agoI have no idea why Java chose that, but thought it worth mentioning "->" has been in use for Ruby longer than the alternative .NET and ES6 syntax.
- tajen 11y agoI'm not an expert. C++ uses -> for pointer dereference, e.g. o->p refers to the property "p" of object "o". I would assume C# inherits from C++ and had to define another operator. Java probably followed Scala's notation, which is probably derived from mathematics where ↦ is an application (a function) and ⇒ is a simple logical implication.
- incepted 11y agoActually Scala uses =>, so Java went the opposite way. Kotlin also uses ->. Doesn't matter much in the long run, you'll get used to whichever your language favors after just a few days or writing code in it.
- leothekim 11y agoHear hear. A couple more features that'd be nice: - An `public Optional<T> or(Optional<T> other)` so if optA is empty, then `optA.or(optB)` would return `optB` - A `toStream` method on `Optional` (I believe this is coming in Java 9) or have a `Stream.flatMap` signature that flattens `Optional`s without needing to call `Optional.toStream` (Scala does this, arguable if this is an acceptable munge of Monadic types, but it's really convenient)
- wsh91 11y agoCheck out fugue: https://bitbucket.org/atlassian/fugue https://bitbucket.org/atlassian/fugue -- a proper monadic Option and more. :) (Full disclosure: I'm an Atlassian and I know/<3 the people who write it, but I also use it a fuckton in my own code.)
- GeneTT 11y agoYea this library with Java 8 makes functional style java actually kinda nice. The addition of an Either really opens up what you can do.
- the8472 11y agoComing in java 9: http://download.java.net/jdk9/docs/api/java/util/Optional.html http://download.java.net/jdk9/docs/api/java/util/Optional.ht...
- kodablah 11y agoI believe this use is a real overuse and is definitely abusing. Sure, use optional as a return type when clarity is needed, but otherwise don't do all of this when you could use a simple conditional ala: String foo = defaultValue; if (parameter != null && ...) { foo = doAAndB(parameter); }
- mabbo 11y agoDoes that really look better to you? More understandable? Methods with the word "and" in them are really awful smells to me too. Comparing your code and mine, I ask you this: which one do you thing is more maintainable after 5 years of edits? Each time a new developer needs to add a new case, a new rule, a new whatever, on my Optional (ab)usage, they just add a new line in the appropriate spot, a .filter or a .map or whatever. In yours it's far less clear. Optional, for me, is wonderful because it lets me have a single return statement. A lot of the code in Java I'm replacing with this pattern is the stuff that has 5 different returns after checks. Crusty old stuff, but the business logic it's running has grown the way it has for good reasons.
- kodablah 11y agoJava does not have a full FP story, so to bastardize newer code as though it does becomes unreadable IMO. The "and" was just for the example, since "..." wouldn't have made it clear. I do not find it more readable personally, but that is a personal opinion. Because other code eagerly returns (doesn't usually bother me in an imperative language) is a different problem with code path complexity that can be addressed elsewhere. There is still a practicality in normal conditionals and traditional linear paths.
- mabbo 11y agoI don't disagree that FP doesn't feel complete in Java yet. But that doesn't mean I'm not totally willing to start playing with what I've got! The biggest worry I have right now is the story on debugging code with Optional bastardized FP. I know I'm going to learn some lessons soon enough, lol.
- malcolmgreaves 11y agoWelcome to the world of functional programming =D. I personally (and professionally) suggest moving toward Scala when you feel that itch to dig deeper into FP.
- incepted 11y agoUgh, no. Skip Scala, which is on the decline and headed fast toward obsolescence, and pick a post-Scala language such as Kotlin or Ceylon.
- Nyetan 11y agoCould you point an interested reader towards some stats :) ? I wanted to pick up Frege for a hobby project some weekend soon and would love to read more about the JVM up-and-comers.
- lmm 11y agoScala is not in decline - as far as I can see it's on the up and up. Scala has its share of warts but that comes with maturity - I would lay money that Kotlin won't look so nice when it's gone through a similar amount of change. Ceylon OTOH is at least good design, though I don't think that outweighs the library and tool ecosystem that Scala has.
- malcolmgreaves 11y agoDefinitely not true. Scala is at its strongest ever. It's now possible to write frontends, backends, and mobile applications in Scala. There's an incredibly diverse and growing ecosystem of libraries. The Scala tooling has really stepped up. The fact that there's so much discussion on the new SIP (Scala improvement process) and SLIP (Scala library improvement process) issues is a testament that Scala is alive and well. This is what happens in a mature language: many people put stakes in the ground. Also, Scala most certainly has a bright future to go with its vibrant present. EPFL is hard at work with dotty, which will be a simplification and improvement of Scala.
- MrBra 11y agoNo, I'll pick the next next one.
- guard-of-terra 11y agoTwo .map-s one after another is code smell (and also a bit slow). Why not combine them into one? Do standard collections have groupBy? You can go a long way with groupBy and zipWith operations, which are a pair like map-reduce but for in-memory handling.
- RandomBK 11y agoIt might be simplified this this example, but if the mapping function is a method reference or some other reusable lambda, then it can be clearer to use consecutive .map-s
- wtetzner 11y ago>Two .map-s one after another is code smell (and also a bit slow). Why not combine them into one? I believe they are automatically combined before the results of the stream are forced.
- mabbo 11y agoWhy two .map operations? Three reasons. #1- If I'm dealing with some legacy code that I don't know well, and it's mapping from one object to a property of it that is another object... well, I'm not 100% certain it's not null. .map(a -> a.getB()) .map(b -> b.getC()) if a.getB() is null, Optional eats it and I'm safe from NPE- I just an a non present Optional value. .map(a -> a.getB().getC()) If B is null, I'm going to NPE here (... right? I'm like 99% sure of that, but correct me please). And there are counter arguments like "never be null", etc, but I've got legacy code to cleanup, and no one taught the person who wrote it that particular lesson. #2- Ease of understanding. Little jumps rather than big ones. Makes the code easier to understand for the next guy who has to work on it. As much as I can, I try to write code that requires no commenting- because it's so clean it's not needed. #3- The compiler will (or will eventually) optimize it into a single map anyways. Compilers are smart and keep getting smarter. So long as my big-O runtime is fine, I just focus on ease of understanding of my code.
- norswap 11y agoTwo things. First, why is it better than: String foo; if (parameter != null) { foo = ... ; } else { foo = defaultValue; } or even this, if you express all your transformations as a single expression: String foo = parameter != null ? ... : defaultValue I don't get it. Your way of doing seem awfully more verbose. Please note that I'm not against Optional in general (although they are overplayed in my opinion). Second thing, I can't shake off the feeling of inefficiency: building these closures up, calling them. Lots of indirection for something that's probably very simple. I wouldn't want to call this code in a hot loop. But then maybe it's not in a hot loop. Before you bring that up, the sufficiently smart (JIT) compiler doesn't exist. "Sometimes suprisingly dumb" is a better qualifier for many compilers. Note that I work with Java, and use the Java 8 features a lot. I just think this isn't a really good example.
- incepted 11y agoActually, your way is awfully more verbose, but you didn't notice it because you ellipsized the verbosity. If you actually take the time to translate OP's code with your own, you will soon find yourself indented six levels with "if (a != null) { ... if (b != null) { ... if (c != null) {... You get the idea. Monads (the type class that Optional belongs to) flatten all this boiler plate with a function called... flatMap! And you don't even need to know about it, all you need to do is chain the calls like OP did: Optional.ofNullable(paramater) .filter(...) .map(a -> ...) .map(b -> ...) .orElseGet(() -> ...) .orElse(defaultValue) without having to check against null every step along the way.
- norswap 11y agoPoint taken. I'll tentatively argue if all your functions can return null you have other problems to contend with, but what you said makes sense.