cancelOrder(int orderId)를 추가하라. 해당 주문의 항목마다 재고를 되돌리고, orders 배열에서 그 주문을 제거한 뒤 뒤쪽 원소를 한 칸씩 앞으로 당겨 빈틈을 없애야 한다. 없는 주문이면 [실패] 존재하지 않는 주문: N을 출력한다. Product에 increaseStock(int)를 추가해야 한다.
// Product.java에 추가
public void increaseStock(int qty) { stock += qty; }
// Main.java에 추가
static void cancelOrder(int orderId) {
int index = -1;
for (int i = 0; i < orderCount; i++) {
if (orders[i].getId() == orderId) { index = i; break; }
}
if (index < 0) {
System.out.println("[실패] 존재하지 않는 주문: " + orderId);
return;
}
Order o = orders[index];
for (int j = 0; j < o.getLineCount(); j++) {
findProduct(o.getProductId(j)).increaseStock(o.getQuantity(j)); // 재고 복구
}
for (int i = index; i < orderCount - 1; i++) {
orders[i] = orders[i + 1]; // 한 칸씩 앞으로 (ArrayList.remove가 하는 일)
}
orders[orderCount - 1] = null; // 마지막 칸 비우기
orderCount--;
System.out.println("주문 취소: #" + orderId);
}ArrayList.remove(index)가 내부에서 System.arraycopy로 하는 일을 손으로 쓴 것이다. 원소를 당기는 루프가 O(n)인 이유가 코드에 보인다.
MAX_ORDERS를 없애고, 주문 배열이 가득 차면 1.5배 크기의 새 배열을 만들어 기존 내용을 복사한 뒤 계속 저장하도록 createOrder를 고쳐라. java.util.Arrays.copyOf를 써도 되고 직접 루프를 돌려도 된다. 확장이 일어날 때 배열 확장: 3 → 4처럼 로그를 남겨라.
// 정답: 확장 전용 메서드
static void ensureOrderCapacity() {
if (orderCount < orders.length) return;
int newCapacity = orders.length + (orders.length >> 1); // 1.5배 (ArrayList와 같은 정책)
if (newCapacity == orders.length) newCapacity++; // 길이 1일 때 방어
Order[] bigger = new Order[newCapacity];
for (int i = 0; i < orderCount; i++) bigger[i] = orders[i];
System.out.println("배열 확장: " + orders.length + " → " + newCapacity);
orders = bigger;
}
// createOrder에서 "주문 저장 공간이 가득 찼습니다" 검사 대신:
// ensureOrderCapacity();
// ... (검증) ...
// orders[orderCount] = order;orders는 static Order[]이므로 final이 아니어야 재할당할 수 있다. 이 12줄이 ArrayList.add의 핵심이고, 2단계에서는 이 코드를 통째로 new ArrayList<>()로 바꾼다.
printSalesByCategory()를 추가하라. 상품의 카테고리별로 매출 합계를 출력해야 한다. 컬렉션 없이 하려면 "지금까지 본 카테고리 이름"을 String[]에, 합계를 같은 인덱스의 int[]에 모으는 병렬 배열이 필요하다. 카테고리는 최대 10개로 가정한다. 출력 순서는 처음 등장한 순서.
// 정답
static void printSalesByCategory() {
String[] names = new String[10];
int[] sums = new int[10];
int count = 0;
for (int i = 0; i < orderCount; i++) {
Order o = orders[i];
for (int j = 0; j < o.getLineCount(); j++) {
Product p = findProduct(o.getProductId(j));
int amount = p.getPrice() * o.getQuantity(j);
int idx = -1; // 카테고리 위치 찾기 (선형 탐색)
for (int k = 0; k < count; k++) {
if (names[k].equals(p.getCategory())) { idx = k; break; }
}
if (idx < 0) { // 처음 보는 카테고리
names[count] = p.getCategory();
idx = count;
count++;
}
sums[idx] += amount;
}
}
for (int k = 0; k < count; k++) {
System.out.println("카테고리별 매출: " + names[k] + " " + format(sums[k]) + "원");
}
}
// 출력 (3.7의 데이터 기준):
// 카테고리별 매출: 전자 83,000원
// 카테고리별 매출: 도서 32,000원
// 카테고리별 매출: 생활 45,000원"이름 배열에서 위치를 찾고, 없으면 끝에 추가하고, 그 위치의 합계에 더한다" — 이것이 Map.merge(category, amount, Integer::sum) 한 줄이 하는 일이다. 2단계에서 직접 비교해 본다.