Upgrade to Pro — share decks privately, control downloads, hide ads and more …

[DevoxxPL 2017] The Seven Sins of Optional

[DevoxxPL 2017] The Seven Sins of Optional

Grzegorz Rożniecki

June 22, 2017
Tweet

More Decks by Grzegorz Rożniecki

Other Decks in Programming

Transcript

  1. @xaerxess #DevoxxPL 0. Introduction to Optional „Sigh, why does everything

    related to Optional have to take 300 messages?” – Brian Goetz (2013-10-23 on lambda-libs-spec-experts)
  2. @xaerxess #DevoxxPL 1. Optional => OptionalResult „Where the class is

    useful is in the return position. (…) Simply rename "Optional" to "OptionalResult", or just "Result" and many of the issues go away.” – Stephen Colebourne (2013-06-04 on lambda-dev)
  3. @xaerxess #DevoxxPL 2. get() should be named differently “In retrospect,

    we should have called get something like getOrElseThrowNoSuchElementException or something that made it far clearer that this was a highly dangerous method that undermined the whole purpose of Optional in the first place.” – Brian Goetz (2014-10-12 on SO)
  4. @xaerxess #DevoxxPL 3. get() should be deprecated “So, in the

    context of a deprecation effort, this seems an entirely reasonable candidate. I'd like to see it fixed, and the sooner the better.” – Brian Goetz (2016-04-26 on core-libs-dev)
  5. @xaerxess #DevoxxPL 4. It should be a language feature •

    Kotlin does it right – see reference for Null Safety var a: String = "abc”; a = null // compilation error var b: String? = "abc”; b = null // ok bob?.department?.head?.name val l = b?.length ?: -1 val l = b!!.length val nullableList: List<Int?> = listOf(1, 2, null, 4) val intList: List<Int> = nullableList.filterNotNull()
  6. @xaerxess #DevoxxPL 5. It should be a (true) value type

    “Value type - small immutable, identityless” – John Rose, Brian Goetz, and Guy Steele (State of the Values - April 2014) No support for this yet :( …maybe Java 10.
  7. @xaerxess #DevoxxPL 6. It is not Serializable • Guava’s Optional

    implements Serializable • Granted, implementing Serializable is hard... “Making something in the JDK serializable makes a dramatic increase in our maintenance costs, because it means that the representation is frozen for all time.” – Brian Goetz (2013-09-28 on jdk8-dev)
  8. @xaerxess #DevoxxPL 7. It isn’t useful anywhere • Fields •

    Collections • Parameters • Error handling but…
  9. @xaerxess #DevoxxPL 1. All nulls are Optionals now • „Null

    sucks.” – Doug Lea • „I call it my billion-dollar mistake.” – Tony Hoare Optional.ofNullable(foo).ifPresent(this::doWork); vs if (foo != null) { doWork(foo); }
  10. @xaerxess #DevoxxPL 2. get() == unwrapping null ref • You

    should never be forced to use .get() alone • There are other options: • filter() + map() • flatMap() • orElse(V) / orElseGet(Supplier<V> / orElseThrow(Supplier<T>) getMyOptionalResult().get(); vs getMyOptionalResult().orElseThrow(IllegalStateException::new);
  11. @xaerxess #DevoxxPL 3. Using only a subset of API •

    There’s more than just .get() and .isPresent()… • …so you should be able to avoid them… • …unless you’re not on Java 9: final Optional<User> userOptional = userRepository.findById(userId); if (userOptional.isPresent()) { doWork(userOptional.get()); } else { LOG.error("User ID {} not found!", userId); }
  12. @xaerxess #DevoxxPL 3. Using only a subset of API •

    There’s more than just .get() and .isPresent()… • …so you should be able to avoid them… • …unless you’re not on Java 9: userRepository.findById(userId).ifPresentOrElse( this::doWork, () -> LOG.error("User ID {} not found!", userId));
  13. @xaerxess #DevoxxPL 3. Using only a subset of API •

    More coming in JDK9: List<User> users = ids.stream() .map(userRepository::findById) .filter(Optional::isPresent) .map(Optional::get) .collect(Collectors.toList()); vs List<User> users = ids.stream() .map(userRepository::findById) .flatMap(Optional::stream) .collect(Collectors.toList());
  14. @xaerxess #DevoxxPL 4. Using Optional as preconditions • Remember, Optional

    is a boxed type • It should be used as result Optional.ofNullable(foo) .orElseThrow(IllegalArgumentException::new); vs checkNotNull(foo);
  15. @xaerxess #DevoxxPL 5. Optional combos • Nesting Optionals and comboing

    combining Optionals of Optionals… Optional<BigDecimal> result = first.map(b -> second.map(b::add).orElse(b)) .map(Optional::of) .orElse(second); vs Optional<BigDecimal> result; if (!first.isPresent() && !second.isPresent()) { result = Optional.empty(); } else { result = Optional.of(first.orElse(ZERO).add(second.orElse(ZERO))); }
  16. @xaerxess #DevoxxPL 6. Using Optional in fields, params • Remember,

    Optional is a return type • It’s not Serializable by design! • Guava version is, but it was a design mistake „The intent is that the caller immediately check the Optional and extract the actual value if it's present.” – Stuart Marks (2014-07-03 on SO)
  17. @xaerxess #DevoxxPL 6. Using Optional in fields, params private final

    Optional<String> foo; public Optional<String> getFoo() { return foo; } vs private final @Nullable String foo; public Optional<String> getFoo() { return Optional.ofNullable(foo); }
  18. @xaerxess #DevoxxPL 7. Using Optional in collections „Meanwhile I continue

    to fear Map<Optional<List<Optional<String>>> and the like. The generics type system in Java simply isn't good enough to be doing anything like that, even if it were remotely desirable.” – Stephen Colebourne (2013-06-04 on lambda-dev)
  19. @xaerxess #DevoxxPL Bonus – javadoc changes in JDK9 “Optional is

    primarily intended for use as a method return type where there is a clear need to represent "no result," and where using null is likely to cause errors. A variable whose type is Optional should never itself be null; it should always point to an Optional instance.” – Optional javadoc
  20. @xaerxess #DevoxxPL Bonus – javadoc changes in JDK9 “The methods

    orElse and orElseGet are generally preferable to this method, as they return a substitute value if the value is absent, instead of throwing an exception.” – Optional#get() javadoc
  21. @xaerxess #DevoxxPL Bonus – Try monad • Like Optional, but

    for either result or an exception • Similar API but semantically different (right tool for the right job)
  22. @xaerxess #DevoxxPL • “Optional: The Mother of All Bikesheds” by

    Stuart Marks • “The Design of Optional” by Nicolai Parlog • “Why Isn’t Optional Serializable?” by Nicolai Parlog • ”State of the Values” by John Rose, Brian Goetz, and Guy Steele • JDK mailing lists Resources