밤빵's 개발일지
[TIL]20240716 단일 항목에 Lambda표현식을 쓴 이유? 본문
나는 그냥 람다식이 좋은건데..!! 기술 매니저님이 질문하실 때 마다 강사님이 썼기때문에? 그거아니여도 코드가 간결해져서 좋다! 그거 하나 뿐이라 얼마전에 람다식에 대해서 개발일지를 썼지만, 내가 이 질문을 받게 된 서비스 계층 코드를 보면서 특정 ID로 조회한 단일 항목에 대해서도 람다표현식을 사용한 부분에 대해 이유를 생각하면서 이해를 위해 정리를 시작했다. (사실 gpt도 나한테 람다표현식만 주구장창 보여주는 이유도 있다..!)
▶ 람다 표현식 (Lambda Expression) 이란?
람다 표현식은 Java 8에서 도입된 함수형 프로그래밍의 한 기능으로, 익명 함수(Anonymous Function)를 간결하게 표현하는 방법이다. 람다 표현식을 사용하면 불필요한 코드 작성 없이 함수형 인터페이스를 구현할 수 있고, 코드의 가독성을 높이고 유지보수를 쉽게 해준다. 예를 들어, 리스트를 돌면서 각 요소를 처리하는 경우 람다 표현식을 사용하면 코드가 간결하고 명확해진다.
▶ 단일 항목에 람다를 사용한 내 코드
MemoService 클래스에서 단일 메모 항목을 조회할 때도 람다 표현식을 사용했다. getMemo() 메서드에서는 findById() 메서드를 사용하여 Optional<Memo> 객체를 반환받고, 여기에 람다 표현식을 사용해 데이터를 변환하거나 예외를 처리했다.
public MemoResponseDto getMemo(long id) {
return memoRepository.findById(id)
.map(MemoResponseDto::new)
.orElseThrow(() -> new IllegalArgumentException("Memo not found"));
}
→ 코드에서 findById() 메서드는 Optional<Memo> 객체를 반환한다. Optional은 Java 8에서 도입된 컨테이너 클래스로, 값이 존재할 수도 있고 존재하지 않을 수도 있는 경우를 안전하게 처리하는 데 사용된다.
▶ "단일 항목에 람다 표현식을 사용한 이유가 뭔가요?" 라는 질문에 내가 해야하는 대답?
1. 간결한 데이터 변환 및 예외 처리?
→ 람다 표현식을 사용하면 Optional의 map() 메서드를 통해 조회된 엔티티를 직접 MemoResponseDto로 변환할 수 있다. 이는 코드의 가독성을 높이고, 데이터 변환 로직을 간결하게 유지할 수 있게 해준다.
→ orElseThrow() 메서드를 통해 엔티티가 존재하지 않을 경우 예외를 발생시킬 수 있다. 이를 통해 예외 처리 로직을 일관되게 관리할 수 있다.
2. 안전한 null 처리?
→ Optional을 사용한 람다 표현식은 null 처리를 안전하게 한다. 만약 조회된 메모가 존재하지 않는다면, map() 메서드는 실행되지 않고, orElseThrow()가 실행되어 IllegalArgumentException 예외를 던진다. 이를 통해 NPE(NullPointerException)와 같은 문제를 예방할 수 있다.
3. 가독성 및 유지보수성 향상?
→ 람다 표현식을 사용하면 코드의 구조가 간결해지고 명확해진다. 조건문이나 불필요한 로직을 제거할 수 있어서, 코드의 유지보수성이 향상된다. 특히, 예외 처리와 데이터 변환 로직을 한 줄에 표현함으로써 코드의 흐름을 쉽게 파악할 수 있다.
4. 함수형 프로그래밍 스타일의 일관성?
→ 서비스 계층의 다른 메서드들과 동일한 함수형 스타일로 작성하여 일관성을 유지할 수 있다. getMemos()와 같은 메서드에서도 stream()과 map()을 사용해 리스트를 처리하는 것처럼, 단일 항목도 Optional의 map() 메서드를 통해 일관되게 처리할 수 있다. 이는 코드 스타일의 통일성을 유지하고, 코드베이스 전체의 가독성을 높이는 데 도움이 된다.
5. 명시적인 의도 표현?
→ 람다 표현식을 사용함으로써 "이 엔티티를 DTO에 매핑하거나, 존재하지 않는 경우 예외를 발생시킵니다"라는 명시적인 의도를 코드에서 바로 읽을 수 있다. 코드의 의도를 명확히 하고, 유지보수 시 코드의 목적을 쉽게 파악할 수 있게 된다.
▶ 코드 예시를 통해 장점을 찾는다면?
코드 예시를 통해, 람다 표현식이 어떻게 단일 항목에 대한 데이터를 처리하고, 예외를 처리하며, 코드의 간결성과 가독성을 높이는지 살펴보았다. 람다 표현식을 사용함으로써 반복적인 코드 작성을 피할 수 있고, 명확한 의도를 가진 일관된 예외 처리 방식을 알 수 있다.
▶ 정리
왜 나는 ... 람다 표현식을 썼을까. 애초에 모르는 걸 쓰는게 아니였는데, 코드가 너무 간결해지니까 단지 좋다고 그 이유 하나로만 썼다. 사실 for로 풀어도 그렇게 길어지지않는 코드기 때문에 굳이 람다를 쓸 필요는 없었다. ( 사실 간결서 라고 했다가 직접 풀어서써봐주시더니 그렇게 안 길어지는데 굳이? 란 소리를 들음). 본인 코드에 대해 설명하지 못하면 본인 꺼 아니라고 리뷰 때 마다 듣는 터라 꼭꼭 알아내야 했다. 람다표현식은 코드의 가독성을 높이고, 안전한 데이터 처리와 예외처리를 가능하게한다. 간결하고 유지보수성이 좋으니까... 앞으로는 람다표현힉을 쓰면 꼭 설명할 수 있기를..!
추가 +)
예시 코드 조각의 서비스클래스 전체코드
package com.sparta.memo.service;
import com.sparta.memo.dto.MemoRequestDto;
import com.sparta.memo.dto.MemoResponseDto;
import com.sparta.memo.entity.Memo;
import com.sparta.memo.repository.MemoRepository;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class MemoService {
private final MemoRepository memoRepository;
public MemoService(MemoRepository memoRepository) {
this.memoRepository = memoRepository;
}
public MemoResponseDto createMemo(MemoRequestDto requestDto) {
Memo memo = new Memo(requestDto);
memoRepository.save(memo);
return new MemoResponseDto(memo);
}
public List<MemoResponseDto> getMemos() {
return memoRepository.findAll().stream()
.map(MemoResponseDto::new)
.collect(Collectors.toList());
}
public MemoResponseDto getMemo(long id) {
return memoRepository.findById(id)
.map(MemoResponseDto::new)
.orElseThrow(() -> new IllegalArgumentException("Memo not found"));
}
public Long updateMemo(Long id, MemoRequestDto requestDto) {
Memo memo = memoRepository.findById(id)
.orElseThrow(() -> new IllegalArgumentException("Memo not found"));
memo.update(requestDto);
memoRepository.save(memo);
return memo.getId();
}
public Long deleteMemo(Long id, MemoRequestDto requestDto) {
Memo memo = memoRepository.findById(id)
.orElseThrow(() -> new IllegalArgumentException("Memo not found"));
memoRepository.delete(memo);
return memo.getId();
}
}
'개발Article' 카테고리의 다른 글
[TIL]20240718 /api를 두는 이유 (0) | 2024.07.19 |
---|---|
[TIL]20240717 RESTful의 의미 (0) | 2024.07.17 |
[TIL]20240715 제네릭의 와일드카드 <?> (0) | 2024.07.15 |
[WIL]20240714 (0) | 2024.07.14 |
[TIL]20240713 Entity에 @Setter어노테이션을 사용하지 않는 이유? (0) | 2024.07.14 |