3

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?

4
  • 7
    Seems like complexity resulting from efforts to make it a one-liner. This problem will pretty much go away if you filtered to find your object, then updated it as separate statements... and the resulting code would be more readable! Commented Jul 19, 2021 at 7:26
  • Does the type of your built Student object override equals() and hashCode()? Commented Jul 19, 2021 at 7:30
  • 1
    Rule of thumb: if you're dealing with at most one element, don't use streams. Commented Jul 19, 2021 at 8:29
  • Hi @AmalK, yes it does. Commented Jul 20, 2021 at 5:58

1 Answer 1

3

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;
}
Sign up to request clarification or add additional context in comments.

3 Comments

As I understand the code in the question, it's updating both the matching object from the findAll() list and the matching object from students. I think this code would only update the former.
@ernest_k Yeah I somehow missed the findAll part (I have updated my answer). But only the object from students is updated right?
Ah you're right. Only students is updated.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.