Example of Optional

As a demonstration of Optional, we are going to create an in-memory student repository. This repository has a method to find students by their name, which, for convenience, will be considered the ID. The value returned by the method is Optional<Student>; this means that the response might or might not contain a Student. This pattern is basically one of the common scenarios for Optional.

At this point, the reader should be familiar with the TDD process. For the sake of brevity the complete Red-Green-Refactor process is skipped. Tests are going to be presented along with the implementation in a convenient order, which could not coincide with the order in a TDD iteration.

First of all, we need a Student class to represent students within our system. To keep it simple, our implementation is going to be very basic, with only two parameters: the student's name and age:

public class Student {
public final String name;
public final int age;

public Student(String name, int age) {
this.name = name;
this.age = age;
}
}

The next test class verifies two scenarios: a successful lookup and an unsuccessful one. Note that AssertJ has some useful and meaningful assertion methods for Optional. That makes testing really fluent and readable:

public class StudentRepositoryTest {

private List<Student> studentList = Arrays.asList(
new Student("Jane", 23),
new Student("John", 21),
new Student("Tom", 25)
);

private StudentRepository studentRepository =
new StudentRepository(studentList);

@Test
public void whenStudentIsNotFoundThenReturnEmpty() {
assertThat(studentRepository.findByName("Samantha"))
.isNotPresent();
}

@Test
public void whenStudentIsFoundThenReturnStudent() {
assertThat(studentRepository.findByName("John"))
.isPresent();
}
}

In cases where verifying the existence of a student with that name is not enough, we can perform some assertions on the returned object. In the majority of scenarios, this is the way to go:

@Test
public void whenStudentIsFoundThenReturnStudent() {
assertThat(studentRepository.findByName("John"))
.hasValueSatisfying(s -> {
assertThat(s.name).isEqualTo("John");
assertThat(s.age).isEqualTo(21);
});
}

Now, it's time to focus on the StudentRepository class, which contains only one constructor and the method to perform student lookups. As shown in the following code, the lookup method findByName returns an Optional holding a Student. Note that this is a valid yet not functional implementation used as a starting point:

public class StudentRepository {
StudentRepository(Collection<Student> students) { }

public Optional<Student> findByName(String name) {
return Optional.empty();
}
}

If we run the tests against the preceding implementation we get one successful test, because the lookup method is returning by default an Optional.empty(). The other test throws an error, as follows:

java.lang.AssertionError: 
Expecting Optional to contain a value but was empty.

For the sake of completeness, this is one of the possible implementations:

public class StudentRepository {
private final Set<Student> studentSet;

StudentRepository(Collection<Student> students) {
studentSet = new HashSet<>(students);
}

public Optional<Student> findByName(String name) {
for (Student student : this.studentSet) {
if (student.name.equals(name))
return Optional.of(student);
}
return Optional.empty();
}
}

In the next section, we will see a different point of view on functions. In Java 8, some additional capabilities have been added to functions if they are used in a particular way. We are going to explore a few of them with some examples.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.158.32