
저번 과제에서는 어떻게 시작해야 될지도 모르고 단계별로 차근차근 못했는데 이번에는 단계별로 차근차근 해 볼 생각이다.
🚩STEP 1 - 객체지향 설계를 적용해 상품 관리 시스템을 프로그래밍 해 보자
1️⃣ `product` 클래스 생성하기
// 상품 1개의 정보를 담는 클래스(설계도)
public class Product {
// 필드 - 이 객체가 가지고 있어야 하는 정보를 저장하는 변수
String name; // 상품명
int price; // 가격
String descrption; // 설명
int stock; // 재고 수량
// 생성자
public Product(String name, int price, String descrption, int stock) {
this.name = name;
this.price = price;
this.descrption = descrption;
this.stock = stock;
}
}
1) 클래스(class) = 설계도
- `product` 클래스는 상품 하나가 어떤 정보를 가져야 하는지 정의한 설계도
- 이 설계도를 기반으로 실체 상품을 만들면 그게 객체
2) 객체(object) = 실제 만들어진 상품
3) 필드(field) = 객체의 데이터
- 여기서는 `name`, `price`, `description`, `stock` 이 상품이 무슨 상품인지 설명
4) 생성자(constructor) = 객체 만들 때 최초 세팅을 담당한다
- 생성자는 클래스 이름이랑 똑같다
- 반환 타입이 없다 (`void`가 안 붙음)
- `new Product()` 할 때 자동 실행된다
2️⃣ `main` 함수에서 `Product` 클래스를 생성하여 상품 목록을 추가
상품은 여러 개가 있어야 목록이 된다
-> 그 여러 개의 `Product`를 어디에 담아야 되는가?
-> `List` 순서가 있고 개수 늘어날 수 있다
public class Main {
public static void main(String[] args) {
// 프로그램 시작 출력
System.out.println("[ 실시간 커머스 플랫폼 - 전자제품]");
// 여러 Product를 담기 위한 List 생성
List<Product> products = new ArrayList<>();
// Product 객체 생성을 하고 List에 추가한다
// new Produc()를 이용해서 실제 상품 객체를 생성한다
products.add(new Product("Galaxy S25", 1200000, "최신 안드로이드 스마트폰", 50));
products.add(new Product("iPhone 16", 1350000, "Apple의 최신 스마트폰", 30));
products.add(new Product("MacBook Pro", 2400000, "M3 칩셋이 탑재된 노트북", 20));
products.add(new Product("AirPods Pro", 350000, "노이즈 캔슬링 무선 이어폰", 100));
}
}
1) `List<Product>`
- `List` = 여러 개를 담는 통
- `<Product>` = 이 리스트에는 Product만 담겠다는 약속 (제네릭)
2) `ArrayList`
- `List`는 인터페이스(규칙)이고
- `ArrayList`는 그 규칙을 실제로 구현한 클래스
3) `new Product()`
- `new` = 메모리에 객체를 만든다
- 생성자가 실행되면서 필드들이 세팅됨
- 이때 상품 1개가 만들어짐
4) `List<Product> products = new Array List<>();`
왼쪽(`List`) -> USB-C 규격 / 기능 -> 이 변수는 List로 쓰겠다
오른쪽(`ArrayList`) -> 삼성 충전기 / 구현체 -> 이걸로 만들겠다!
- List는 여러 객체를 관리하기 위한 자료구조
- `List<타입>`을 사용하면 해당 타입만 담을 수 있음
- `new` 키워드는 객체를 메모리에 생성함
Array vs List 차이 정리
| 구분 | Array | List |
| 크기 | 고정 | 유동 |
| 데이터 추가 | 불편 | 쉬움 |
| 삭제 | 불편 | 쉬움 |
| 실무 사용 | 제한적 | 매우 많음 |
👉 실무에서는 대부분 List 사용
3️⃣ 반복문으로 상품 목록 출력
1번부터 번호를 붙여서 각 상품의 name / price / descrption을 한 출로 출력
-> 리스트에 든 걸 하나씩 꺼내서 출력
// 상품명을 외부에서 읽을 수 있게 해 주는 getter
public String getName() {
return name;
}
// 가격을 외부에서 읽을 수 있게 해 주는 getter
public int getPrice() {
return price;
}
// 설명을 외부에서 읽을 수 있게 해 주는 getter
public String getDescription() {
return description;
}
Product 클래스에 getter 추가
// 상품 목록 출력
for (int i = 0; i < products.size(); i++) {
// 리스트에서 i 번째 상품을 꺼낸다
Product product = products.get(i);
int menuNumber = i + 1;
// 메뉴판 출력
System.out.println(menuNumber + ". " + product.getName()
+ " | " + product.getPrice() + "원"
+ " | " + product.getDescription());
}
// 종료
System.out.println("0. 종료 | 프로그램 종료");
main에 반복문 출력 추가
- for문은 리스트 크기만큼 반복한다
- `get(i)`로 i번째 요소를 꺼낸다
- 사용자 메뉴 번호랑 인덱스는 다르다 그래서 `i + 1`이 필요하다
4️⃣ 입력을 받고 0이면 종료
1. 메뉴를 출력
2. 입력을 받고
3. 0이면 종료 메시지 출력 후 끝내야 되고?
4. 0 아니면 일단은 지원하지 않는다고 하고 다시 메뉴로......
package com.example.commerce;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// 사용자 입력을 받기 위한 Scanner
Scanner sc = new Scanner(System.in);
// 여러 Product를 담기 위한 List 생성
List<Product> products = new ArrayList<>();
// Product 객체 생성을 하고 List에 추가한다
// new Produc()를 이용해서 실제 상품 객체를 생성한다
products.add(new Product("Galaxy S25", 1200000, "최신 안드로이드 스마트폰", 50));
products.add(new Product("iPhone 16", 1350000, "Apple의 최신 스마트폰", 30));
products.add(new Product("MacBook Pro", 2400000, "M3 칩셋이 탑재된 노트북", 20));
products.add(new Product("AirPods Pro", 350000, "노이즈 캔슬링 무선 이어폰", 100));
// 프로그램을 계속 돌릴지 결정하는 변수
boolean run = true;
// run이 true인 동안 계속 반복
while (run) {
// 프로그램 시작 출력
System.out.println("[ 실시간 커머스 플랫폼 - 전자제품]");
// 상품 목록 출력
for (int i = 0; i < products.size(); i++) {
// 리스트에서 i 번째 상품을 꺼낸다
Product product = products.get(i);
int menuNumber = i + 1;
// 메뉴판 출력
System.out.println(menuNumber + ". " + product.getName()
+ " | " + product.getPrice() + "원"
+ " | " + product.getDescription());
}
// 종료
System.out.println("0. 종료 | 프로그램 종료");
// 입력 받음
System.out.print("선택> ");
int choice = sc.nextInt();
// 입력 처리
if (choice == 0) {
System.out.println("커머스 플랫폼을 종료합니다");
run = false;
} else {
System.out.println("아직 안 돼요 ㅜ");
}
System.out.println();
}
sc.close();
}
}
package com.example.commerce;
// 상품 1개의 정보를 담는 클래스(설계도)
public class Product {
// 필드 - 이 객체가 가지고 있어야 하는 정보를 저장하는 변수
private String name; // 상품명
private int price; // 가격
private String description; // 설명
private int stock; // 재고 수량
// 생성자
public Product(String name, int price, String description, int stock) {
this.name = name;
this.price = price;
this.description = description;
this.stock = stock;
}
// 상품명을 외부에서 읽을 수 있게 해 주는 getter
public String getName() {
return name;
}
// 가격을 외부에서 읽을 수 있게 해 주는 getter
public int getPrice() {
return price;
}
// 설명을 외부에서 읽을 수 있게 해 주는 getter
public String getDescription() {
return description;
}
// 재고를 외부에서 읽을 수 있게 해 주는 getter
public int getStock() {
return stock;
}
}
- `while`로 메뉴를 일단 반복 출력하게 만들었다
- `choice == 0`일 때 `run = false`로 반복 종료하게 만들었다
- `Scanner.nextInt()`로 입력을 받게 만듦

🚩STEP 2 - 객체 지향 설계를 적용해 순서 제어를 클래스로 관리하기
- Main: 준비 담당(시작 버튼)
- CommerceSystem: 운영 담당(실제로 일하는 사람)
- products(List<Product>): 준비물(상품 목록)
Main이 준비물을 만들어서 CommerceSystem에게 주고, CommerceSystem은 그 준비물로 프로그램을 운영함
package com.example.commerce;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
// 여러 Product를 담기 위한 List 생성
List<Product> products = new ArrayList<>();
// Product 객체 생성을 하고 List에 추가한다
// new Produc()를 이용해서 실제 상품 객체를 생성한다
products.add(new Product("Galaxy S25", 1200000, "최신 안드로이드 스마트폰", 50));
products.add(new Product("iPhone 16", 1350000, "Apple의 최신 스마트폰", 30));
products.add(new Product("MacBook Pro", 2400000, "M3 칩셋이 탑재된 노트북", 20));
products.add(new Product("AirPods Pro", 350000, "노이즈 캔슬링 무선 이어폰", 100));
// products를 CommerceSystem에 넘겨줌
new CommerceSystem(products).start();
}
}
package com.example.commerce;
import java.util.List;
import java.util.Scanner;
public class CommerceSystem {
// Main에서 받은 상품 리스트를 저장할 필드
private List<Product> products;
// 생성자: Main이 만든 상품 리스트를 받음
public CommerceSystem(List<Product> products) {
this.products = products;
}
public void start() {
// 사용자 입력을 받기 위한 Scanner
Scanner sc = new Scanner(System.in);
// 프로그램을 계속 돌릴지 결정하는 변수
boolean run = true;
// run이 true인 동안 계속 반복
while (run) {
// 프로그램 시작 출력
System.out.println("[실시간 커머스 플랫폼 - 전자제품]");
// 상품 목록 출력
for (int i = 0; i < products.size(); i++) {
// 리스트에서 i 번째 상품을 꺼낸다
Product product = products.get(i);
int menuNumber = i + 1;
// 메뉴판 출력
System.out.println(menuNumber + ". " + product.getName()
+ " | " + product.getPrice() + "원"
+ " | " + product.getDescription());
}
// 종료
System.out.println("0. 종료 | 프로그램 종료");
// 입력 받음
System.out.print("선택> ");
int choice = sc.nextInt();
// 입력 처리
if (choice == 0) {
System.out.println("커머스 플랫폼을 종료합니다");
run = false;
} else {
System.out.println("아직 안 돼요 ㅜ");
}
System.out.println();
}
sc.close();
}
}
일단 Main에서 CommerceSystem.start()로 그대로 복사하고 start 함수를 만들어서 CommerceSystem 생성자를 통해 값을 할당하고 Main에 값을 넘겨 줌
🚩STEP 3 - 객체 지향 설계를 적용해 상품 카테고리와 고객 관리를 클래스 기반으로 관리하기
기본에 `Product`만 단순히 출력하던 구조를 Category / Customer 중심의 객체지향 구조로 확장하는 작업
1️⃣ `Category` 기반 구조로 변경
기존에는 `CommerceSysterm`이 `List<Product>`를 직접 관리하고 있었는데, 상품 관리는 Category가 담당하도록 구조를 변경했다
- `Category` 클래스 = 카테고리 이름(name), 해당 카테고리에 속한 `List<Product>를 가진다
- `CommerceSystem`은 더 이상 Product를 직접 관리하지 않고 `List<Category>`를 관리하면서 흐름 제어 역할만 담당한다
❗이 과정에서 `List<Category>`를 넘기는데 `List<Product>`를 받도록 되어 있어서 `incompatible types` 에러가 발생했고 step2 기준 지금 기준 구조에 맞게 수정하지 않아서 발생한 문제였다
👉 생성자 타입을 `List<Category>`로 수정하면서 해결
2️⃣ 카테고리 선택 -> 상품 목록 -> 상품 선택 구현
1. 메인 화면에서 카테고리 목록 출력
2. 카테고리 선택 시 해당 카테고리 진입
3. 카테고리 내부에서 상품 목록 출력
4. 상품 번호 선택 시 상품 상세 정보 출력
5. `0` 입력 시 뒤로가기 / 종료 처리
여기서 중첩 while문을 사용해서 메인 화면이랑 카테고리 화면을 전환하는 걸로 했다
3️⃣ Customer 객체를 통한 누적 주문 금액 & 등급 관리
상품 선택을 주문으로 한다 치면 `Customer` 객체를 추가해서 기능을 구현했다
- 상품 선택 시 상품 가격을 고객의 누적 주문 금액에 추가
- 누적 금액 기준으로 고객 등급 자동 변경
Customer는 본인의 상태를 관리하도록 하고 `addOrderAmount()` 메서드 내부에서 누적 금액 갱신과 등급 계산을 함께 처리했다
🚩STEP 4 - 캡슐화 적용하기
public List<Product> getProducts() {
// 원본을 그대로 주지 않고, 원본을 복사한 "새 리스트"를 만들어서 준다
return new ArrayList<>(products);
}
`Category`의 products 리스트 원본을 그대로 반환하면, 외분에서 리스트를 마음대로 수정할 수 있어서 캡슐화가 깨진다. 그래서 getter는 원본이 아니라 복사본을 반환해 내부 상태를 보호한다.
public CommerceSystem(List<Category> categories, Customer customer) {
// categories 원본을 그대로 들고 있지 않고 복사본 저장
this.categories = new ArrayList<>(categories);
// 필드 private
this.customer = customer;
}
생성자에서 리스트를 그대로 받으면 외부와 내부가 같은 리스트를 공유하게 되어 외부 수정이 내부 상태를 망가뜨릴 수 있다. 그래서 생성자에서 복사해서 저장해 객체 내부 상태를 보호한다.
// 상품 1개를 카테고리에 추가하는 메서드
public void addProduct(Product product) {
if (products == null) {
return;
}
products.add(product); // 원본 리스트에 추가
}
// 상품 1개를 카테고리에서 삭제하는 메서드
public void removeProduct(Product product) {
// null이면 아무 것도 하지 않음
if (products == null) {
return;
}
products.remove(product); // 원본 리스트에서 제거
}
getProducts()로 원본을 주면 외부가 마음대로 수정해 캡슐화가 깨진다.
그래서 복사본을 주고, 실제 수정은 Category의 add/remove 같은 메서드로만 하게 만든다.
❗
// 생성자: Main이 만든 상품 리스트를 받음
public CommerceSystem(List<Category> categories, Customer customer) {
// categories 원본을 그대로 들고 있지 않고 복사본 저장
this.categories = new ArrayList<>(categories);
// customer가 null일 때 예외처리
if (customer == null) {
throw new IllegalArgumentException("Customer는 null일 수 없습니다.");
}
// 필드 private
this.customer = customer;
}
customer null이면 예외처리
❗
// 입력값이 숫자가 아닐 시에 예외처리
private int readInt(Scanner sc, String message) {
while (true) {
// 안내 문구 출력
System.out.println(message);
String input = sc.nextLine();
try {
return Integer.parseInt(input);
} catch (NumberFormatException e) {
System.out.println("보기에 보이는 숫자만 입력해 주세요! ㅜㅜ");
}
}
}
nextInt()는 다른 숫자를 누르거나 다른 입력을 하면 프로그램이 터진다...... 그래서 nextLine() + parseInt()로 입력을 받는 메서드를 만들어서 예외에도 반복 입력하도록 함
🚩도전기능 - Lv 1. 장바구니 및 주문하기 기능을 추가하기
🎯 전체 목표 정리
상품을 고르면 "장바구니에 담을래?" 물어보고, 담으면 장바구니에 저장해 두다가, 나중에 한 번에 주문하면서 재고를 줄이고 장바구니를 비운다.
1) CartItem (장바구니에 물건을 넣을 때는 상품 하나만 저장하는 것이 아니라 수량까지 넣는다)
- `Product` (어떤 상품인가?)
- `quantity` (몇 개 담았는가?)
2) Cart (CartItem들을 모아 놓는 곳)
- `items` (List<CartItem>) - 얘도 캡슐화 진행해야 됨
- `addItem` (product, quantity): 담기
- `printCart()`: 장바구니 보여 주기
- `getTotalPrice()`: 총금액 계산
- `clear()`: 주문 확정 후 장바구니 비우기
1️⃣ 일단 출력하기
// 장바구니 추가 여부 질문
System.out.println();
System.out.println("\"" + selectedProduct.getName()
+ " | " + formatPrice(selectedProduct.getPrice()) + "원"
+ " | " + selectedProduct.getDescription()
+ " | " + selectedProduct.getStock() + "\"");
System.out.println("위 상품을 장바구니에 추가하시겠습니까?");
System.out.println("1. 확인 2. 취소");
// 입력 받기
int addChoice = readInt(sc, "선택> ");
if (addChoice == 1) {
System.out.println("다음 단계: 수량 입력 및 장바구니 저장(음~ 아직 구현이 안 됐더요)");
} else if (addChoice == 2) {
System.out.println("장바구니 추가를 취소했습니다.");
} else {
System.out.println("잘못된 입력입니다.");
}

- 장바구니 추가할까요?
- 1이나 2 입력 받고 1이면 다음 단계로, 2면 그냥 카테고리 화면으로 계속
2️⃣ 장바구니 저장
package com.example.commerce;
public class CartItem {
private Product product;
private int quantity;
// 상품과 수량 받아서 저장
public CartItem(Product product, int quantity) {
this.product = product;
this.quantity = quantity;
}
public Product getProduct() {
return product;
}
public int getQuantity() {
return quantity;
}
// 수량을 더해줌
public void addQuantity(int quantity) {
this.quantity += quantity;
}
}
package com.example.commerce;
import java.util.ArrayList;
public class Cart {
// 장바구니에 담긴 것들
private ArrayList<CartItem> items = new ArrayList<>();
// 장바구니에 상품 추가
public void addItem(Product product, int quantity) {
// 같은 상품이면 수량 더함
for (CartItem item : items) {
if (item.getProduct() == product) {
item.addQuantity(quantity);
return;
}
}
items.add(new CartItem(product, quantity));
}
public boolean isEmpty() {
return items.isEmpty();
}
public void printCart() {
for (CartItem item : items) {
Product product = item.getProduct();
int quantity = item.getQuantity();
System.out.println(product.getName() + " | " + product.getPrice() + "원"
+ " | " + product.getDescription()
+ " | 수량: " + quantity + "개 장바구니에 추가되었습니다." );
}
}
public ArrayList<CartItem> getItems() {
return new ArrayList<>(items);
}
public void clear() {
items.clear();
}
}
if (addChoice == 1) {
int quantity = readInt(sc, "수량: ");
// 수량이 1 이상인지 확인
if (quantity <= 0) {
System.out.println("수량은 1개 이상 입력하세요.");
continue;
}
// 재고 체크
if (quantity > selectedProduct.getStock()) {
System.out.println("재고가 부족합니다. 현재 재고: " + selectedProduct.getStock() + "개");
continue;
}
// 장바구니 추가
cart.addItem(selectedProduct, quantity);
System.out.println(selectedProduct.getName() + "가 " + quantity + "개 장바구니에 추가되었습니다.");
} else if (addChoice == 2) {
System.out.println("장바구니 추가를 취소했습니다.");
} else {
System.out.println("잘못된 입력입니다.");
}
상품 선택 -> 장바구니 확인(1) -> 수량 입력 -> 출력
3️⃣ 주문 관리
// 4번 장바구니 확인
if (choice == 4) {
if (cart.isEmpty()) {
System.out.println("장바구니가 비어있어용.");
continue;
}
System.out.println("[장바구니 내역]");
for (CartItem item : cart.getItems()) {
Product p = item.getProduct();
int quantity = item.getQuantity();
System.out.println(p.getName() + " | " + formatPrice(p.getPrice()) + "원"
+ " | " + p.getDescription() + " | " + quantity + "개");
}
continue;
}
// 5번: 주문 취소 장바구니 비움
if (choice == 5) {
if (cart.isEmpty()) {
System.out.println("취소할 주문이 없습니다. 장바구니가 비어있습니다.");
continue;
}
cart.clear();
System.out.println("진행중인 주문이 취소되었습니다. 장바구니를 비웠습니다.");
}
장바구니에 상품이 있을 때만 주문 관리 메뉴를 보여 주고 입력값이 4나 5면 카테고리로 들어가 먼저 처리한 뒤 continue로 메인 메뉴로 돌아가게 했다.
4️⃣ 주문 확정 시에 재고 차감 및 장바구니 초기화
if (confirm == 1) {
totalPrice = 0;
for (CartItem item : cart.getItems()) {
Product p = item.getProduct();
int quantity = item.getQuantity();
totalPrice += p.getPrice() * quantity;
int beforeStock = p.getStock();
p.decreaseStock(quantity);
int afterStock = p.getStock();
System.out.println(p.getName() + " 재고가 " + beforeStock + "개에서 " + afterStock + "개로 업데이트되었습니다.");
}
customer.addOrderAmount(totalPrice);
cart.clear();
System.out.println("주문이 완료되었습니다...! 총 금액: " + String.format("%,d", totalPrice) + "원");
} else if (confirm == 2) {
System.out.println("메인으로 돌아갑니다.");
} else {
System.out.println("잘못된 입력입니다. 메인으로 돌아갑니다.");
}
❗
customer.addOrderAmount(selectedProduct.getPrice());
테스트를 하는데 장바구니에 담는 순간 고객 금액 누적이 됐었다...... 삭제했다. 그리고
customer.addOrderAmount(totalPrice);
로 바꿔서 주문 완료할 때 바꾸는 걸로 했다
🚩도전기능 - Lv 2. 관리자 모드 추가
package com.example.commerce;
import java.util.List;
import java.util.Scanner;
public class AdminSystem {
private final List<Category> categories;
public AdminSystem(List<Category> categories) {
this.categories = categories;
}
public void start(Scanner sc) {
System.out.print("관리자 비밀번호를 입력하세요: ");
String password = sc.nextLine();
if (!"1234".equals(password)) {
System.out.println("비밀번호가 틀렸습니다.");
return;
}
System.out.println("관리자 모드에 진입");
}
}
딱히 분리하라는 말은 없었지만 일단 너무 길어져서 분리했다
// 9번: 관리자 모드
if (choice == 9) {
adminSystem.start(sc);
continue;
}
이걸 추가해서 일단 밑의 결과처럼 나오게 했다


와 이거 하는 거 진심 머리 터질 뻔했다 와...... 전혀 진도가 안 나가서 머리가 아팠다. 상품 삭제를 상품 번호로 입력해서 구현하려고 하다가 또 머리 아파서 수정이랑 비슷하게 검색으로 찾아서 하는 걸로 했다. 보통 이럴 때는 어떻게 해야 되지? 그리고 하나 하고 오류 나면 또 바꾸고 빨간 줄 왜 뜨나 고민하다가 막상 트러블 슈팅을 작성 제대로 못한 게 아쉽다.
AdminSystem으로 분리를 한 게 잘한 것 같다. 아 그리고 더 뭔가 분리할 수 있을 것 같은데...... 난 바보 감자 멍청이 쪼랩이지만 이래서 리팩토링을 하나 싶기도 하고
🚩도전기능 - Lv 3. Enum, 람다 & 스트림을 활용한 고급 관리 기능
1️⃣ Enum을 활용한 고객 등급별 할인율 관리하기
Enum은 정해진 값만 쓸 수 있는 목록이다. Enum 안에 할인율 같은 정보도 같이 붙일 수 있다.
package com.example.commerce;
// 고객 등급
public enum CustomerGrade {
BRONZE(0, "브론즈"),
SLIVER(5, "실버"),
GOLD(10, "골드"),
PLATINUM(15, "플래티넘");
private final int discountPercentage;
private final String description;
CustomerGrade(int discountPercentage, String description) {
this.discountPercentage = discountPercentage;
this.description = description;
}
public int getDiscountPercentage() {
return discountPercentage;
}
public String getDescription() {
return description;
}
public long calculateDiscount(long amount) {
return amount * discountPercentage / 100;
}
}
주로 누적되는 금액은 21억을 넘길 수 있기 때문에 long으로 설정
2️⃣ 람다 & 스트림을 활용한 상품 검색 및 관리 기능
1) 람다(lambda) = 작은 규칙(기준)을 한 줄로 적는 방법
items.removeIf(item -> item.getProduct() == product);
- `item` = 장바구니 한 칸(CartItem)
- `->` = 그래서(그러면)
- `item.getProduct() == product` = 이 조건이 맞으면 true
- items 안에 있는 각 item을 보면서 item이 가진 product가 내가 지우려는 product랑 같으면 지워
- 조건/동작을 짧게 적을 수 있고
- 코드가 덜 길어짐
2) 스트림(stream) = 리스트를 컨베이어 벨트에 올림
- for문으로 하나씩 꺼내서
- 조건 검사하고
- 출력하고
- 합치고
- 이 과정들을 컨베이어 벨트 위로 상품들이 지나가는데 필요한 것만 골라서(필터) 하고 싶은 일을 한다(출력/모으기)
- `필터링 / 정렬 / 출력 / 합계` 같은 작업이 한 줄로 깔끔해짐
- for문에서 if랑 continue가 섞이는 복잡함이 줄어든다
1. stream() = 컨베이어 벨트에 올린다
products.stream()
2. filter(...) = 조건에 맞는 것만 통과시킨다
.filter(p -> p.getPrice() <= 1000000)
3. forEach(...) / toList() = 마지막에 결과를 사용한다
- 출력할 거면 `forEach()`
- 새 리스트로 만들 거면 `toList()`
products.stream()
.filter(p -> p.getPrice() <= 1000000)
.forEach(p -> System.out.println(p.getName()));
product를 벨트에 올리고 100만원 이하만 통과시키고 통과한 애들 이름을 출력해라
🚩어려웠던 점과 느낀 점
솔직히 필수 기능까지 할 때는 할만하다고 생각했다. 도전기능 들어가고서는 맨날 머리를 싸매고 있었다. 생각보다 더 내가 개념을 제대로 알고 있는 게 아니구나..... 장바구니 기능을 구현할 때는 새로 만든 Cart와 CartItem 클래스를 어떻게 CommerceSystem에 적용해야 되는지부터 관리자 모드를 들어갔을 때는 CommerceSystem이 너무 길어져서 AdminSystem으로 분리를 하고 또 다시 적용을 하고 진짜 AI한테 힌트만 달라고 해서 적용하고 와중에 안 되면 정답도 알려 달라고 하면서 튜터님한테 가서도 물어보고 확인을 하고 정말 오래 걸렸다...... 와중에 스트림으로 넘어가니 스트림에서는 숫자를 잘못 쓴다거나 continue를 안 써서 무한 반복이 된다거나 이런 일들이 너무 많았다. 분명 위에 보면 차근차근 개념 정리를 하고 한다고 했는데 이러다 보니 시간이 훨씬 더 오래 걸린 것 같다. 막상 진짜로 어려운 도전 기능에 왔을 때는 시간에 쫓겨서 블로그를 신경 쓰지도 못했다. 오류가 났을 때 곧바로 캡처를 했어야 됐는데 그런 것도 생각이 안 났다.
자바가 끝난 건가? 전혀 모르겠다...... 아직 개념이 안 잡힌 건 너무 많고 정확히 객체 지향이 어떤 건지도 솔직히 감이 안 온다. 코드가 너무 길어지는데? 쪼갤 수 있을 것 같은데? 내가 눈에 벌써 안 들어오는데? 이런 의문을 가지고 ProductFilter 이런 클래스로도 쪼개 봤다. 이런 생각들이 모이면 더 괜찮은 코드를 만들 수 있을까...... 사실 개념은 똑바로 잡힌 건지 의문이 든다. 이런 상태에서 Spring을 들어가도 되는 건가? 주말에는 좀 쉬어야 된다는 마인드였는데 자바를 조금 더 잘 공부해 보고 싶다...... 나는 너무 부족하다. 그래도 희망을 가질 수 있는 건? 좀 재미있다. 이거 분리해서 해 볼 수 있을 것 같은데?라는 생각이 든다는 게 재미있었다. 이제 한 지 거의 한 달이 다 되어 간다. 조금 더 노력을 해 보자. 이건 진짜로 리팩토링을 할 수 있을 것 같다..... 더 이쁘게 쪼갤 수 있었을 것 같다 계속 아쉽기만 하다 나중에 고쳐 봐야지
'IL > WIL' 카테고리의 다른 글
| [WIL] Spring - 일정 관리 앱 업글 (0) | 2026.02.09 |
|---|---|
| [WIL] Spring - 일정 관리 앱 만들기 (0) | 2026.02.02 |
| 20260107 [WIL] 왜 Git을 배우는데 머리가 아플까 (0) | 2026.01.07 |