ifPresent() 메서드로 Optional 처리하기

2022. 7. 22. 17:21JAVA

초보자 삽질 귀여움주의;; 도움 안됨주의;;

 

 

 

프로젝트 진행 중, DB에서 단건조회를 하고 Optional로 감싸져서 반환되는 값을 처리하고 있었다..

 

게시글 추천 기능을 구현하려고 user_id 속성과 post_id 속성이 복합적으로 유니크하게 존재해야 했는데, 테이블 상에서 묶어서 unique로 관리하는 것은 뭔가 맘에 들지 않았다. 그래서 id속성을 따로 만들고 개발자가 수작업으로 데이터 정합성을 관리하려고 했다.

 

 

추천_테이블 코드:

@Repository
public interface PostRecommendRepository extends JpaRepository<PostRecommend, Long> {

    @Query("select pr from PostRecommend pr where pr.user.userId=:userId and pr.post.postId=:postId")
    Optional<PostRecommend> findByUsersIdAndPostId(@Param("postId") Long postId,@Param("userId") Long userId);
}

 

서비스레이어 코드:

@Transactional
public void postRecommendCount(PostRecommendRequest postRecommendRequest) {
    Post post = postRepository.findById(postRecommendRequest.getPostId()).
            orElseThrow(() -> new IllegalArgumentException("해당하는 postId가 없습니다. 잘못된 입력"));
    Users user = userRepository.findById(postRecommendRequest.getUserId())
            .orElseThrow(() -> new IllegalArgumentException("해당하는 userId가 없습니다"));

    postRecommendRepository.findByUsersIdAndPostId(post.getPostId(), user.getUserId())
            .ifPresent(i -> new IllegalStateException("해당 유저가 이미 추천한 게시물입니다."));

    PostRecommend postRecommend = PostRecommend.builder()
            .post(post)
            .user(user)
            .createdAt(LocalDateTime.now())
            .build();
    postRecommendRepository.save(postRecommend);
}

중간 쯤에 있는 ifPresent() 메서드를 활용해서, 이미 user_id와 post_id를 복합적으로 갖고있는 레코드가 존재하면 IllegalStateException()을 터트리려는 것이 주요한 로직이었다.

 

근데, 포스트맨으로 아무리 중복 요청을 보내도 에러가 안터진다................. 그냥 DB에 계속 데이터만 쌓인다

ifPresent()를 잘 사용한 것인지 글도 계속 찾아보고 예제도 찾아봤는데 참 이상허다...

 

그냥 복합 unique 제약조건을 걸까 하던 참에.. 스택오버플로우의 글을 하나 보게 되었다

https://stackoverflow.com/questions/28596790/throw-an-exception-if-an-optional-is-present

 

Throw an exception if an Optional<> is present

Let's say I want to see if an object exists in a stream and if it is not present, throw an Exception. One way I could do that would be using the orElseThrow method: List<String> values = new

stackoverflow.com

ifPresent()는 consumer 라는 함수형 인터페이스를 인자를 받는다. 입력은 있고 출력은 없는 형태라고 생각하면 된다.

그래서 람다식의 왼쪽 부분이 필수적인 것은 인텔리제이에서 알려줘서 인지하고 있었다.

오른쪽 부분은 consumer의 반환타입이 void 이므로.. i를 써도 되고 안써도 된다. 반환값이 void기만 하면 된다. 그래서 오류를 던진 것이었는데...

 

postRecommendRepository.findByUsersIdAndPostId(post.getPostId(), user.getUserId())
        .ifPresent(i -> new IllegalStateException("해당 유저가 이미 추천한 게시물입니다."));
        
postRecommendRepository.findByUsersIdAndPostId(post.getPostId(), user.getUserId())
        .ifPresent(i -> {throw new IllegalStateException("해당 유저가 이미 추천한 게시물입니다.");});

알고보니 new로 exception을 생성만 되고 그냥 버려지고 있었다.

ㅎㅎ; 중괄호로 감싸고 throw 를 넣어주니 잘 작동한다. (허무)

 

삽질은 조금 했지만 함수형 인터페이스에 대해서 조금 더 알게 되었다.

 

 

근데 중괄호는 왜 필요한거지..