Skip to content

Get updated object after mapping by lambda expression

I have a list of objects as following,

ArrayList<Student> students = new ArrayList<>(
        List.of(
                Student.builder().id(1L).name("Joe").build(),
                Student.builder().id(2L).name("Jan").build()
        )
);

I want to update one of these objects and I have the following implementation

return findAll().stream()
            .filter(s -> s.getId() == studentId)
            .map(s -> students.set(students.indexOf(s), Student.builder().id(s.getId()).name(studentPayload.getName()).build()))
            .findFirst()
            .orElseThrow(() -> new StudentNotFoundException(String.format("Student with id [%d] not found", studentId)));

This returns an object which satisfied with the condition based on filter. Unfortunately this is an not-up-to-date object!

How can I get the updated object after mapping?

Answer

This is because the set method of a List would return the PREVIOUS element at that position and not the newly created one. Refer

Assuming that your id value is unique, I don’t think it is neat to use map and then findFirst even though you could achieve the desired result.

Instead use findFirst and get the element and then then update the details as a second step.

Student sOne = findAll().stream()
                      .filter(s -> s.getId() == studentId)
                      .findFirst()
                      .orElseThrow(() -> new StudentNotFoundException(String.format("Student with id [%d] not found", studentId)));
    
Student sTwo = students.get(students.indexOf(sOne));
if(sTwo!=null) {
    sTwo.setName(studentPayload.getName());
}

return sTwo;

If you still want to do it in single line, then use:

map(s -> {
    Student stu = students.get(students.indexOf(s));
    stu.setName(studentPayload.getName());
    return stu;
}