[Java]익숙한 for each말고 Stream도 써봐야지
코드리뷰를 통해 익숙한 for each대신 Stream을 써보게되었다. 너무 재밌는 배움이라 기록하기로 마음먹었다.
정책상의 이유로 동일한 데이터를 서로 다른 User DB와 Wallet DB에 각각 저장하고 있다. 이 두 DB의 값들이 싱크가 맞는지 확인하는 메서드가 필요했다.
상황
User.java
1
2
3
4
5
6
public class User{
private int id;
private String name;
private int balance;
}Wallet.java
1
2
3
4
5
6
7
public class Wallet{
private int walletId;
private int userId;
private int balance;
private Boolean isAvailalbe;
}
내 코드
DiffVO를 담을 객체를 구현하고 User 디비를 호출해서 userDBValue에 셋팅하고 Wallet를 호출해서 walletDBValue에 셋팅한 뒤 if조건문으로 두 값을 비교해서 같으면 isTheSame = true로 바꿔주도록 구현했다.
주의점은 User 디비 호출메서드 리턴데이터타입(User)과 Wallet 디비 호출메서드 리턴데이터타입(List)이 다르게 고정되어 있다는 점이다.
DiffVO.java
1
2
3
4
5
6
public class DiffVO{
private int userDBValue;
private int walletDBValue;
private Boolean isTheSame = false; // 디폴트 false로
}service
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26public testService{
private DiffVO checkTheSameValue(int id){
DiffVO diffInfo = new DiffVO();
// 1. A디비 값 가져오기
User userInfo = dao.selectUserInfo(id);
diffInfo.setUserDBValue(userInfo.getBalance());
// 2. B디비 값 가져오기
List<Wallet> walletInfo = balanceAllWallet(); // 기 구현된 서비스 balanceAllWallet()이용 필수
for(Wallet w : walletInfo){
if(w.getUserId() == id){
diffInfo.setWalletDBValue(w.getBalance());
}
}
// 3. 비교하기
if(diffInfo.getUserDBValue() == diffInfo.getWalletDBValue()){
diffInfo.setIsTheSame(true);
}
return diffInfo;
}
}
3단계로 비교했다. 팀장님이 내 코드를 보시곤 Stream을 사용하는 건 어떻겠냐고 말씀해주셨다.
팀장님 코드
내 코드는 for each문이고 팀장님은 stream을 사용하셨다.
stream에 대한 자세한 설명은 블로그 글 - 스트림 API 개념에 엄청 친절하게 적어놓았다.
stream을 써보고싶었는데 익숙한 for 문만 쓰다 이렇게 코드리뷰하다가 쓰게되니 무척 재밌었다. 너무 재밌어!
- service
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// (중략)
// 2. B디비 값 가져오기 -> 코드리뷰
List<Wallet> walletInfo = balanceAllWallet(); // 기 구현된 서비스 balanceAllWallet()이용 필수
Stream<Wallet> walletStream = walletInfo.stream().filter(d -> id.equals(d.getUserId()));
Wallet wallet = walletInfo.findFirst().orElse(null);
diffInfo.setWalletDBValue(wallet.getBalance());
// 3. 비교하기
if(diffInfo.getUserDBValue() == diffInfo.getWalletDBValue()){
diffInfo.setIsTheSame(true);
}
return diffInfo;
Stream을 쓰니 가독성도 좋아졌다.
여담이지만 팀장님은 정말 천재같다.
스트림과 for반복문 어느 것이 더 좋을까?
이렇게 스트림을 쓰고나니 for문과 비교해서 뭐가 더 좋은지가 궁금했다. 여러 구글링 끝에 흥미로운 미디엄 글 Sigrid Jin님의 Java Stream API는 왜 for-loop보다 느릴까?를 찾았다.
오늘의 결론이다. 스트림 사용이 for-loop보다 의미가 있으려면 Collection이 되는 스트림 소스의 크기가 충분히 크거나, 컴퓨팅 연산이 CPU-intensive할 정도로 비용이 매우 비싸야 한다. 병렬 스트림을 사용하려면, 스트림 소스인 Collection은 split하기 쉬운 자료 구조이어야 하며, 웬만해서는 연산이 stateful하지 않아야 한다. 성능차이는 개발자의 로컬환경에 따라 다를 수 있다.