$30 off During Our Annual Pro Sale. View Details »

Fixing a billion dollar mistake

Fixing a billion dollar mistake

A presentation regarding so called "Billion Dollar Mistake", which is introducing of Null Reference. Presentation covers different ways of handling that problem in Java and JVM projects. Talk was presented during Quality Meetup #15 in Katowice, Poland.

Piotr Wittchen

February 08, 2018
Tweet

More Decks by Piotr Wittchen

Other Decks in Programming

Transcript

  1. What could happen if we pass null to our method?

    public void processData(String data) { data.contains("foo"); } processData(null); NullPointerException 7
  2. Null-checks in application code public void processData(String data) { if(data

    != null) { data.contains("foo"); } } processData(null); 8
  3. Null-checks in library API public void processData(String data) { if(data

    == null) { throw new NullPointerException("data is null!"); } data.contains("foo"); } 9
  4. Objects.requireNonNull(...) method introduced in Java 7 public void processData(String data)

    { Objects.requireNonNull(data, "data cannot be null"); data.contains("foo"); } 10
  5. Dealing with collections public List<Integer> createList() { List<Integer> list =

    new ArrayList<>(); ... if(canReturnList) { return list; } return null; } 14
  6. Dealing with collections public List<Integer> createList() { List<Integer> list =

    new ArrayList<>(); ... if(canReturnList) { return list; } return list; } 15
  7. Dealing with collections public List<Integer> createList() { List<Integer> list =

    new ArrayList<>(); ... if(canReturnList) { return list; } return new ArrayList<>(); } 16
  8. Null Object Pattern interface NullableObject { boolean isNull(); Object getObject();

    } class RealObject implements NullableObject { @Override public boolean isNull() { return false; } @Override public Object getObject() { return new Object(); } } 17
  9. Null Object Pattern interface NullableObject { boolean isNull(); Object getObject();

    } class NullObject implements NullableObject { @Override public boolean isNull() { return true; } @Override public Object getObject() { return null; } } 18
  10. Optional type in Guava final Optional<Object> optional = Optional.of(new Object());

    if (optional.isPresent()) { Object notNull = optional.get(); } 20
  11. Optional type in Guava final Optional<Object> optional = Optional.absent(); final

    boolean isPresent = optional.isPresent(); assertThat(isPresent).isFalse(); 21
  12. Optional type in Guava final Optional<Object> optional = Optional.fromNullable(null); final

    boolean isPresent = optional.isPresent(); assertThat(isPresent).isFalse(); https://github.com/google/guava/wiki/UsingAndAvoidingNullExplained 22
  13. Optional type in Java 8 Optional<Object> optional = Optional.of(new Object());

    if (optional.isPresent()) { Object notNull = optional.get(); } This example is the same as Guava Optional 23
  14. Optional type in Java 8 Optional<Object> optional = Optional.empty(); Object

    returnedValue = optional.orElse(StringUtils.EMPTY); assertThat(returnedValue).isInstanceOf(String.class); 24
  15. Optional type in Java 8 Optional<Object> optional = Optional.of(new Object());

    optional.ifPresent(object -> assertThat(object).isNotNull()); 25
  16. Optional type in Java 8 final Optional<Object> optional = Optional.of(new

    Object()); final String value = optional .map(o -> o.toString()) .orElse(StringUtils.EMPTY); 26
  17. Enhancements of Optional type in Java 9 final Optional<Object> optional

    = Optional.of(new Object()); optional.ifPresentOrElse(object -> assertThat(object).isNotNull(), Assert::fail); 27
  18. Enhancements of Optional type in Java 9 final Optional<Object> optional

    = Optional.empty(); Optional<Object> newValue = optional.or(() -> Optional.of(new Object())); assertThat(newValue.isPresent()).isTrue(); 28
  19. Enhancements of Optional type in Java 9 List<Optional<Object>> optionals; optionals

    .stream() .flatMap(Optional::stream) .collect(Collectors.toList()); 29
  20. We have even better Option (in Vavr) Option<Object> option =

    Option.of(new Object()); boolean defined = option.isDefined(); assertThat(defined).isTrue(); 30
  21. We have even better Option (in Vavr) Option<Object> option =

    Option.none(); boolean defined = option.isDefined(); assertThat(defined).isFalse(); 31
  22. We have even better Option (in Vavr) Option<Object> option =

    Option.of(null); boolean defined = option.isDefined(); assertThat(defined).isFalse(); 32 // and no exception is thrown here!
  23. We have even better Option (in Vavr) Option<Object> option =

    Option.of(new Object()); Object returnedValue = option.getOrElse(() -> StringUtils.EMPTY); 33
  24. We have even better Option (in Vavr) final Option<Object> option

    = Option.of(new Object()); option.forEach(object -> { if (option.isDefined()) { // handle object here } else { // object does not exist } }); 34
  25. We have even better Option (in Vavr) final Option<Object> option

    = Option.of(new Object()); option .peek(object -> /* handle object here*/) .onEmpty(() -> /* object does not exist*/); 35
  26. We have even better Option (in Vavr) private Object getObject()

    { throw new NullPointerException("Surprise! There's no Object!"); } final Object object = Try .of(this::getObject) .toOption() .getOrElse(new Object()); assertThat(object).isNotNull(); // and no exception is thrown here! 36
  27. We have even better Option (in Vavr) Option<String> option =

    Option.of("my string"); String result = Match(option).of( Case($Some($()), String::toUpperCase), Case($None(), () -> StringUtils.EMPTY) ); assertThat(result).isEqualTo("MY STRING"); 37
  28. Option type and Vavr References: • http://www.vavr.io • http://www.vavr.io/vavr-docs/#_option •

    https://softwaremill.com/do-we-have-better-option-here • https://dev.to/koenighotze/in-praise-of-vavrs-option 38
  29. Optional won’t save us from NPEs Optional<Object> optional = Optional.of(new

    Object()); ... 39 NullPointerException optional = null; optional.isPresent();
  30. Let’s talk about immutability Object object = new Object(); object

    = null; object.toString(); 40 NullPointerException!
  31. Let’s talk about immutability final Object object = new Object();

    object = null; object.toString(); 41 Error: java: cannot assign a value to final variable object
  32. Let’s talk about immutability final Object object = new Object();

    object = null; object.toString(); 42 Error: java: cannot assign a value to final variable object
  33. Let’s talk about immutability final Object object = new Object();

    object = null; object.toString(); 43 Error: java: cannot assign a value to final variable object
  34. Let’s talk about immutability final Object object = new Object();

    object = null; object.toString(); 44 Error: java: cannot assign a value to final variable object
  35. Let’s talk about immutability final Object object = new Object();

    object.toString(); 45 Don’t modify the state of the data if you don’t have to
  36. Null safety in Kotlin value.getObject() // IntelliJ will highlight this

    as an error if there could be NPE! if (value != null) { // null-check value.getObject() } value?.getObject() // safe call val l: Int = if (b != null) b.length else -1 val l = b?.length ?: -1; // Elvis operator value!!.getObject() // unsafe call - can produce NPE! 46 https://kotlinlang.org/docs/reference/null-safety.html
  37. Maybe type in RxJava Maybe<Object> maybe = createMaybe(); maybe .subscribeOn(Schedulers.io())

    .subscribe(object -> System.out.println(object.toString())); 48
  38. Maybe type in RxJava Maybe<Object> maybe = createMaybe(); maybe .subscribeOn(Schedulers.io())

    .subscribe(new MaybeObserver<Object>() { @Override public void onSubscribe(Disposable d) { } @Override public void onSuccess(Object o) { } @Override public void onError(Throwable e) { } @Override public void onComplete() { } }); 49
  39. Error Prone Error Prone is a static analysis tool for

    Java developed at Google that catches common programming mistakes at compile-time. https://github.com/google/error-prone 51
  40. Null Away NullAway is a tool developed at Uber built

    as an Error Prone plugin to help eliminate NullPointerExceptions (NPEs) in your Java code. https://github.com/uber/NullAway 52
  41. Null Away static void log(Object x) { System.out.println(x.toString()); } static

    void foo() { log(null); } warning: [NullAway] passing @Nullable parameter 'null' where @NonNull is required log(null); ^ 53
  42. Null Away Integration with Gradle-based Java project https://github.com/uber/NullAway#java-non-android Integration with

    Gradle-based Android project https://github.com/uber/NullAway#android http://wittchen.io/2017/09/15/integrating-nullaway-with-an-android-project/ 54
  43. Keeping up good practices in greenfield projects • Choose one

    approach or several approaches • Apply chosen solutions to your work routine and CI server • Perform code reviews carefully • Be consistent 55
  44. How about legacy code? • Apply proper rules to the

    new code (see previous slide) • Perform null-checks and write more unit tests for the old code • Keep backward compatibility when necessary • Gradually deprecate old code and introduce new rules 56
  45. Languages without null Languages with Option type: • Rust •

    Ocaml • Standard ML • F# • Scala Languages with Maybe type: • Elm • Haskell and others I could miss... Crystal has nil, but compiler prevents NPEs at compile time 59
  46. Summary • Do not pass null • Do not return

    null • Return empty collections instead of null • Use Optional/Option type for returning “nullable” sync data • Use RxJava Maybe type for returning “nullable” async data • Make data in your code as much immutable as possible • Use compile time analysis and static code analysis • Use language without null or with null-safety features when you can • Be careful during code reviews • Be consistent during applying good practices 60
  47. Fixing a billion dollar mi$take Thank you for attention! Questions?

    Piotr Wittchen wittchen.io github.com/pwittchen 61