0

I have a method in a Service that retrieve the courses objects from database. Before sending it to Controller I need to uncompress the field byte[] logo. Logo is a image that needs to be uncompress from database before rendering to front-end. I'm trying to do this with streams but without any success. map() method not working after forEach() method.

public List<CourseDto> getCoureses() {

    List<Courses> courses = courseRepositoryDao.findAllByIsCourseFreeAndIsCourseActive(true, true);
    List<CourseDto> coursesNameDto = courses
            .stream()
            .forEach(course-> course.setLogo(decompressZLib(course.getLogo()))
            .map(course -> modelMapper.map(CourseMapper.toUserDtoFreeCourses(course), CourseDto.class))
            .collect(Collectors.toList());

    return coursesNameDto;
}
Bogdan
  • 623
  • 5
  • 13

2 Answers2

5

Use peek(Consumer)

peek(Consumer) exists so that you can perform some action at some point in the stream calls. So use it instead of forEach(Consumer).

The javadoc states:

Returns a stream consisting of the elements of this stream, additionally performing the provided action on each element as elements are consumed from the resulting stream.

Just call it like this:

public List<CourseDto> getCoureses() {

    List<Courses> courses = courseRepositoryDao.findAllByIsCourseFreeAndIsCourseActive(true, true);
    List<CourseDto> coursesNameDto = courses
            .stream()
            .peek(byteArray -> byteArray.setLogo(decompressZLib(byteArray.getLogo()))
            .map(course -> modelMapper.map(CourseMapper.toUserDtoFreeCourses(course), CourseDto.class))
            .collect(Collectors.toList());

    return coursesNameDto;
}

Why doesn't forEach work?

forEach is a terminal operation, that means that the stream cannot be reused after this. This is also the reason why forEach returns void, and of course the language makes it so you cannot chain call after a method returns void.

Olivier Grégoire
  • 33,839
  • 23
  • 96
  • 137
2

forEach is a terminal operation.

Intermediete operations like map return instantly and modify the Stream (actually creating a new Stream object). The operations they represent might get executed when the terminal operation is run.

Terminal operations are operations intended to run at the end of the stream pipeline. They should be used to e.g. collect the elements or do whatever you need the Stream for.

You cannot use a Stream any more after calling a terminal operation.

dan1st
  • 12,568
  • 8
  • 34
  • 67