You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: 05-optionals.md
+24-25Lines changed: 24 additions & 25 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,19 +1,19 @@
1
1
Optionals
2
2
----
3
3
4
-
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 nullfree code using Java 8 `Optional`.
4
+
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`.
5
5
6
-
> 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 ;))
6
+
> 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 ;)).
7
7
8
8
## What are null references?
9
9
10
-
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.
10
+
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.
11
11
12
-
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.
12
+
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.
13
13
14
-
## Why null references are a bad thing?
14
+
## Why null references are a bad thing
15
15
16
-
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.
16
+
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.
17
17
18
18
> 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).
19
19
@@ -84,7 +84,7 @@ public String taskAssignedTo(String taskId) {
84
84
}
85
85
```
86
86
87
-
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.
87
+
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.
@@ -103,7 +103,7 @@ The code shown above misses developer intent and bloats client code with `if-nul
103
103
104
104
## Null Object pattern
105
105
106
-
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.
106
+
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.
107
107
108
108
```java
109
109
publicclassNullUserextendsUser {
@@ -122,7 +122,7 @@ public User getAssignedTo() {
122
122
}
123
123
```
124
124
125
-
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.
125
+
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 8 introduced a new data type***java.util.Optional<T>*** which encapsulates an empty value. It makes intent of the API clear. If a function returns a value of type Optional<T> 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.
139
+
Java 8 introduced a new data type, `java.util.Optional<T>`, which encapsulates an empty value. It makes the intent of the API clear. If a function returns a value of type `Optional<T>`, 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.
140
140
141
141
Let's update our domain model to reflect optional values.
142
142
@@ -200,20 +200,19 @@ public class User {
200
200
}
201
201
```
202
202
203
-
Use of `Optional` data type in the data model makes it explicit that `Task` refers to an ***Optional<User>*** and ***User*** has an **Optional<String>** 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.
203
+
Use of the `Optional` data type in the data model makes it explicit that `Task` refers to an `Optional<User>` and `User` has an `Optional<String>*` 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.
204
204
205
205
## Working with creational methods in the java.util.Optional API
206
206
207
-
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.
207
+
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.
208
208
209
-
***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.
209
+
*`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.
210
210
211
-
***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);`.
211
+
*`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);`).
212
212
213
-
***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.
213
+
*`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.
214
214
215
-
216
-
Below is a simple example of how you can write API using Optional.
215
+
Below is a simple example of how you can write an API using Optional.
217
216
218
217
```java
219
218
publicclassTaskRepository {
@@ -232,11 +231,11 @@ public class TaskRepository {
232
231
233
232
## Using Optional values
234
233
235
-
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`.
234
+
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`.
236
235
237
236
### Getting title for a Task
238
237
239
-
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<Task>*** to ***Optional<String>***. The `orElseThrow` method is used to throw a custom business exception when no Task is found.
238
+
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<Task>` to `Optional<String>`. The `orElseThrow` method is used to throw a custom business exception when no Task is found.
240
239
241
240
```java
242
241
publicString taskTitle(String taskId) {
@@ -249,17 +248,17 @@ public String taskTitle(String taskId) {
249
248
250
249
There are three variants of `orElse*` method:
251
250
252
-
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.
251
+
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.
253
252
254
-
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.
253
+
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.
255
254
256
-
3.**orElseThrow**: This allow clients to throw their own custom exception when value is not present.
255
+
3.`orElseThrow`: This allow clients to throw their own custom exception when a value is not present.
257
256
258
-
The find method shown above returns an `Optional<Task>` that the client can use to get the value. Suppose we want to get the task's title from the Optional<Task>, we can do that by using the map function as shown below.
257
+
The find method shown above returns an `Optional<Task>` that the client can use to get the value. Suppose we want to get the task's title from the `Optional<Task>` -- we can do that by using the `map` function, as shown below.
259
258
260
259
### Getting username of the assigned user
261
260
262
-
To get the username of the user who is assigned a task we can use the `flatMap` method as shown below.
261
+
To get the username of the user who is assigned a task, we can use the `flatMap` method, as shown below.
263
262
264
263
```java
265
264
publicString taskAssignedTo(String taskId) {
@@ -272,7 +271,7 @@ public String taskAssignedTo(String taskId) {
272
271
273
272
### Filtering with Optional
274
273
275
-
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.
274
+
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.
0 commit comments