From a6eee0c3a2a187d11f707ef56ada21f01137c89c Mon Sep 17 00:00:00 2001 From: Blake Hawkins Date: Mon, 25 Apr 2016 17:23:58 +0100 Subject: [PATCH] improve grammar in section 5 --- 05-optionals.md | 49 ++++++++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/05-optionals.md b/05-optionals.md index 3f7cb24..c322edd 100644 --- a/05-optionals.md +++ b/05-optionals.md @@ -1,19 +1,19 @@ Optionals ---- -Every Java developer whether beginner, novice, or seasoned has in his/her lifetime experienced `NullPointerException`. This is a true fact that no Java developer can deny. We all have wasted or spent many hours trying to fix bugs caused by `NullPointerException`. According to `NullPointerException` JavaDoc, ***NullPointerException is thrown when an application attempts to use null in a case where an object is required.***. This means if we invoke a method or try to access a property on ***null*** reference then our code will explode and `NullPointerException` is thrown. In this chapter, you will learn how to write null free code using Java 8 `Optional`. +Every Java developer, whether beginner, novice, or seasoned, has in their lifetime experienced `NullPointerException`. We all have wasted or spent many hours trying to fix bugs caused by `NullPointerException`. According to `NullPointerException`'s JavaDoc, ***NullPointerException is thrown when an application attempts to use null in a case where an object is required.***. This means if we invoke a method or try to access a property on ***null*** reference, then our code will explode and `NullPointerException` is thrown. In this chapter, you will learn how to write null-free code using Java 8's `Optional`. -> On a lighter note, if you look at the JavaDoc of NullPointerException you will find that author of this exception is ***unascribed***. If the author is unknown unascribed is used(nobody wants to take ownership of NullPointerException ;)) +> On a lighter note, if you look at the JavaDoc of NullPointerException you will find that author of this exception is ***unascribed***. If the author is unknown, unascribed is used (nobody wants to take ownership of NullPointerException ;)). ## What are null references? -In 2009 at QCon conference ***[Sir Tony Hoare](https://en.wikipedia.org/wiki/Tony_Hoare)*** stated that he invented null reference type while designing ***ALGOL W*** programming language. null was designed to signify absence of a value. He called *null references* as a *billion-dollar mistake*. You can watch the full video of his presentation on Infoq http://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare. +In 2009, at QCon conference, ***[Sir Tony Hoare](https://en.wikipedia.org/wiki/Tony_Hoare)*** stated that he invented the `null` reference type while designing the ***ALGOL W*** programming language. `null` was designed to signify absence of a value. He called *null references* as a *billion-dollar mistake*. You can watch the full video of his presentation on Infoq http://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare. -Most of the programming languages like C, C++, C#, Java, Scala, etc. has nullable type as part of their type system which allows the value to be set to a special value **Null** instead of other possible data type values. +Most of the programming languages like C, C++, C#, Java, Scala, etc. have a nullable type as part of their type system, which allows the value to be set to a special value, **Null**, instead of other possible data type values. -## Why null references are a bad thing? +## Why null references are a bad thing -Let's look at the example Task management domain classes shown below. Our domain model is very simple with only two classes -- Task and User. A task can be assigned to a user. +Let's look at the example Task management domain classes shown below. Our domain model is very simple with only two classes -- Task and User. A task can be assigned to a user. > Code for this section is inside [ch05 package](https://github.com/shekhargulati/java8-the-missing-tutorial/tree/master/code/src/main/java/com/shekhargulati/java8_tutorial/ch05). @@ -84,7 +84,7 @@ public String taskAssignedTo(String taskId) { } ``` -The biggest problem with the code shown above is that absence of the value is not visible in the API i.e. if the `task` is not assigned to any user then the code will throw `NullPointerException` when `getAssignedTo` is called. The `taskRepository.find(taskId)` and `taskRepository.find(taskId).getAssignedTo()` could return `null`. This forces clients of the API to program defensively and check for null checks as shown below. +The biggest problem with the code shown above is that absence of the value is not visible in the API, i.e. if the `task` is not assigned to any user, then the code will throw `NullPointerException` when `getAssignedTo` is called. The `taskRepository.find(taskId)` and `taskRepository.find(taskId).getAssignedTo()` could return `null`. This forces clients of the API to program defensively, and check for null frequently, as shown below. ```java public String taskAssignedTo(String taskId) throws TaskNotFoundException { @@ -103,7 +103,7 @@ The code shown above misses developer intent and bloats client code with `if-nul ## Null Object pattern -A common solution to working with `null` references is to use [Null Object pattern](https://en.wikipedia.org/wiki/Null_Object_pattern). The idea behind this pattern is very simple instead of returning null you should return a null object that implements your interface or class. So, you can create a `NullUser` as shown below. +A common solution to working with `null` references is to use [Null Object pattern](https://en.wikipedia.org/wiki/Null_Object_pattern). The idea behind this pattern is very simple -- instead of returning null, you should return a null object that implements your interface or class. So, you can create a `NullUser` as shown below. ```java public class NullUser extends User { @@ -122,7 +122,7 @@ public User getAssignedTo() { } ``` -Now client code can be simplified to not use null check for user as shown below. In this example, it does not make sense to use Null Object pattern for `Task` because non-existence of task in the repository is an exception situation. Also, by adding `TaskNotFoundException` in the throws clause we have made it explicit for the client that this code can throw exception. +Now client code can be simplified to not use a null check for `User`, as shown below. In this example, it does not make sense to use Null Object pattern for `Task` because non-existence of task in the repository is an exception situation. Also, by adding `TaskNotFoundException` in the `throws` clause, we have made it explicit for the client that this code can throw an exception. ```java public String taskAssignedTo(String taskId) throws TaskNotFoundException { @@ -136,7 +136,7 @@ public String taskAssignedTo(String taskId) throws TaskNotFoundException { ## Java 8 -- Introduction of Optional data type -Java 8 introduced a new data type ***java.util.Optional*** which encapsulates an empty value. It makes intent of the API clear. If a function returns a value of type Optional then it tells the clients that value might not be present. Use of `Optional` data type makes it explicit to the API client when it should expect an optional value. When you use Optional type then you as a developer makes it visible via the type system that value may not be present and client can cleanly work with it. The purpose of using `Optional` type is to help API designers design APIs that makes it visible to their clients by looking at the method signature whether they should expect optional value or not. +Java 8 introduced a new data type, `java.util.Optional`, which encapsulates an empty value. It makes the intent of the API clear. If a function returns a value of type `Optional`, then it tells the clients that a value might not be present. Use of the `Optional` data type makes it explicit to the API client when it should expect an optional value. The purpose of using the `Optional` type is to help API designers make it visible to their clients, by looking at the method signature, whether they should expect an optional value or not. Let's update our domain model to reflect optional values. @@ -200,20 +200,19 @@ public class User { } ``` -Use of `Optional` data type in the data model makes it explicit that `Task` refers to an ***Optional*** and ***User*** has an **Optional** username. Now whoever tries to work with `assignedTo` User would know that it might not be present and they can handle it in a declarative way. We will talk about `Optional.empty` and `Optional.of` methods in the next section. +Use of the `Optional` data type in the data model makes it explicit that `Task` refers to an `Optional` and `User` has an `Optional*` username. Now whoever tries to work with `assignedTo` User would know that it might not be present and they can handle it in a declarative way. We will talk about `Optional.empty` and `Optional.of` methods in the next section. ## Working with creational methods in the java.util.Optional API -In the domain model shown above, we used couple of creational methods of the Optional class but I didn't talked about them. Let's now discuss three creational methods which are part of the `Optional` API. +In the domain model shown above, we used a couple of creational methods of the Optional class, but didn't discuss them. Three creational methods which are part of the `Optional` API follow below. -* **Optional.empty**: This is used to create an Optional when value is not present like we did above `this.assignedTo = Optional.empty();` in the constructor. +* `Optional.empty`: This is used to create an Optional when a value is not present, like we did above (`this.assignedTo = Optional.empty();`) in the constructor. -* **Optional.of(T value)**: This is used to create an Optional from a non-null value. It throws `NullPointerException` when value is null. We used it in the code shown above `this.address = Optional.of(address);`. +* `Optional.of(T value)`: This is used to create an Optional from a non-null value. It throws `NullPointerException` when `value` is null. We used it in the code shown above (`this.address = Optional.of(address);`). -* **Optional.ofNullable(T value)**: This static factory method works for both null and non-null values. For null values it will create an empty Optional and for non-null value it will create Optional using the value. +* `Optional.ofNullable(T value)`: This static factory method which works for both null and non-null values. For null values it will create an empty Optional and for non-null values it will create an Optional using the value. - -Below is a simple example of how you can write API using Optional. +Below is a simple example of how you can write an API using Optional. ```java public class TaskRepository { @@ -232,11 +231,11 @@ public class TaskRepository { ## Using Optional values -Optional can be thought as a Stream with one element. It has methods similar to Stream API like map, filter, flatMap that we can use to work with values contained in the `Optional`. +Optional can be thought of as a Stream with one element. It has methods similar to Stream API like `map`, `ilter`, and `flatMap`, which we can use to work with values contained in the `Optional`. ### Getting title for a Task -To read the value of title for a Task we would write code as shown below. The `map` function was used to transform from ***Optional*** to ***Optional***. The `orElseThrow` method is used to throw a custom business exception when no Task is found. +To read the value of title for a Task, we would write code as shown below. The `map` function was used to transform from `Optional` to `Optional`. The `orElseThrow` method is used to throw a custom business exception when no Task is found. ```java public String taskTitle(String taskId) { @@ -249,17 +248,17 @@ public String taskTitle(String taskId) { There are three variants of `orElse*` method: -1. **orElse(T t)**: This is used to return a value when exists or returns the value passed as parameter like `Optional.ofNullable(null).orElse("NoValue")`. This will return `NoValue` as no value exist. +1. `orElse(T t)`: This is used to return the value if it exists, or returns the value `t` passed as parameter, like `Optional.ofNullable(null).orElse("NoValue")`. This will return `"NoValue"` as no value exists. -2. **orElseGet**: This will return the value if present otherwise invokes the `Supplier`s `get` method to produce a new value. For example, `Optional.ofNullable(null).orElseGet(() -> UUID.randomUUID().toString()` could be used to lazily produce value only when no value is present. +2. `orElseGet`: This will return the value if it is present, otherwise invokes the `Supplier`'s `get` method to produce a new value. For example, `Optional.ofNullable(null).orElseGet(() -> UUID.randomUUID().toString()` could be used to lazily produce a value only when none is present. -3. **orElseThrow**: This allow clients to throw their own custom exception when value is not present. +3. `orElseThrow`: This allow clients to throw their own custom exception when a value is not present. -The find method shown above returns an `Optional` that the client can use to get the value. Suppose we want to get the task's title from the Optional, we can do that by using the map function as shown below. +The find method shown above returns an `Optional` that the client can use to get the value. Suppose we want to get the task's title from the `Optional` -- we can do that by using the `map` function, as shown below. ### Getting username of the assigned user -To get the username of the user who is assigned a task we can use the `flatMap` method as shown below. +To get the username of the user who is assigned a task, we can use the `flatMap` method, as shown below. ```java public String taskAssignedTo(String taskId) { @@ -272,7 +271,7 @@ public String taskAssignedTo(String taskId) { ### Filtering with Optional -The third Stream API like operation supported by Optional is filter, which allows you to filter an Optional based on property as shown in example below. +The third Stream API like operation supported by `Optional` is `filter`, which allows you to filter an Optional based on some property, as shown in the example below. ```java public boolean isTaskDueToday(Optional task) {