<a href="https://www.buymeacoffee.com/eduardoeljaiek" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-blue.png" alt="Buy Me A Coffee" style="height: 35px !important;width: 125px !important;" ></a> *** > Optional - The Mother of all [[What Bikeshedding is | Bikesheds]]. ~ Stuart Marks ### What is Optional meant for? >Optional is intended to provide a **limited mechanism for library method return types where there is a clear need to represent "no result", and where using null for that is overwhelmingly to cause errors**. >\~ Optional Javadoc That's the main reason **I use Optional in my projects, to represent "no result" in my public APIs** or components that will be consumed outside the package they belong. > [!WARNING] Remember, Optional is a box! > - It is a separate object, **consumes 4x memory** of a bare reference. > - Potentially adds [[What GC pressure is | GC pressure]]. > - Always requires a dependent load, leading to cache misses. > - Could turn into a performance/space problem if used frequently. > > \~ Stuart Marks > [!INFO] Don't replace every null with an Optional > - [[Java - Null can be safe, if it is well controlled| null can be safe, if it's well controlled]] > - `null` in private field can be easily checked > - nullable parameters are ok (if [déclassé](https://www.merriam-webster.com/dictionary/d%C3%A9class%C3%A9)) > - library code should take responsibility for checking args > > ~ Stuart Marks > [!HINT] Technique: unit testing a method that returns Optional > > ```java > assertEquals(Optional.of("expected value"), optionalReturningMethod()); > assertEquals(Optional.empty(), optionalReturningMethod()); >``` >~ Stuart Marks ### Rules **Rule 1:** Never, ever, use `null` for an `Optional` variable or return value. **Rule 2:** Never use `Optional.get()` unless you can prove that the `Optional` is present. **Rule 3:** Prefer alternatives to `Optional.isPresent()` and `Optional.get()`. ![[optional-rule2-3.png]] **Rule 4:** It's generally a bad idea to create an `Optional` for the specific purpose of chaining methods from it to get a value. ```java // BAD return Optional.ofNullable(s).orElseGet(this::getDefault); // GOOD return (s != null) ? s : getDefault() return Objects.requireNonNullElseGet(s, this::getDefault); ``` **Rule 5:** If an `Optional` chain is nested or has an intermediate result of `Optional<Optional<T>>`, it's probably too complex. ```java Optional<BigDecimal> first = getFirstValue(); Optional<BigDecimal> second = getSecondValue(); // Add first and second, treating empty as zero, returning an Optional of the sum, // unless BOTH are empty, in which case return an empty `Optional`. // Clever, and allows any number of Optionals to be combined. // OK, BUT COULD BE BETTER Optional<BigDecimal> result = Stream.of(first, second) .filter(Optional::isPresent) .map(Optional::get) .reduce(BigDecimal::add); // Even more clever! // Exercise: verify this is correct. Optional<BigDecimal> result = first.map(b -> second.map(b::add).orElse(b)) // NOT RECOMMENDED .map(Optional::of) .orElse(second); // Not the shortest, or cleverest, but is it the clearest ? if (first.isEmpty() && second.isEmpty()) { result = Optional.empty(); } else { result = Optional.of(first.orElse(ZERO).add(second.orElse(ZERO))); } ``` **Rule 6**: Avoid using Optional in fields, method parameters, and collections. ![[optional-rule6.png]] ![[optional-rule6-2.png]] **Rule 7:** Avoid using identity-sensitive operations on Optionals. ![[optional-rule7.png]] ![[optional-rule7-2.png]] *** **References**: - [Optional by Stuart Marks](https://www.youtube.com/watch?v=fBYhtvY19xA&list=WL&index=100) - [Java SE 8 Optional, a pragmatic approach](https://blog.joda.org/2015/08/java-se-8-optional-pragmatic-approach.html) - [Java 8 SE Optional, a strict approach](https://nipafx.dev/stephen-colebourne-java-optional-strict-approach/) - [Nothing is better than the Optional type](https://homes.cs.washington.edu/~mernst/advice/nothing-is-better-than-optional.html) - [Optional Javadoc](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Optional.html)