[문제]
package com.spring.weekthree.repository;
import com.spring.weekthree.dto.PlanResponseDto;
import com.spring.weekthree.entity.Plan;
import org.springframework.stereotype.Repository;
import java.time.LocalDate;
import java.util.*;
// Data Access Layer(Repository Layer)
@Repository
public class PlanRepositoryImpl implements PlanRepository {
// 속성
private final Map<Long, Plan> planList = new HashMap<>();
// 생성자
// 기능
@Override
public Plan save(Plan plan) {
Long planId = planList.isEmpty() ? 1 : Collections.max(planList.keySet()) + 1;
plan.setId(planId);
planList.put(planId, plan);
return plan;
}
@Override
public List<PlanResponseDto> fetchAllPlans(String name, LocalDate updatedDate) {
List<PlanResponseDto> allPlans = new ArrayList<>();
if (name != null) {
for (Plan plan : planList.values()) {
if (plan.getName().equals(name)) {
allPlans.add(new PlanResponseDto(plan));
}
}
} else if (updatedDate != null) {
for (Plan plan : planList.values()) {
if (plan.getUpdatedDateTime().toLocalDate().equals(updatedDate)) {
allPlans.add(new PlanResponseDto(plan));
}
}
} else if ((name != null) && (updatedDate != null)) {
/*
[문제]
노란 줄이 뜬 부분
마우스로 가리키면 조건식이 항상 false라는 문구가 떴다.
*/
for (Plan plan : planList.values()) {
if ((plan.getUpdatedDateTime().toLocalDate().equals(updatedDate))
&& (plan.getName().equals(name))) {
allPlans.add(new PlanResponseDto(plan));
}
}
} else {
for (Plan plan : planList.values()) {
PlanResponseDto responseDto = new PlanResponseDto(plan);
allPlans.add(responseDto);
}
}
return allPlans;
}
@Override
public Plan fetchPlanById(Long id) {
return planList.get(id);
}
@Override
public void deletePlan(Long id) {
planList.remove(id);
}
}
전체 일정을 조회하는 기능을 구현할 때 '수정일'과 '작성자명'을 모두 충족하거나, 둘 다 충족하지 않거나, 둘 중 하나를 충족할 때 각각 목록을 조회할 수 있도록 구현해야 했다. 이때 조건을 어떻게 해야 할지 몰라 우선 CRUD 기능을 구현한 다음 리팩토링(refactoring)하는 식으로 조건을 추가했다. 작성자명인 name이 null이 아닐 때와 수정일인 updatedDate가 null이 아닐 때, 즉 값이 있을 때 저장된 값과 동일한 일정을 목록으로 뽑아내도록 했는데, 갑자기 노란 줄이 떴다.
[원인]
package com.spring.weekthree.repository;
import com.spring.weekthree.dto.PlanResponseDto;
import com.spring.weekthree.entity.Plan;
import org.springframework.stereotype.Repository;
import java.time.LocalDate;
import java.util.*;
// Data Access Layer(Repository Layer)
@Repository
public class PlanRepositoryImpl implements PlanRepository {
// 속성
private final Map<Long, Plan> planList = new HashMap<>();
// 생성자
// 기능
@Override
public Plan save(Plan plan) {
Long planId = planList.isEmpty() ? 1 : Collections.max(planList.keySet()) + 1;
plan.setId(planId);
planList.put(planId, plan);
return plan;
}
@Override
public List<PlanResponseDto> fetchAllPlans(String name, LocalDate updatedDate) {
List<PlanResponseDto> allPlans = new ArrayList<>();
/*
[첫 번째]
- name이 null이 아니면 조건식이 true가 된다.
- name이 null이면 false이므로 다음 조건문으로 넘어간다.
*/
if (name != null) {
for (Plan plan : planList.values()) {
if (plan.getName().equals(name)) {
allPlans.add(new PlanResponseDto(plan));
}
}
/*
[두 번째]
- if문이 실행되지 않았으므로 name은 null이다.
- updatedDate가 null이 아니면 조건식이 true가 된다.
- updatedDate가 null이면 false이므로 다음 조건문으로 넘어간다.
*/
} else if (updatedDate != null) {
for (Plan plan : planList.values()) {
if (plan.getUpdatedDateTime().toLocalDate().equals(updatedDate)) {
allPlans.add(new PlanResponseDto(plan));
}
}
/*
[세 번째]
Q. 그렇다면 세 번째에 도달했다는 말은?
A. 첫 번째 조건식도 false가 되었고,
두 번째 조건식도 false가 되었단 뜻이다.
즉, 이미 name도 null이고 updatedDate도 null이란 뜻이다.
*/
} else if ((name != null) && (updatedDate != null)) {
for (Plan plan : planList.values()) {
if ((plan.getUpdatedDateTime().toLocalDate().equals(updatedDate))
&& (plan.getName().equals(name))) {
allPlans.add(new PlanResponseDto(plan));
}
}
} else {
for (Plan plan : planList.values()) {
PlanResponseDto responseDto = new PlanResponseDto(plan);
allPlans.add(responseDto);
}
}
return allPlans;
}
@Override
public Plan fetchPlanById(Long id) {
return planList.get(id);
}
@Override
public void deletePlan(Long id) {
planList.remove(id);
}
}
원인은 논리 흐름, 즉 로직(logic)이 위에서 아래로 흐른다는 데에 있었다. 주석으로 적었다시피, 두 번째 else if문의 ((name != null) && (updatedDate != null)) 조건식에 이를 때에는 이미 (name != null) 조건식도 false이고, (updatedDate != null) 조건식도 무조건 false일 수밖에 없었다. 앞에서 조건식이 true였으면 메서드(method)가 실행되었을 테니까.
[해결]
① if문과 else if문의 조건식 수정하기
package com.spring.weekthree.repository;
import com.spring.weekthree.dto.PlanResponseDto;
import com.spring.weekthree.entity.Plan;
import org.springframework.stereotype.Repository;
import java.time.LocalDate;
import java.util.*;
// Data Access Layer(Repository Layer)
@Repository
public class PlanRepositoryImpl implements PlanRepository {
// 속성
private final Map<Long, Plan> planList = new HashMap<>();
// 생성자
// 기능
@Override
public Plan save(Plan plan) {
Long planId = planList.isEmpty() ? 1 : Collections.max(planList.keySet()) + 1;
plan.setId(planId);
planList.put(planId, plan);
return plan;
}
@Override
public List<PlanResponseDto> fetchAllPlans(String name, LocalDate updatedDate) {
List<PlanResponseDto> allPlans = new ArrayList<>();
if ((name != null) && (updatedDate == null)) {
/*
[수정 전]
if (name != null)
[수정 후]
if ((name != null) && (updatedDate == null))
*/
for (Plan plan : planList.values()) {
if (plan.getName().equals(name)) {
allPlans.add(new PlanResponseDto(plan));
}
}
} else if ((name == null) && (updatedDate != null)) {
/*
[수정 전]
if (updatedDate != null)
[수정 후]
else if ((name == null) && (updatedDate != null))
*/
for (Plan plan : planList.values()) {
if (plan.getUpdatedDateTime().toLocalDate().equals(updatedDate)) {
allPlans.add(new PlanResponseDto(plan));
}
}
} else if ((name != null) && (updatedDate != null)) {
for (Plan plan : planList.values()) {
if ((plan.getUpdatedDateTime().toLocalDate().equals(updatedDate))
&& (plan.getName().equals(name))) {
allPlans.add(new PlanResponseDto(plan));
}
}
} else {
for (Plan plan : planList.values()) {
PlanResponseDto responseDto = new PlanResponseDto(plan);
allPlans.add(responseDto);
}
}
return allPlans;
}
@Override
public Plan fetchPlanById(Long id) {
return planList.get(id);
}
@Override
public void deletePlan(Long id) {
planList.remove(id);
}
}
노란 줄이 뜬 부분은 true로 고칠 수 있었지만, 어느 부분이 true인지 잘 보이도록 그대로 두었다. 문제는 if문과 향상된 for문을 사용할수록 코드가 한눈에 보이지 않았다. 소괄호가 두 개, 세 개 겹치니까 이미 내 마음에 들지 않는다는 점을 튜터님도 눈치채신 걸까? 두 번째 해결책을 쓰기로 했다.
② 스트림(Stream) 사용하기
package com.spring.weekthree.repository;
import com.spring.weekthree.dto.PlanResponseDto;
import com.spring.weekthree.entity.Plan;
import org.springframework.stereotype.Repository;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Stream;
// Data Access Layer(Repository Layer)
@Repository
public class PlanRepositoryImpl implements PlanRepository {
// 속성
private final Map<Long, Plan> planList = new HashMap<>();
// 생성자
// 기능
@Override
public Plan save(Plan plan) {
Long planId = planList.isEmpty() ? 1 : Collections.max(planList.keySet()) + 1;
plan.setId(planId);
planList.put(planId, plan);
return plan;
}
@Override
public List<PlanResponseDto> fetchAllPlans(String name, LocalDate updatedDate) {
Stream<PlanResponseDto> allPlans;
allPlans = planList.values().stream().map(PlanResponseDto::new);
if (name != null) {
allPlans = allPlans.filter(x -> x.getName().equals(name)
);
}
if (updatedDate != null) {
allPlans = allPlans.filter(y -> {
return y.getUpdatedDateTime().toLocalDate().equals(updatedDate);
}
);
}
return allPlans.toList();
}
@Override
public Plan fetchPlanById(Long id) {
return planList.get(id);
}
@Override
public void deletePlan(Long id) {
planList.remove(id);
}
}
확실히 if문을 썼을 때보다 간결하고 논리 흐름이 한눈에 보여서 마음에 들었다. 대신 스트림(Stream)이 무엇인지 강의를 듣지 않았기 때문에, 튜터님들이 알려주신 개념과 특징을 바탕으로 꼭 공부하기로 했다. 역시 코드를 더 잘 쓰려면, 다양한 작성 방법을 알려면 그 방법을 익혀야 했다. 너무나 먼 얘기이고 언제 접하기는 할까 싶은 스트림에 한 발짝 다가선 느낌이 들었다.
[결과 수치화]
[수정 전] 자바(Java) 인텔리제이(IntelliJ) 노란 줄 경고 표시 1개 발생
[수정 후] 자바(Java) 인텔리제이(IntelliJ) 노란 줄 경고 표시 0개 발생
'Troubleshooting: 무엇이 문제였는가? > 본캠프 3주 차: 일정 관리 앱 만들기' 카테고리의 다른 글
2단계: "왜 수정 날짜를 수정하려고 하니!" (0) | 2024.12.08 |
---|---|
1단계: "@NoArgsConstructor가 굴린 대형 눈덩이" (0) | 2024.12.08 |
2단계: "500 Internal Server Error라니! 일단 침착해!" (0) | 2024.12.07 |
2단계: "꿈쩍 안 하는 수정일과 얼음땡!" (0) | 2024.12.06 |
1단계: "컴퓨터가 200 OK라는데 [ ] 밖에 안 보여요." (0) | 2024.12.06 |