A bit of history
https://en.wikipedia.org/wiki/Tony_Hoare
https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare 6
What could happen if we pass null to our method?
public void processData(String data) { data.contains("foo");}
processData(null);
NullPointerException
9
Null-checks in application code
public void processData(String data) { if(data != null) { data.contains("foo"); }}
processData(null);
10
Null-checks in library API
public void processData(String data) { if(data == null) { throw new NullPointerException("data is null!"); }
data.contains("foo");}
11
Objects.requireNonNull(...) method introduced in Java 7
public void processData(String data) { Objects.requireNonNull(data, "data cannot be null"); data.contains("foo");}
12
Guava and Preconditions
public void processData(String data) { Preconditions.checkNotNull(data ,"data cannot be null"); data.contains("foo");}
13
Dealing with collections
public List<Integer> createList() { List<Integer> list = new ArrayList<>();
...
if(canReturnList) { return list; }
return null;} 16
Dealing with collections
public List<Integer> createList() { List<Integer> list = new ArrayList<>();
...
if(canReturnList) { return list; }
return list;} 17
Dealing with collections
public List<Integer> createList() { List<Integer> list = new ArrayList<>();
...
if(canReturnList) { return list; }
return new ArrayList<>();} 18
Null Object Patterninterface NullableObject { boolean isNull(); Object getObject();}
class RealObject implements NullableObject { @Override public boolean isNull() { return false; }
@Override public Object getObject() { return new Object(); }}
19
Null Object Patterninterface NullableObject { boolean isNull(); Object getObject();}
class NullObject implements NullableObject { @Override public boolean isNull() { return true; }
@Override public Object getObject() { return null; }}
20
Null Object Pattern
NullableObject object;Object returnedValue;
if(!object.isNull()) { returnedValue = object.getObject();}
21
Optional type in Guavafinal Optional<Object> optional = Optional.of(new Object());
if (optional.isPresent()) { Object notNull = optional.get();}
22
Optional type in Guavafinal Optional<Object> optional = Optional.absent();
final boolean isPresent = optional.isPresent();
assertThat(isPresent).isFalse();
23
Optional type in Guavafinal Optional<Object> optional = Optional.fromNullable(null);
final boolean isPresent = optional.isPresent();
assertThat(isPresent).isFalse();
https://github.com/google/guava/wiki/UsingAndAvoidingNullExplained
24
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
25
Optional type in Java 8Optional<Object> optional = Optional.empty();
Object returnedValue = optional.orElse(StringUtils.EMPTY);
assertThat(returnedValue).isInstanceOf(String.class);
26
Optional type in Java 8Optional<Object> optional = Optional.of(new Object());
optional.ifPresent(object -> assertThat(object).isNotNull());
27
Optional type in Java 8final Optional<Object> optional = Optional.of(new Object());
final String value = optional .map(o -> o.toString()) .orElse(StringUtils.EMPTY);
28
Enhancements of Optional type in Java 9final Optional<Object> optional = Optional.of(new Object());
optional.ifPresentOrElse(object -> assertThat(object).isNotNull(), Assert::fail);
29
Enhancements of Optional type in Java 9final Optional<Object> optional = Optional.empty();
Optional<Object> newValue = optional.or(() -> Optional.of(new Object()));
assertThat(newValue.isPresent()).isTrue();
30
Enhancements of Optional type in Java 9
List<Optional<Object>> optionals;
optionals .stream() .flatMap(Optional::stream) .collect(Collectors.toList());
31
We have even better Option (in Vavr)Option<Object> option = Option.of(new Object());
boolean defined = option.isDefined();
assertThat(defined).isTrue();
32
We have even better Option (in Vavr)Option<Object> option = Option.none();
boolean defined = option.isDefined();
assertThat(defined).isFalse();
33
We have even better Option (in Vavr)Option<Object> option = Option.of(null);
boolean defined = option.isDefined();
assertThat(defined).isFalse();
34
// and no exception is thrown here!
We have even better Option (in Vavr)Option<Object> option = Option.of(new Object());
Object returnedValue = option.getOrElse(() -> StringUtils.EMPTY);
35
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 }});
36
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*/);
37
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!
38
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");
39
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
40
Optional won’t save us from NPEsOptional<Object> optional = Optional.of(new Object());...
41
NullPointerException
optional = null;
optional.isPresent();
Let’s talk about immutabilityObject object = new Object();
object = null;
object.toString();
42
NullPointerException!
Let’s talk about immutabilityfinal Object object = new Object();
object = null;
object.toString();
43
Error: java: cannot assign a value to final variable object
Let’s talk about immutabilityfinal Object object = new Object();
object = null;
object.toString();
44
Error: java: cannot assign a value to final variable object
Let’s talk about immutabilityfinal Object object = new Object();
object = null;
object.toString();
45
Error: java: cannot assign a value to final variable object
Let’s talk about immutabilityfinal Object object = new Object();
object = null;
object.toString();
46
Error: java: cannot assign a value to final variable object
Let’s talk about immutabilityfinal Object object = new Object();
object.toString();
47
Don’t modify the state of the data if you don’t have to
Null safety in Kotlinvalue.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 -1val l = b?.length ?: -1; // Elvis operator
value!!.getObject() // unsafe call - can produce NPE!
48
https://kotlinlang.org/docs/reference/null-safety.html
Maybe type in RxJavaMaybe<Object> maybe = createMaybe();
maybe .subscribeOn(Schedulers.io()) .subscribe(object -> System.out.println(object.toString()));
50
Maybe type in RxJavaMaybe<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() { } });
51
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
53
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
54
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);
^
55
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://blog.wittchen.biz.pl/integrating-errorprone-and-nullaway-with-an-android-project/
56
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
57
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
58
Languages without nullLanguages 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 time61
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
62