Skip to content

Commit e88392b

Browse files
committed
Write explanation for the Optional concept, as well as the test file, the stub implementation, the reference solution and other required files. Some files must be modified. This is a draft.
1 parent 3ec59e8 commit e88392b

File tree

14 files changed

+479
-0
lines changed

14 files changed

+479
-0
lines changed

config.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,13 @@
308308
"generic-types"
309309
],
310310
"status": "beta"
311+
},
312+
{
313+
"slug": "tim-from-marketing-2",
314+
"name": "tim-from-marketing-2",
315+
"uuid": "a6cfc286-8c62-4f5b-8e59-f6bfc4374092",
316+
"concepts": [],
317+
"prerequisites": []
311318
}
312319
],
313320
"practice": [

exercises/concept/tim-from-marketing-2/.docs/hints.md

Whitespace-only changes.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Instructions
2+
3+
In this exercise you will be writing code to print all the names of the factory employees.
4+
5+
Employees have an ID, a name and a department name, like in [tim-from-marketing](/exercises/concept/tim-from-marketing).
6+
Assume that the ID of the first employee is 1, the ID of the second employee is 2, and so on. If an employee has an ID, the other two fields, name and department name, have valid values.
7+
8+
Two methods are already implemented:
9+
10+
- `getAllTheEmployeesById()` returns an Optional<List<Employee>> object. Notice this method does NOT receive any parameter.
11+
- `getEmployeeById(id)` returns an Optional<Employee> object for the given ID, being Employee the following class:
12+
13+
```java
14+
class Employee {
15+
private int id;
16+
private String name;
17+
private String departmentName;
18+
// Getters and setters
19+
}
20+
```
21+
22+
## 1.- Print the names of all the employees
23+
24+
Implement the `printAllEmployeesNamesById()` method to print the names of all the employees, together with their id. If the employee does not exist, print "[id] - This employee does not exist".
25+
26+
```java
27+
"1 - Tim"
28+
"2 - Bill"
29+
"3 - Steve"
30+
"4 - This employee does not exist"
31+
"5 - Charlotte"
32+
```
33+
34+
## 2.- Print the name and department of a given employee
35+
36+
Implement the `printEmployeeNameAndDepartmentById(id)` method to print the name and department of a given employee, together with their id. If the employee does not exist, print "[id] - This employee does not exist":
37+
38+
```java
39+
printEmployeeNameAndDepartmentById(1) => "1 - Tim - Marketing"
40+
printEmployeeNameAndDepartmentById(2) => "2 - Bill - Sales"
41+
printEmployeeNameAndDepartmentById(3) => "3 - Steve - Engineering"
42+
printEmployeeNameAndDepartmentById(4) => "4 - This employee does not exist"
43+
printEmployeeNameAndDepartmentById(5) => "5 - Charlotte - Owner"
44+
```
45+
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Introduction
2+
3+
## Optional
4+
5+
## Introduction
6+
7+
The Optional<T> type was introduced in Java 8 as a way to indicate that a method will return an object of type T or a null value. It is present in type signatures of many core Java methods.
8+
9+
Before Java 8, developers had to implement null checks:
10+
11+
```java
12+
public Employee getEmployee(String name) {
13+
// Assume that getEmployeeByName retrieves an Employee from a data base
14+
Employee employee = getEmployeeByName(name);
15+
if (employee != null) {
16+
return employee;
17+
} else {
18+
return throw new IllegalArgumentException("Employee not found");
19+
}
20+
}
21+
```
22+
23+
With the Optional API, the code above can be simplified to:
24+
25+
```java
26+
public Optional<Employee> getEmployee(String name) {
27+
// Assume that getEmployeeByName returns an Optional<Employee>
28+
return getEmployeeByName(name)
29+
.orElseThrow(() -> new IllegalArgumentException("Employee not found"));
30+
}
31+
```
32+
33+
If a default value must be returned, the `orElse` method can be used.
34+
35+
```java
36+
public Optional<Employee> getEmployee(String name) {
37+
// Assume that getEmployeeByName returns an Optional<Employee>
38+
return getEmployeeByName(name)
39+
.orElse(new Employee("Daniel"));
40+
}
41+
```
42+
43+
Provided all the invoked methods return Optional objects, many methods can be chained without having to worry about null checking:
44+
45+
```java
46+
public Optional<Integer> getEmployeeAge(String name) {
47+
Optional<Employee> optionalEmployee = getEmployeeByName(name);
48+
return getEmployeeByName(name)
49+
.map(Employee::getAge)
50+
.orElse(0);
51+
}
52+
```
53+
54+
It is important to understand that the Optional API does not eliminate the null values. It defers the null checking until the end of a series of methods, as long as all those methods return an optional object.
55+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Introduction
2+
3+
## Optional
4+
5+
%{concept:optional}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"authors": ["josealonso"],
3+
"files": {
4+
"solution": [
5+
"src/main/java/TimFromMarketing2.java"
6+
],
7+
"test": [
8+
"src/test/java/TimFromMarketing2Test.java"
9+
],
10+
"exemplar": []
11+
},
12+
"blurb": ""
13+
}

exercises/concept/tim-from-marketing-2/.meta/design.md

Whitespace-only changes.
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
import java.util.List;
2+
import java.util.ArrayList;
3+
import java.util.Optional;
4+
import java.util.stream.*;
5+
6+
7+
public class Main {
8+
public static void main(String[] args) {
9+
System.out.println("Hello");
10+
11+
var employeeService = new EmployeeService();
12+
System.out.println(employeeService.printAllEmployeesNamesById());
13+
System.out.println(employeeService.printEmployeeNameAndDepartmentById(1));
14+
System.out.println(employeeService.printEmployeeNameAndDepartmentById(2));
15+
System.out.println(employeeService.printEmployeeNameAndDepartmentById(3));
16+
System.out.println(employeeService.printEmployeeNameAndDepartmentById(4));
17+
}
18+
}
19+
20+
class EmployeeService {
21+
22+
private Utils utils = new Utils();
23+
24+
public List<Optional<Employee>> getAllTheEmployeesById() {
25+
return utils.getAllTheEmployeesById()
26+
.stream()
27+
.map(employee -> Optional.ofNullable(employee))
28+
.collect(Collectors.toList());
29+
}
30+
31+
public Optional<Employee> getEmployeeById(int employeeId) {
32+
/* Solution using Streams
33+
34+
return getAllTheEmployeesById(employeesList).stream()
35+
.filter(employee -> employee.getId() == id)
36+
.orElse("Employee not found");
37+
*/
38+
39+
return Optional.ofNullable(utils.getEmployeeById(employeeId));
40+
}
41+
42+
public String printAllEmployeesNamesById() {
43+
List<Optional<Employee>> nullableEmployeesList = getAllTheEmployeesById();
44+
// var employee = new Employee();
45+
StringBuilder stringBuilder = new StringBuilder();
46+
for (int i = 0; i < nullableEmployeesList.size(); i++) {
47+
stringBuilder.append(i).append(" - ");
48+
49+
nullableEmployeesList.get(i)
50+
.flatMap(employee -> employee.getName())
51+
// .map(nullableEmployee -> nullableEmployee.get()) // Compile error
52+
.ifPresentOrElse(
53+
name -> stringBuilder.append(name).append("\n"),
54+
() -> stringBuilder.append("No employee found\n")
55+
);
56+
// .ifPresent(name -> stringBuilder.append(name))
57+
// .orElse("No employee found"); // compile error
58+
}
59+
return stringBuilder.toString();
60+
}
61+
62+
public String printEmployeeNameAndDepartmentById(int employeeId) {
63+
64+
var employee = getEmployeeById(employeeId);
65+
StringBuilder stringBuilder = new StringBuilder();
66+
stringBuilder.append(employeeId).append(" - ");
67+
employee.ifPresentOrElse(
68+
e -> {
69+
// Handle Optional values
70+
e.getName().ifPresentOrElse(
71+
name -> stringBuilder.append(name).append(" - "),
72+
() -> {}
73+
);
74+
e.getDepartment().ifPresentOrElse(
75+
department -> stringBuilder.append(department),
76+
() -> {}
77+
);
78+
},
79+
() -> stringBuilder.append("No employee found")
80+
);
81+
return stringBuilder.toString();
82+
}
83+
84+
}
85+
86+
class Utils {
87+
88+
private List<Employee> listOfEmployees = new ArrayList<>();
89+
// List.of( // Immutable lists do not allow null elements
90+
{
91+
listOfEmployees.add(new Employee(0, "Tim", "Direction"));
92+
listOfEmployees.add(new Employee(1, "Mark", "Sales"));
93+
listOfEmployees.add(new Employee(2, "John", "Engineering"));
94+
listOfEmployees.add(null); // Adding a null element
95+
listOfEmployees.add(new Employee(4, "Jane", "Sales"));
96+
}
97+
98+
public List<Employee> getAllTheEmployeesById() {
99+
return listOfEmployees;
100+
}
101+
102+
public Employee getEmployeeById(int employeeId) {
103+
return listOfEmployees.get(employeeId);
104+
}
105+
}
106+
107+
108+
class Employee {
109+
private final int id; // It can't be final due to the empty constructor
110+
private final String name;
111+
private final String department;
112+
113+
public Employee(int id, String name, String department) {
114+
this.id = id;
115+
this.name = name;
116+
this.department = department;
117+
}
118+
119+
public Optional<Integer> getId() {
120+
return Optional.ofNullable(id);
121+
}
122+
123+
public Optional<String> getName() {
124+
return Optional.ofNullable(name);
125+
}
126+
127+
public Optional<String> getDepartment() {
128+
return Optional.ofNullable(department);
129+
}
130+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import java.util.List;
2+
import java.util.ArrayList;
3+
import java.util.Optional;
4+
import java.util.stream.*;
5+
6+
7+
class EmployeeService {
8+
9+
public List<Optional<Employee>> getAllTheEmployeesById() {
10+
return getAllTheEmployeesById()
11+
.stream()
12+
.map(employee -> Optional.ofNullable(employee))
13+
.collect(Collectors.toList());
14+
}
15+
16+
public Optional<Employee> getEmployeeById(int employeeId) {
17+
/* Solution using Streams
18+
19+
return getAllTheEmployeesById(employeesList).stream()
20+
.filter(employee -> employee.getId() == id)
21+
.orElse("Employee not found");
22+
*/
23+
24+
return Optional.ofNullable(getEmployeeById(employeeId));
25+
}
26+
27+
public String printAllEmployeesNamesById() {
28+
List<Optional<Employee>> nullableEmployeesList = getAllTheEmployeesById();
29+
StringBuilder stringBuilder = new StringBuilder();
30+
for (int i = 0; i < nullableEmployeesList.size(); i++) {
31+
stringBuilder.append(i).append(" - ");
32+
33+
nullableEmployeesList.get(i)
34+
.flatMap(employee -> employee.getName())
35+
.ifPresentOrElse(
36+
name -> stringBuilder.append(name).append("\n"),
37+
() -> stringBuilder.append("No employee found\n")
38+
);
39+
}
40+
return stringBuilder.toString();
41+
}
42+
43+
public String printEmployeeNameAndDepartmentById(int employeeId) {
44+
45+
var employee = getEmployeeById(employeeId);
46+
StringBuilder stringBuilder = new StringBuilder();
47+
stringBuilder.append(employeeId).append(" - ");
48+
employee.ifPresentOrElse(
49+
e -> {
50+
// Handle Optional values
51+
e.getName().ifPresentOrElse(
52+
name -> stringBuilder.append(name).append(" - "),
53+
() -> {}
54+
);
55+
e.getDepartment().ifPresentOrElse(
56+
department -> stringBuilder.append(department),
57+
() -> {}
58+
);
59+
},
60+
() -> stringBuilder.append("No employee found")
61+
);
62+
return stringBuilder.toString();
63+
}
64+
65+
}
66+

exercises/concept/tim-from-marketing-2/build.gradle

Whitespace-only changes.

0 commit comments

Comments
 (0)