7 ms·
A better (than Optional) maybe for Java
- rubenvanwyk 2y agoOr... Just use Kotlin?
- gf000 2y agoWhich has worse no real pattern matching like Java has?
- rhdunn 2y agoI'd like Java to add support for the null coalescing operator `?.` and associated `!.` and `?:`. -- I find this easier to use and read than using Optional or null check code. I find heavy use of Optionals for nullable values can quickly overwhelm the codebase and make it hard to read the control flow. Especially when interacting with other parts of the codebase. E.g. var baz = foo?.bar?.baz ?: return false; vs something like: var baz = foo.map(f => f.bar).map(b => b.baz).getOrElse(null); or using `then`.
- dehrmann 2y ago> The exception that is raised when an empty Maybe is used is a checked exception so you don't forget to handle it. I think they acknowledged get() should have been getOrThrow() so it's clear what can happen, but I don't know if making it checked is an improvement. > It implements the Collection interface, so it can be accessed with a for-loop. I'm curious what the use cases are for this. I've used Optional, it can be annoying, it's mostly around it being verbose and APIs being inconsistent. It was never wishing I could treat it as a collection.
- kelseyfrog 2y agoI'd imagine it's a poor-man's do notation. When it comes to structured programming, languages without a do syntax are considered incomplete. It's like programming without ifs.
- AtlasBarfed 2y agoFro what language? Is that like groovy with?
- eru 2y agoDo-notation is a thing in eg Haskell.
- hackingonempty 2y agoLike Scala's for-comprehension.
- porridgeraisin 2y agoYeah I don't get the iterator thing either... Saw the implementation and I'm not sure what the usecase would be. They have essentially implement a single element iterator for Some and a zero element iterator for None.
- ai_ 2y agoIt's useful for combinators, like flatMap. For instance if you want to flatten an iterator of optional values into the values of all some elements.
- dehrmann 2y agoIs it worth using a custom library so you can do .flatMap(Maybe::stream) instead of .filter(Optional::isPresent).map(Optional::get)
- sedro 2y agoIt's useful and very common to use. For example, you could concatenate together command-line argument flags that may or may not be present.
- blastonico 2y ago> The method names are more intuitive: e.g., then instead of map But map makes total sense, considering that maybe is a monad.
- voidhorse 2y agoTrue, but I would not be surprised if the vast majority of Java programmers have no clue what a monad is.
- deleted 2y ago[deleted]
- chii 2y ago> no clue what a monad is. which is a good opportunity to introduce said nomenclature, and ideas to them, rather than renaming said method to something more "palatable".
- Dansvidania 2y agoIn my experience just name-dropping monads in non functional-programming oriented circles will get weird looks. EDIT: I would even argue, as a fan of FP, that it's not immediately obvious how this terminology or concept even helps, from the point of view of a non purely functional programming language
- mrkeen 2y agoBecause the alternative to using one name is using more than one name. These days I'm pretty sure I'm using `select` to mean `map`.
- xigoi 2y agoYou don’t need to mention monads, just imagine an Optional as a list with at most one element.
- edflsafoiewq 2y ago
- stickfigure 2y ago`map()` makes Optional congruent with java Streams. Optionals are very frequently used with Streams, eg: someList.stream().map(Thing::foo).findFirst().map(Other::bar)... And checked exceptions are a scourge. There's a reason post-Java languages like C#, Scala, and Kotlin abandoned them. Even lombok offers @SneakyThrows. The Java Optional<?> is pretty good as-is. The main improvement I'm make is that it needs to be Serializable. And woven into the core collection classes.
- crummy 2y agoWhy do you want Optional to implement Serializable?
- Timwi 2y agoTo make it able to be serialized?... Am I missing something?
- evidencetamper 2y agoYou don't need your optional to be serialized - it's just a container. You need what's inside your optional to be serialized.
- crummy 2y agoMost of the serialization libraries I use (Jackson, gson) ignore the Serialization interface. I think it's only used for Java's now-rarely-used native serialization functionality.
- lucumo 2y agoOnly Java's built-in serialization still requires Serializable. And Java's built-in serialization is fundamentally vulnerable and should never be used. Newer libraries dropped the need for Serializable, because whether or not an object is serializable is not just dependent on its class, but also on the features the serialization library supports.
- 2y ago
- stemlaur 2y agoI would make the abstract class "Maybe" a sealed class with None and Some being the only permitted implementation So that clients can use pattern matching (enhanced switch)
- Hackbraten 2y agoVery good point.
- Blackarea 2y agoChecked exception in a Optional.get is really the worst idea that you could possibly come up with. Have a look at vavr (https://github.com/vavr-io/vavr https://github.com/vavr-io/vavr) They did a fantastic job and the DX is so much better than anything java std has to offer. They have immutable equivalents for pretty much any java util data structure as well as either try option etc. To me the one lib that makes java actually feel fresh.
- gylterud 2y agoVavr is nice! But I understand the want to make the get exception checked. It makes it so that you can use try/catch as a Java-man’s do-notation, and not fear having forgotten to deal with the None case. You can then make lots of utility functions which all get without handling it (only declare that they throw) and then you compose these into larger functions which make sure to catch at the end. Having to declare it makes it really clear what the function actually does.
- Blackarea 2y agoCan you provide an example. I just don't see it tbh. Especially since closures in java really don't work with checked exceptions at all. That's why vavr avoids it at all costs. Eg: ```java assertEquals( Vector.of(1, 3), Vector.of(Some(1), None(), Some(3)) .filter(Option::isDefined) .map(Option::get) ); ``` If `Option.get` was throwing a checked you'd always have to wrap it in try-catch. I understand that this is a break with the type system (meaning it is not strong typed Maybe/Option in that sense). But otherwise you'd be worse of than with stupid null checks IMO.
- _kidlike 2y ago`then` is definitely less intuitive than `map` considering that you actually want to, well, map to something else. Semantically, `then` would be equivalent to `ifPresent`, but, well, then both are intuitive.
- funcDropShadow 2y agoNothing is intuitive on its own. Intuitiveness is a property of the relation between a thing and and some subject. Whether `map` is more intuitive than `then` depends on that subject. Without assuming a target audience, it is futile to design a library to be intuitive. Intuitive is that, for which we already have built an intuition.
- ljlolel 2y agoIn UX, there is nothing intuitive, only familiar Although have you seen that video of a chimpanzee browsing Instagram? Or a parrot using zoom?
- occz 2y agoThe real improvement is to lift nullability up to the type system. That way, every type acts as an optional by default, and the computer can infer when a nullable type has been null-checked. This is what Kotlin does - it's truly freeing to work with.
- ajkjk 2y ago"the real fix is to move from the stone age to the iron age" ...suffice it to say, there are even better ages
- occz 2y agoI don't know, I think Kotlin strikes a pretty good balance as far as languages go. What's your preference over it?
- ajkjk 2y agooh I think it's fine. I just find it a bit odd to be saying "the thing we should have from our type system is that it's a type system, it's truly freeing to work with". Like... yeah of course we should but it's a bit sad that we're getting exciting over basic functionality like that in 2025.
- DarkNova6 2y agoThey are slowly getting there. See the JEP draft: Null-Restricted Value Class Types (Preview) Source: https://openjdk.org/jeps/8316779 https://openjdk.org/jeps/8316779 But it is already possible today using the Spring annoation "NonNullApi" on a package level. Then, you can allow nullable fields via @Nullable. It's not perfectly elegant, but it works surprisingly well.
- pjmlp 2y agoUsually I have bigger fish to fry in enterprise projects than a couple of NullReferenceExceptions. What would be truly freeing is getting the right set of folks on the projects.
- ivan_gammel 2y agoInteresting attempt, however: 1. There was no need to implement Set interface to support foreach loop. Iterable would be sufficient. Set is too specific and is not an obvious choice (for return type interoperability in subclasses sometimes it would be more convenient to have List). 2. Moving from isPresent/get to try/catch checked exception will produce worse result. Either you wrap ‘get’ immediately and get more verbose code, or you catch somewhere else and loose the context and readability. In “throws Exception” methods absence of stack trace will be painful. 3. Renaming ‘map’ to ‘then’ is too late. “Then” was used in functional style libraries more than 15 years ago, Java 8 settled the naming convention and it’s better to follow it. 4. What Optional is often missing is the context of empty state. It would be cool to have an implementation of None with a Throwable cause (and orElseThrow throwing it wrapped).
- derriz 2y agoI really dislike the use of exceptions - particularly checked exceptions - to handle control flow for things like this. I mean, it's not EXCEPTIONAL to have an empty Optional, right? Their use here is an anti-pattern to my eye. Java (the language) should just drop the notion of checked exceptions. It would be fully backward compatible as the checked/unchecked distinction is a language feature not a JVM one. They simply don't work with Stream and cause abstraction leaks everywhere (e.g. you have to handle IOExpection for operations on StringWriter). It obfuscates flow control. Anyway the problem with Optional is not going to be fixed by renaming API methods and fiddling like this (sorry to be harsh). The reason Optional is broken is because there is so much legacy APIs which use null to represent "no result" and until all of these APIs are changed/deprecated, then Optional will never be a very useful tool. As others have commented, the correct solution would be to ditch Optional completely along with the mass of flavors of @Nullable, @NotNull, etc that everyone uses along with having to use package_info.java everywhere and just make "nullability" part of the type system. Kotlin got it right here. But it would be a breaking change in Java to make not-nullable the default. They could do it the opposite way to Kotlin - add a marker for "not-nullable" instead of one for "nullable" - e.g. "String!" would be a not-nullable String instead of say "String?" representing a nullable string.
- ivan_gammel 2y ago> the correct solution would be to ditch Optional completely along with the mass of flavors of @Nullable, @NotNull How would you suggest to implement Stream::findAny without Optional?
- derriz 2y agoUsing my suggestion, the signature would simply be "T findAny();" - while "T!" would represent non-nullable T. So the opposite of the Kotlin/Typescript/etc. way where the default is not-nullable and you'd have something like "T? findAny();". It would be a language level change and would require language level syntax extensions to provide mappings between T and T!. Like how we're used to having to add "final" to most variable declarations, you'd add "!" to a class type indicate not-null. Contra-variance would allow you to add ! to return values without breaking interface compatibility so you could migrate your code base in steps. Actually to be honest I'm just throwing this idea out there, I haven't given it deep thought. Without language level support, Optional is a broken design. You've just multiplied the state space: the Optional instance can be null, the Optional instance can be not-null but empty, the Optional instance can be not-null and non-empty but the content is null and finally the Optional instance can be not-null and non-empty and the contained value can be non-null. Java's type system doesn't distinguish.
- DarkNova6 2y agoI really hate the inclusion of a "FastException" and "UnsafeUtils" class. Many developers will consistently make the wrong choice thinking their complex (but cold) execution path needs to be extra sleek and fast. But the reckoning comes during debugging (most likely by somebody else) where you have extra levels of indirection and non-expected violations of typically default behavior.
- dfe 2y agoThis seems to be worse in every way to Optional. The throwing of a checked exception is ludicrous. It's a classic case of abusing checked exceptions for flow control. The right approach is an isPresent() or isEmpty() call followed by a get() when you know it's present. Static analysis can ensure you don't screw this up. Similarly, using then and thenMaybe instead of map and flatMap means it now has its own terminology different from Stream. Being able to iterate it is dubious. You can already .stream() an Optional (to an empty or 1-element stream). You can also if (o.isPresent()) { o.get(); } which is hardly burdensome. I'm trying to figure out how a for-each loop is an improvement. But if you must: o.map(Collections::singleton).orElse(Collections.empty()). Or o.stream().toList(). I applaud the author for experimenting with different API designs, but this one is just not good. It causes more trouble than it solves.