티스토리 뷰
728x90
반응형
문제 발단
프로젝트에서 얕은 복사와 깊은 복사에 대한 이해도가 적어 애먹은 부분이 있다
먼저 내가 문제가 되었던 알고리즘에 대하여 먼저 얘기해 보자면
어떤 쇼핑몰의 장바구니 로컬 스토리지 처리 관련된 문제이다...
기존 방식: 상품번호가 일치하면 상품번호에 대한 데이터를 중복체크해서 등록이 불가능하도록하는 것
변경된 방식: 장바구니에는 담는데로 담기게 하였다.
그러므로 발생하는 것은 로컬스토리지에 저장되어 장바구니에 표출하던 데이터는 로컬 스토리지에 저장된 상품 번호를 조회하여 그에 대한 상품 정보를 장바구니에 표출하는 형태였는데
중복체크를 안하도록 하는 방식으로 변경 되면서 기존 프로세스로는 장바구니에 중복 정보를 표출할 수 없게 되었습니다.(왜냐하면 상품번호에 해당하는 데이터는 하나의 pk를 가지기 때문...)
그래서 상품 번호를 조회해서 가져온 리스트를 필터를 하여 로컬 스토리지에 저장된 데이터를 일일이 새로운 리스트에 담아주는 방식으로 표출하는 형식을 선택했다.
ex)
로컬 스토리지에 담긴 데이터
여기서 보면 prodNum는 상품번호에 해당 -> 같은 번호로 리스트가 담긴것을 확인 가능
기존 프로세스로는 이 두개의 데이터를 나눠서 출력이 안되도록 했었음...
그래서 변경하여 생각한 알고리즘
int index = 0;
//상품 체크
for(String prodNum : prodNumList) {
DojaMallProductVO vo = new DojaMallProductVO();
// 로컬 스토리지에 등록되어있는 상품번호들을 조회한 리스트에서 현재 반복문에 해당하는 prodNum을 필터로 하여 VO를 가져와서 데이터를 비교
vo = list.stream().filter(p->p.getProdNum().equals(prodNum)).findFirst().orElseThrow(() -> new NullPointerException()); //이놈이 문제?? 인듯??
List<DojaMallProductItemOptionVO> itemList = new ArrayList<DojaMallProductItemOptionVO>();
//로컬 상품에 상품 옵션 추가
//위에서 sno, count 맵핑한 리스트를 이용하여 resultList item optionVO 객체에 다가 개수 추가
for(Map<String,String> temp : prodMap.get(vo.getProdNum()+"_"+index)) {
for(DojaMallProductItemOptionVO item : vo.getItemList()) {
if(item.getSno() == Integer.parseInt(temp.get("sno"))) {
DojaMallProductItemOptionVO itemVO = new DojaMallProductItemOptionVO();
...
ctrLog.debug("@@@@@ {} ",itemList);
}
}
}
if(index > 0) {
ctrLog.debug("####@!!!!!!!!!!!!!!!!!!!!! {} ",resultList.get(0).getItemList().size());
}
vo.setItemList(itemList); //여기가 문제되는 부분
if(index > 0) {
ctrLog.debug("####@2222!!!!!!!!!!!!!!!!!!!!! {} ",resultList.get(0).getItemList().size());
}
...
resultList.add(vo);
ctrLog.debug("@!!!!!!!!!!!!!!!!!!!!! {} ",resultList.get(0).getItemList().size());
if(index > 0) {
ctrLog.debug("@!!!!!!!!!!!!!!!!!!! : {}",resultList.get(1).getItemList().size());
}
index++;
ctrLog.debug("--------------------------------");
}
map.put("result","success");
map.put("resultList",resultList);
결과 :
원하던 결과는
위의 로컬 스토리지에 담긴 리스트 사진처럼 장바구니 리스트에는 2개의 데이터가 나오고 첫번째 상품에는 2개 옵션을 가진 정보가 두번째 상품에는 하나의 옵션 정보를 가진 데이터가 나와야한다.
결과는 두번째 데이터가 리스트에 두번 나오게 됨!!??? 첫번째 상품정보는 사라짐;; 뭐지..
왜그럴까??
여기 보면 "@@@@@@@VO :" 에 해당하는 결과 값을 보게 되면 두개의 경우 서로 같은 주소값을 공유하고 있는 것을 알 수 있다. 이런 문제로 인해 첫번째 리스트정보에 덮어쓰기가 되버리는 문제가 발생했다....
그러면 어디서 문제가 되는걸까? 왜 resultList에는 처음에는 잘들어가다가 마지막 데이터로 누적되서 들어가는가????
그 이유는 여기에 있다. vo = list.stream().filter(p->p.getProdNum().equals(prodNum)).findFirst().orElseThrow(() -> new NullPointerException()); 여기서 우리는 반복문을 돌기때문에 새로 vo가 생성되는 걸로 알고 있음
하지만 list에서 필터를 하다보니 얕은 복사 개념으로 주소값만을 복사해온 상황이 된다. 이렇게 되면 처음에 등록된 vo 정보가 변경되는 상황이 발생한다..
이 부분을 해결하기 위해서 깊은 복사 개념을 사용한다.
여기서 개념적인 차이를 느낀... 객체는 주소값을 공유하고 있다는것을 간과하고 있었다는 부분이다..
그렇기에 최종 resultList 에 담기는 itemList 정보들이 마지막 정보이 등록되는 문제가 있었던것 그러므로 얕은 복사가 아닌 깊은 복사를 사용해야함
문제가 되던 부분
주소값만 가져왔던거라 문제가 발생했던것
여기서 우리가 사용할 것은 복사 생성기 또는 복사팩토리이다.
코드)
DojaMallProductVO vo = list.stream().filter(p->p.getProdNum().equals(prodNum.split("_")[0])).findFirst().orElseThrow(() -> new NullPointerException());
기존의 DojaMallProductVO 에 복사 생성기 또는 복사 팩토리를 만든다.
public class DojaMallProductVO {
......
/**복사 생성자*/
public DojaMallProductVO(DojaMallProductVO original) {
this.prodNum = original.getProdNum();
this.prodName = original.prodName;
this.price = original.price;
this.sale = original.sale;
this.saleType=original.saleType;
this.listImage = original.listImage;
this.itemList = original.getItemList();
this.colorList = original.getColorList();
this.sellStatus = original.sellStatus;
this.sellOption = original.sellOption;
this.shippFee= original.shippFee;
this.shippIfFee = original.shippIfFee;
}
/**복사 팩터리*/
public static DojaMallProductVO copy(DojaMallProductVO original) {
DojaMallProductVO copy = new DojaMallProductVO();
copy.prodNum = original.getProdNum();
copy.prodName = original.prodName;
copy.price = original.price;
copy.sale = original.sale;
copy.saleType=original.saleType;
copy.listImage = original.listImage;
copy.itemList = original.getItemList();
copy.colorList = original.getColorList();
copy.sellStatus = original.sellStatus;
copy.sellOption = original.sellOption;
copy.shippFee= original.shippFee;
copy.shippIfFee = original.shippIfFee;
return copy;
}
}
이렇게 복사를 하여 새로운 생성자로 등록 또는 static 을 생성 하는 것이다.
코드)
DojaMallProductVO vo = list.stream().filter(p->p.getProdNum().equals(prodNum.split("_")[0])).findFirst().orElseThrow(() -> new NullPointerException());
DojaMallProductVO copyVO = new DojaMallProductVO(vo);//복사 생성기를 이용한 경우
DojaMallProductVO copy2VO = DojaMallProductVO.copy(vo); //복사 팩토리를 이용한 경우
결과 :
여기서 보면 위에 데이터에서 "@@@@@VO : " 에 해당하는 주소값들이 다르다는 것을 알 수 있다. 즉 DojaMallProductVO 가 다르다는 것 이렇게 되므로써 복사가 완벽하게 이루어짐을 알 수 있다.
느낀점 :
이런 문제는 개념적인 부분에 해당한다.
데이터를 복사한다 했을 때 특히 객체,리스트,배열 같은 경우 주소값을 공유하므로서 문제가 자주 발생할 수 있다.
이번 일을 통해 얕은 복사의 개념과 깊은 복사의 개념을 다시 배우는 시간이 되었다.
728x90
반응형
'프로그램 언어 > JAVA' 카테고리의 다른 글
자바(자바) stream 특정 key 값 중복 제거 처리 방 (0) | 2023.05.02 |
---|---|
자바(java) stream Map 그룹만들기 ,내림차순 정렬 , 더하기 (0) | 2023.05.02 |
java xml 정보 Sax 방식을 이용한 파싱 방법 (0) | 2023.05.02 |
클라이언트 실제 접속 IP 가져오는 방법 (0) | 2023.05.02 |
java 엑셀 파일 읽기 대용량 문제 처리 방법 part2 (1) | 2023.05.02 |
250x250
반응형
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- centos7
- Linux
- 정의
- 개념 이해하기
- LocalDate
- 격리수준
- 네이버 클라우드
- 권한
- dfs
- docker
- insert
- leatcode
- 알고리즘
- 스케줄러
- 리눅스
- 이미지
- hazelcast
- Cache
- Lock
- 도커
- MySQL
- dockerfile
- 컨테이너
- Java
- mybatis
- spring
- ncp
- Quartz
- 캐시
- 캘린더
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
26 | 27 | 28 | 29 | 30 | 31 |
글 보관함