프로젝트를 진행하면서 기존의 iterator를 써서 만들었던 코드가 다중 반복문이 너무 많다보니, 리팩토링을 해야되겠다고 생각을 해서 고쳐보려고 했는데 그 과정에서 애먹었던 부분이 있어서 기록으로 남기고자 했다. 그리고 아직 더 리팩토링을 해볼 생각이지만, 이것도 하나의 기록이 될 것 같아서 남겨야겠다고 생각했다.
우선 기존 코드의 경우
for (User user : userList) {
List<Pet> pets = user.getPets();
for (Pet pet : pets) {
if (!Objects.equals(pet.getUser().getId(), findUser.getId())) {
PetResponseDto petResponseDto = new PetResponseDto();
List<PetImg> petImg = pet.getPetImg();
List<String> urlList = petImg.stream()
.map(h -> new UrlDto(h.getS3Url()).getImageUrl())
.collect(Collectors.toList());
petResponseDto.setPetImg(urlList);
petResponseDto.setPetId(pet.getId());
petResponseDto.setName(pet.getPetName());
petResponseDto.setSex(pet.getGender());
petResponseDto.setBreed(pet.getBreed().getKorean());
petResponseDto.setIsNeuter(pet.getNeutralization());
petResponseDto.setTag(pet.getLikeTag(), pet.getDislikeTag());
petResponseDto.setAge(pet.getAge().getKorean());
result.add(petResponseDto);
}
}
}
위 코드는 반려견 관련해서 DB에서 반경 안에 있는 유저들을 찾고, 그 유저들이 가지고 있는 반려견에 대한 정보를 제공하기 위한 서비스 로직의 일 부분이다. 반경안에 있는 유저들을 다 찾고 그 유저들에 속한 강아지들이 다견일 경우가 있으므로 반복문을 돌려야 하기 때문에 2중 for문을 썼다. 이 부분도 나중에 바꿔야겠다고 생각을 했었지만, 그러던 중 이미지 관련해서 S3 에서 URL을 저장하는데 사진이 한장 이상의 경우를 고려하다보니, S3 URL을 리스트로 받았놨다. 그러다보니, 이미지를 빼낼 때도 반복문을 돌려야 된다는 것이었다. 그럼 3중 for문이 들어가는데, 아직 실력이 부족한 내가 봐도 이건 상도덕이 없는 행위같아서 그나마 검색을 통해서 stream을 써서 해봤는데 이건 그래도 아닌 것 같아서 그래도 괜찮은 건가 멘토님께 결국 여쭤봤다.
"3중 for문이든 몇중이든 사용할 수는 있다. 그런데 for문을 대체하기 위해서 이미 다중 for문인 상태에서 stream으로 하나를 바꾸는 게 크게 효율적이라고 할 순 없을 것 같다"
그래서 결국 flatMap을 쓰는 것을 추천해주셨다.
당시 내가 이해한 바로는 기존의 다중 리스트인 경우를 다 풀어놓고 거기서 해결하는 것으로 이해했는데 그 부분은 공부를 좀 더 해봐야 될 것 같다.
쨋든 나는 stream자체를 쓰는 것이 익숙지 않아서 하나하나씩 stream으로 바꿔가야겠다고 생각했다.
그래서 바꾼게 아래 코드다
for (User user : userList) {
List<Pet> pets = user.getPets();
List<PetResponseDto> collect = pets.stream()
.map(pet -> {
PetResponseDto dto = PetResponseDto.builder()
.name(pet.getPetName())
.petId(pet.getId())
.sex(pet.getGender())
.breed(pet.getBreed().getKorean())
.age(pet.getAge().getKorean())
.isNeuter(pet.getNeutralization())
.tag(new PetResponseDto.Tag(pet.getLikeTag(), pet.getDislikeTag()))
.build();
List<PetImg> petImg = pet.getPetImg();
List<String> petImgUrl = petImg.stream()
.map(a -> new UrlDto(a.getS3Url()).getImageUrl())
.collect(Collectors.toList());
dto.setPetImg(petImgUrl);
result.add(dto);
return dto;
}
).collect(Collectors.toList());
}
아직도 수정해야 된다. 무조건.
쨋든 이걸 기록하고자 쓴 글이 아니라, 위 코드에서 이 부분 때문에 쓴 글이다.
.tag(new PetResponseDto.Tag(pet.getLikeTag(), pet.getDislikeTag()))
태그 관련해서 클라이언트한테서 String으로 받아서 그 값을 조회할 때 리스트로 제공해야 되는데, 그 부분이 builder패턴을 쓰다보니, 인식을 못하던 거였다. 그래서 계속 애먹다가 결국 아래 처럼 코드를 바꿨다.
이게 dto에 있는 기존 코드들이었는데 이런식으로 생성자 호출을 통해서
private Tag tag = new Tag();
@Getter
@Setter
@NoArgsConstructor
public static class Tag {
private String[] tagLike;
private String[] tagDisLike;
}
public Tag(String tagLike, String tagDisLike) {
this.tagLike = tagLike;
this.tagDisLike = tagDisLike;
}
public void setTag(String tagLike, String tagDisLike) {
this.tag.setTagLike(getTags(tagLike));
this.tag.setTagDisLike(getTags(tagDisLike));
}
public static String[] getTags(String tags) {
String[] strArray = tags.split("[#,]");
List<String> strList = new ArrayList<>(Arrays.asList(strArray));
strList.removeAll(List.of(""));
strArray = strList.toArray(new String[0]);
return strArray;
}
이렇게 구성했었는데,
private Tag tag = new Tag();
@Getter
@Setter
@NoArgsConstructor
public static class Tag {
private String[] tagLike;
private String[] tagDisLike;
public Tag(String tagLike, String tagDisLike) {
this.tagLike = getTags(tagLike);
this.tagDisLike = getTags(tagDisLike);
}
}
public static String[] getTags(String tags) {
String[] strArray = tags.split("[#,]");
List<String> strList = new ArrayList<>(Arrays.asList(strArray));
strList.removeAll(List.of(""));
strArray = strList.toArray(new String[0]);
return strArray;
}
이렇게 바꿨다. 쉽게 기존 getTag는 그대로 썼지만, 변경된 점은 Tag 클래스 내부에서 생성자를 호출해서 그 안에서 getTags를 써서 생성자 내용을 조금 수정했다.
그래서
.tag(new PetResponseDto.Tag(pet.getLikeTag(), pet.getDislikeTag()))
이런식으로 빌더패턴에 생성자를 써서 따로 setter를 쓰지 않고 해결했다.
헷갈렸지만, 좀 더 수정해야된다. 까먹기 전에 기록부터 하다보니 자세한 내부적으로 어떤 로직을 통해서 그렇게 되는지 완전한 이해는 안됐지만 공부를 더 해봐야겠다.
유데미 스타터스 취업 부트캠프 2기 - 백엔드(java, 자바) 12주차 학습 일지 (0) | 2023.01.01 |
---|---|
유데미 스타터스 취업 부트캠프 2기 - 백엔드(java, 자바) 11주차 학습 일지 (0) | 2022.12.25 |
유데미 스타터스 취업 부트캠프 2기 - 백엔드(java, 자바) 10주차 학습 일지 (0) | 2022.12.18 |
유데미 스타터스 취업 부트캠프 2기 - 백엔드(java, 자바) 9주차 학습 일지 (0) | 2022.12.11 |
유데미 스타터스 취업 부트캠프 2기 - 백엔드(java, 자바) 8주차 학습 일지 (0) | 2022.12.04 |