Skip to content

Commit ba6a1d4

Browse files
committed
optional chapter clean up
1 parent fe035e1 commit ba6a1d4

File tree

6 files changed

+158
-30
lines changed

6 files changed

+158
-30
lines changed

05-optionals.md

Lines changed: 42 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
## Optionals
1+
Optionals
2+
----
23

3-
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.
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 null free code using Java 8 `Optional`.
45

56
> 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 ;))
67
@@ -14,6 +15,8 @@ Most of the programming languages like C, C++, C#, Java, Scala, etc. has nullabl
1415

1516
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.
1617

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+
1720
```java
1821
public class Task {
1922
private final String id;
@@ -53,7 +56,7 @@ public class Task {
5356
public class User {
5457

5558
private final String username;
56-
private String fullname;
59+
private String address;
5760

5861
public User(String username) {
5962
this.username = username;
@@ -63,12 +66,12 @@ public class User {
6366
return username;
6467
}
6568

66-
public String getFullname() {
67-
return fullname;
69+
public String getAddress() {
70+
return address;
6871
}
6972

70-
public void setFullname(String fullname) {
71-
this.fullname = fullname;
73+
public void setAddress(String address) {
74+
this.address = address;
7275
}
7376
}
7477
```
@@ -139,53 +142,62 @@ Let's update our domain model to reflect optional values.
139142

140143
```java
141144
import java.util.Optional;
142-
import java.util.UUID;
143145

144146
public class Task {
145-
private final String id;
146147
private final String title;
147-
private final TaskType type;
148-
private Optional<User> assignedTo;
148+
private final Optional<User> assignedTo;
149+
private final String id;
149150

150-
public Task(String title, TaskType type) {
151-
this.id = UUID.randomUUID().toString();
151+
public Task(String id, String title) {
152+
this.id = id;
152153
this.title = title;
153-
this.type = type;
154-
this.assignedTo = Optional.empty();
154+
assignedTo = Optional.empty();
155155
}
156156

157-
public Optional<User> getAssignedTo() {
158-
return assignedTo;
157+
public Task(String id, String title, User assignedTo) {
158+
this.id = id;
159+
this.title = title;
160+
this.assignedTo = Optional.ofNullable(assignedTo);
159161
}
160162

161-
public void setAssignedTo(User assignedTo) {
162-
this.assignedTo = Optional.of(assignedTo);
163+
public String getId() {
164+
return id;
165+
}
166+
167+
public String getTitle() {
168+
return title;
169+
}
170+
171+
public Optional<User> getAssignedTo() {
172+
return assignedTo;
163173
}
164174
}
165175

176+
import java.util.Optional;
177+
166178
public class User {
167179

168180
private final String username;
169-
private Optional<String> fullname;
181+
private final Optional<String> address;
170182

171183
public User(String username) {
172184
this.username = username;
173-
this.fullname = Optional.empty();
185+
this.address = Optional.empty();
174186
}
175187

176-
public String getUsername() {
177-
return username;
188+
public User(String username, String address) {
189+
this.username = username;
190+
this.address = Optional.ofNullable(address);
178191
}
179192

180-
public Optional<String> getFullname() {
181-
return fullname;
193+
public String getUsername() {
194+
return username;
182195
}
183196

184-
public void setFullname(String fullname) {
185-
this.fullname = Optional.of(fullname);
197+
public Optional<String> getAddress() {
198+
return address;
186199
}
187200
}
188-
189201
```
190202

191203
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.
@@ -196,7 +208,7 @@ In the domain model shown above, we used couple of creational methods of the Opt
196208

197209
* **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.
198210

199-
* **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.fullname = Optional.of(fullname);`.
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);`.
200212

201213
* **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.
202214

@@ -220,7 +232,7 @@ public class TaskRepository {
220232

221233
## Using Optional values
222234

223-
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`.
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`.
224236

225237
### Getting title for a Task
226238

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.shekhargulati.java8_tutorial.ch05;
2+
3+
public class TaskNotFoundException extends RuntimeException {
4+
public TaskNotFoundException(String id) {
5+
super("No task found for id: " + id);
6+
}
7+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.shekhargulati.java8_tutorial.ch05;
2+
3+
4+
5+
import com.shekhargulati.java8_tutorial.ch05.domain.Task;
6+
7+
import java.util.HashMap;
8+
import java.util.Map;
9+
import java.util.Optional;
10+
11+
public class TaskRepository {
12+
13+
private final Map<String, Task> db = new HashMap<>();
14+
15+
public void loadData() {
16+
db.put("1", new Task("1", "hello java 1"));
17+
db.put("2", new Task("2", "hello java 2"));
18+
db.put("3", new Task("3", "hello java 3"));
19+
db.put("4", new Task("4", "hello java 4"));
20+
db.put("5", new Task("5", "hello java 5"));
21+
}
22+
23+
public Task find(String id) {
24+
return Optional.ofNullable(db.get(id))
25+
.orElseThrow(() -> new TaskNotFoundException(id));
26+
}
27+
28+
public Optional<String> taskAssignedTo(String id) {
29+
return Optional.ofNullable(find(id))
30+
.flatMap(task -> task.getAssignedTo())
31+
.map(user -> user.getUsername());
32+
}
33+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.shekhargulati.java8_tutorial.ch05.domain;
2+
3+
import java.util.Optional;
4+
5+
public class Task {
6+
private final String title;
7+
private final Optional<User> assignedTo;
8+
private final String id;
9+
10+
public Task(String id, String title) {
11+
this.id = id;
12+
this.title = title;
13+
assignedTo = Optional.empty();
14+
}
15+
16+
public Task(String id, String title, User assignedTo) {
17+
this.id = id;
18+
this.title = title;
19+
this.assignedTo = Optional.ofNullable(assignedTo);
20+
}
21+
22+
public String getId() {
23+
return id;
24+
}
25+
26+
public String getTitle() {
27+
return title;
28+
}
29+
30+
public Optional<User> getAssignedTo() {
31+
return assignedTo;
32+
}
33+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.shekhargulati.java8_tutorial.ch05.domain;
2+
3+
import java.util.Optional;
4+
5+
public class User {
6+
7+
private final String username;
8+
private final Optional<String> address;
9+
10+
public User(String username) {
11+
this.username = username;
12+
this.address = Optional.empty();
13+
}
14+
15+
public User(String username, String address) {
16+
this.username = username;
17+
this.address = Optional.ofNullable(address);
18+
}
19+
20+
public String getUsername() {
21+
return username;
22+
}
23+
24+
public Optional<String> getAddress() {
25+
return address;
26+
}
27+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.shekhargulati.java8_tutorial.ch09;
2+
3+
import java.util.UUID;
4+
import java.util.concurrent.CompletableFuture;
5+
import java.util.concurrent.Executors;
6+
7+
public class CompletableFutureExample {
8+
9+
public static void main(String[] args) {
10+
CompletableFuture.completedFuture("hello");
11+
CompletableFuture.runAsync(() -> System.out.println("hello"));
12+
CompletableFuture.runAsync(() -> System.out.println("hello"), Executors.newSingleThreadExecutor());
13+
CompletableFuture.supplyAsync(() -> UUID.randomUUID().toString());
14+
CompletableFuture.supplyAsync(() -> UUID.randomUUID().toString(), Executors.newSingleThreadExecutor());
15+
}
16+
}

0 commit comments

Comments
 (0)