해결된 질문
작성
·
405
1
안녕하세요 강사님,
제가 이제 막 개발을 시작한 신입이다보니 db와 자바가 아직 서툴어서 굉장히 이상한 질문을 드리는 것 같은데요.
강의 7분..쯤, 도메인 계층에 비지니스 로직을 구현하면서 User 객체에서 작성된 returnBook()메소드관련 질문입니다. 반납을 위해서 Service에서 찾은 유저의 대출 히스토리에서 targetHistory를 찾기 위해 stream()이 시작되고, UserLoanHistory 객체를 필터링하는 중에, ".findFirst()"로 필터를 하신 이유를 문의드립니다.
왜 마지막이 아니고, 첫번째를 찾나요?
답변 1
1
안녕하세요, hyekyung_lee님!! 매우 좋은 질문 감사드립니다!! 🙏 전혀 이상하지 않은 질문입니다!! 👍
답변을 드려보자면
stream()
과 filter()
를 거치게 되었을 때 결과는 UserLoanHistory
1개가 아니라 N개가 들어있을 수 있습니다.
우리는 특정 대출 기록 1개가 필요하므로 N개를 1개로 만들어야 합니다.
여기까지는 완벽히 이해하신 것 같습니다!! 👍
자 그런데, 여기서 사실 암묵적인 가정 한 가지가 있습니다.
책 이름으로 대출 기록을 필터링 했을 때, 대출 기록이 1개만 존재할 것이라는 가정. 즉, 하나의 책은 한 번만 대출할 수 있다는 가정입니다.
아마 이 가정이 어색하게 느껴져서 질문을 주셨을 것 같아요! 매우 좋은 포인트입니다~
이런 상황이 있을 수 있겠죠!
[상황 1]
책A / 책B / 책C 에 대한 대출기록이 있는데 책B
에 대해 반납하려 한다.
stream()
과 filter()
를 거치면 책B
만 남고 findFirst()
를 하더라도 문제가 없다.
[상황 2]
책A / 책B (반납했음) / 책C / 책B (반납하지 않고 다시 빌렸음)에 대한 대출기록이 있는데 책B
에 대해 반납하려 한다.
이 경우는 stream()
과 filter()
를 거치면 2개의 책B
기록이 남게되고 findFirst()
를 했을 때 진작 반납한 책이 걸릴 수 있습니다.
hyekyung님께서 생각해주신게 맞습니다! 이런 경우는 현재 로직에서 고려되어 있지 않습니다!
이럴 때 상황 2를 이 로직에 국한해 해결하기 위해서는 2가지 방법이 있습니다.
[방법 1]
findFirst()
를 하지 않고, id
기준 정렬 + 가장 마지막 대출기록을 찾는다.
[방법 2]
책의 이름만을 기준으로 필터링 하지 않고
"책의 이름 + 대출중인 상태"를 함께 확인해 필터링 한다.
혹시나 또 궁금한 점이 있으시다면 편하게 질문 부탁드리겠습니다!
감사합니다!!! 🙇🙇
아이고~ 감사합니다!!!
아 질문의 의도가 "저는 책 제목으로 필터링 했을 때 여러 권이 존재하고, 때문에, '누가 빌린 어느 책'을 어떻게 지정하는가, 첫번째 찾아지는 책이 그 책인지 어떻게 확신하는가" 이셨다면!!!!
특정 User
객체 안에 있는 List<UserLoanHistory>
를 찾기 때문에 (즉 JPA 연관관계가 걸려 있는, UserLoanHistory를 찾기 때문에)
이 리스트 안에 들어 있는 UserLoanHistory
는 모두 지금 유저 객체의 대출기록이라고 확신할 수 있습니다!!!
예를 들어,
(1번 유저) / (2번 유저)가 있고
(1번 유저, 책 A) / (1번 유저, 책 B) / (2번 유저, 책 A) 대출기록이 존재한다고 하면
User user = userRepository.findById(1); // 1번 유저를 찾는다!! Optional 처리 생략
user.getUserLoanHistories(); // 1번 유저의 List<UserLoanHistory>를 모두 가져온다.
위의 코드에서 user.getUserLoanHistories()
에는 (1번 유저, 책 A) / (1번 유저, 책 B)만 들어 있게 됩니다!!!
JPA의 연관관계로 인해 '해당 유저의 대출기록'만 가져온다 라고 생각하시면 될 것 같습니다!
개발을 공부하면서 최근에 드는 생각은, 나의 생각이 얼마나 모호하고 대충이었는가! 인데요. 대충 말하고 대충 생각했더니 하나의 로직에 여러 가지 기능을 쑤셔 넣으려고 하기도 하고, 단계가 넘어가지 않더라구요
저도 예전에 코딩을 처음 시작할 때에는 10줄 짜리 함수를 작성하더라도 머릿속에서 정리가 잘 안되어 무작정 코딩하려 하면, 한 줄도 못쓰고 그랬습니다 ㅎㅎㅎ... 그래서 이 함수에서 해야될 것을 경우의 수를 적절히 나누며 글로 쓰거나 그림을 그리고, 정리가 된 후에 코딩을 했었어요!! 이게 익숙해지니 꽤 복잡한 경우가 아니면 어느정도 자연스럽게 구현이 되더라고요!
hyekyung님을 응원합니다!
또 궁금한 점 있으시면 편하게 질문 남겨주세요! 감사합니다~!!! 🙏🙏
크~~제가 암묵적인 가정을 이해하지 못했네요!
저는 책 제목으로 필터링 했을 때 여러 권이 존재하고, 때문에, '누가 빌린 어느 책'을 어떻게 지정하는가, 첫번째 찾아지는 책이 그 책인지 어떻게 확신하는가를 고민 했었는데, 간단했군요^^
제가 생각한 방법은, 책 제목으로 필터링 했으니 정렬 후 User로 다시 필터링하여 가장 최근날짜에 대출한 책을 반납 하는 것 이었는데요. 적어놓고 보니 이 짧은 문장에도 여러 가지 작업이 포함되어 있는 것을 봅니다. 강사님의 2가지 방법으로 분리도 되고요~
개발을 공부하면서 최근에 드는 생각은, 나의 생각이 얼마나 모호하고 대충이었는가! 인데요. 대충 말하고 대충 생각했더니 하나의 로직에 여러 가지 기능을 쑤셔 넣으려고 하기도 하고, 단계가 넘어가지 않더라구요. 강사님께서 코딩하실 때 생각을 구분하고 넘버링 하시면서 한글로 먼저 가이드 해주시는 것에서 저의 길을 찾았습니다. ^^
더불어 좋은 질문글도 추천해 주시고 최고십니다. 강의를 준비하시는 정성스러움과 꼼꼼하고 명쾌한 답변에 오늘도 감탄하고요~ 여러 번 반복하여 꼭꼭 씹어 스프링과 백엔드개발 반드시 제 것으로 만들겠습니다.
빛태현님 언제나 응원합니다!
감사합니다~