본 시리즈는 메타 코딩님의 Junit 강의를 학습한 내용을 바탕으로 정리하였습니다.
현재 Service layer의 로직들을 개발하고 있다. 계속해서 이번엔 책 목록보기를 구현해보자.
package site.metacoding.junitproject.service;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.transaction.Transactional;
import org.springframework.stereotype.Service;
import lombok.RequiredArgsConstructor;
import site.metacoding.junitproject.domain.Book;
import site.metacoding.junitproject.domain.BookRepository;
import site.metacoding.junitproject.util.MailSender;
import site.metacoding.junitproject.web.dto.BookRespDto;
import site.metacoding.junitproject.web.dto.BookSaveReqDto;
@RequiredArgsConstructor
@Service
public class BookService {
private final BookRepository bookRepository;
private final MailSender mailSender;
// 1. 책 등록
public BookRespDto 책등록하기(BookSaveReqDto dto) {
// ... (생략)
}
// 2. 책 목록보기
public List<BookRespDto> 책목록보기() {
return bookRepository.findAll().stream()
.map(new BookRespDto()::toDto)
.collect(Collectors.toList());
}
책 목록 보기는 상당히 간단히 구현되었다.
한 가지 특징적인 것을 보자면 bookRepository.findAll().stream()
.
즉, .stream()
메소드를 사용한 것을 볼 수 있다.
stream()
메소드는 무엇이며, .map
, .collect
이 기능들은 다 무엇일까?
이를 알기 쉽게 설명하기 위해 다음 그림을 보자.
평화로운 자바 강(?)에는 여러 물고기들이 살고 있다.
광어, 농어, 숭어, (내가 좋아하는) 연어, 메기 등등...
Stream은 이와 같이 오브젝트 타입의 데이터들이 흘러가는 상태라고 생각하면 된다.
이 중, '광어' 로 Filter를 걸게되면 JAVA 강에 다른 물고기들은 존재하지 않고, 오로지 '광어' 만 돌아다니게 된다.
Map은 한 마디로 ' 변경된 Stream
' 이라고 보면 된다. Stream
은 Filter에 의해 광어만 돌아다니도록 변경되었을 것이고, 이를 통해 '광어' 만의 Stream
으로 바뀐 상태이다. 이렇게 변경된 Stream
의 내용을 복제해서 새로 만든 것이 Map
이다.
우리 코드에서는 객체가 아닌 Dto
로 전달하기 위해 toDto
메소드를 사용하여 Mapping한다.
Map
을 통해 리턴해줄 결과를 알맞은 타입(보통 리스트)으로 정렬하고 담는 것은 Collect
의 몫이다. (물고기를 상자에 담는 느낌...?)
이처럼 JAVA8에는 편리한 기능들이 많다. Stream이 추가되면서 기존에 배열의 원소에 접근할 때, for문과 같은 방식으로 했던 것을 람다함수형식으로 간결하고 편리하게 처리가 가능해졌다.
특히, Map
의 경우 각각의 item을 변경해서 새로운 컨텐츠를 생성하는 기능인 만큼 잘 사용하면 정말 편리한 기능이 된다.