요구사항

  • 장바구니 상품: 양파, 사과, 생선, 두부
  • 기능1: 상품추가(addProduct)
  • 기능2: 장바구니 목록 출력(printCart)
  • 기능3: 상품 삭제(removeProduct)
  • 기능4: 총 가격 계산(calculateTotalPrice)

Step 1. 기본 틀 만들기 

// Product.java
// 각 상품은 이름, 가격 속성을 가짐
public class Product {
    String name;
    int price;

    Product(String name, int price){
        this.name = name;
        this.price = price;
    }
}
// Cart.java
// Cart 객체를 생성하면 ArrayList형 장바구니 하나를 만듦

import java.util.ArrayList;

public class Cart {
    ArrayList<Product> productCart;

    Cart(){
        productCart = new ArrayList<>();
    }
}
public class Main {
    public static void main(String[] args) {
        Cart cart = new Cart(); // 장바구니 생성
    }
}

 


Step 2. 상품추가(addProduct) 기능 구현

// Cart.java
void addProduct(String name, int price){
     productCart.add(new Product(name, price));
}
// Main.java
cart.addProduct("양파", 1000);
cart.addProduct("사과", 1000);
cart.addProduct("생선", 1000);
cart.addProduct("두부", 1000);

 


Step 3. 장바구니 목록 출력(printCart) 기능 구현

// Product.java
String getName(){
    return this.name;
}
// Cart.java
void printCart(){
     for(int i=0; i< productCart.size(); i++){
        System.out.println(productCart.get(i).getName());
     }
}
// Main.java
cart.printCart();

 


Step 4. 상품 삭제(removeProduct) 기능 구현

2-1. 반복문 이용

// Cart.java
void removeProduct(String name){
    for(int i=0; i< productCart.size(); i++){
        if(productCart.get(i).getName().equals(name)){
            productCart.remove(i);
        }
}
// Main.java
cart.removeProduct("양파");
cart.printCart();

 

2-2. 람다 이용

// Cart.java
void removeProduct(String name){
    productCart.removeIf(product -> product.getName().equals(name));
}

 

클래스 내부 최상단에 기본 틀로 작성했던 `ArrayList<Product> productCart;` 코드를 통해 람다식이 Product 객체로 전달될 수 있다.

 


Step 5. 총 가격 계산(calculateTotalPrice) 기능 구현

// Product.java
int getPrice(){
    return this.price;
}
// Cart.java
void calculateTotalPrice(){
    int sum=0;
    for(int i=0; i< productCart.size(); i++){
        sum += productCart.get(i).getPrice();
    }
    System.out.println("총 금액은 " + sum);
}
// Main.java
cart.calculateTotalPrice();

 

테스트 방법

  • 기본형과 래퍼형 모두 1000만 번의 반복문을 돌면서 연산을 진행한다.
  • `System.nanoTime()` 메서드를 사용해서 반복문의 전, 후 사이의 시간을 기록한다.

1. 기본 자료형 int와 래퍼 클래스 Integer 연산 성능 테스트 코드

public class PrimitiveVsWrapperPerformance {
    public static void main(String[] args) {
        int iteration = 10_000_000; // 1000만 번 반복
        
        // 기본형 int 연산 성능 테스트
        long startTime1 = System.nanoTime();
        int sum1 = 0;
        for (int i = 0; i < iteration; i++) {
            sum1 += i;  // 기본형 연산
        }
        long endTime1 = System.nanoTime();
        long primitiveTime = endTime1 - startTime1;

        // 래퍼 클래스 Integer 연산 성능 테스트
        long startTime2 = System.nanoTime();
        Integer sum2 = 0;
        for (int i = 0; i < iteration; i++) {
            sum2 += i;  // 오토박싱 & 언박싱 발생
        }
        long endTime2 = System.nanoTime();
        long wrapperTime = endTime2 - startTime2;

        // 결과 출력
        System.out.println("기본형(int) 연산 시간: " + primitiveTime + " ns");
        System.out.println("래퍼 클래스(Integer) 연산 시간: " + wrapperTime + " ns");
        System.out.println("성능 차이 (배수): " + (double) wrapperTime / primitiveTime);
    }
}

 

 

2. 기본 자료형 double과 직접 만든 래퍼형 MyDouble의 연산 성능 테스트 코드

2-1.

package chap1;

public class MyDouble {
    double value;

    public MyDouble(Double value){
        this.value = value;
    } //기본 생성자

    public Double getValue(){
        return value;
    }

    public void setValue(Double value){
        this.value = value;
    }

    public void sumValue(int num){
        this.value += num;
    }
}
package chap1;

public class PrimitiveVsWrapperPerformance {
    public static void main(String[] args) {
        int iterator = 10_000_000;

        // 기본 Double 성능 테스트
        double sum1 = 0.0;

        long startTime1 = System.nanoTime();
        for(int i=0;i<iterator;i++){
            sum1+=i;
        }
        long endTime1 = System.nanoTime();

        long totalTime1 = endTime1 - startTime1;


        // 내가 만든 MyDouble 성능 테스트
        MyDouble sum2 = new MyDouble(0.0);

        long startTime2 = System.nanoTime();
        for(int i=0;i<iterator;i++){
            sum2.sumValue(i);
        }
        long endTime2 = System.nanoTime();

        long totalTime2 = endTime2 - startTime2;

        System.out.println("totalTime1 = " + totalTime1);
        System.out.println("totalTime2 = " + totalTime2);
    }
}

// totalTime1 = 3683125
// totalTime2 = 24226291

 

계산했을 때, 래퍼형이 약 8배 가량 연산 시간이 오래 걸리는 것을 볼 수 있다.

객체를 언박싱해서 매개변수와 연산하고, 다시 그 값을 박싱하는 과정이 필요하기 때문이다.

래퍼형을 다른 방식으로 연산했을 때는 어떤 결과값이 있는지 확인해보자.

 

 

2-2.

// 직접 만든 Double 래퍼 클래스
class MyDouble {
    private final double value;

    public MyDouble(double value) {
        this.value = value;
    }

    public double getValue() {
        return value;
    }

    // 덧셈
    public MyDouble add(MyDouble other) {
        return new MyDouble(this.value + other.value);
    }

    @Override
    public String toString() {
        return String.valueOf(value);
    }
}
public class DoubleWrapperPerformance {
    public static void main(String[] args) {
        int iteration = 10_000_000; // 1000만 번 반복

        // 1. 기본형 double 연산
        long startTime1 = System.nanoTime();
        double sum1 = 0.0;
        for (int i = 0; i < iteration; i++) {
            sum1 += i * 1.1;
        }
        long endTime1 = System.nanoTime();
        long primitiveTime = endTime1 - startTime1;

        // 2. MyDouble 연산
        long startTime3 = System.nanoTime();
        MyDouble sum3 = new MyDouble(0.0);
        for (int i = 0; i < iteration; i++) {
            sum3 = sum3.add(new MyDouble(i * 1.1));
        }
        long endTime3 = System.nanoTime();
        long myDoubleTime = endTime3 - startTime3;

        // 결과 출력
        System.out.println("기본형(double) 연산 시간: " + primitiveTime + " ns");
        System.out.println("MyDouble 클래스 연산 시간: " + myDoubleTime + " ns");
        System.out.println("MyDouble vs double 성능 차이: " + (double) myDoubleTime / primitiveTime);
    }
}

// totalTime1 = 3717209
// totalTime2 = 103633583

 

이 경우는 약 28배 가량 래퍼형의 연산이 늦었다.

반복문 안에서 add 함수를 실행할 때마다 값을 박싱한 새로운 객체를 생성하고 , 기존의 객체와 새로운 객체를 언박싱하여 연산 후 다시 박싱하는 과정을 거치기 때문에 시간이 매우 지연된다.

그리고 이 코드는 시간의 문제 뿐만 아니라, 1000만 번의 반복문을 실행하면서 1000만 개의 새로운 객체를 생성하게 되면서 아래와 같은 상황을 발생시킬 수 있다.

 

1. 메모리 부족 (OutOfMemoryError)

  • 힙 메모리를 초과하면 OutOfMemoryError 가 발생할 수 있다.

2. 가비지 컬렉션(GC) 부담 증가

  • 가비지 컬렉션이 불필요한 객체를 자동으로 정리하지만, 객체가 너무 많으면 GC 작업이 잦아져 성능 저하가 발생할 수 있다.
  • 잦은 GC → CPU 부하 증가 → 애플리케이션 응답성 저하

3. 메모리 단편화

  • 많은 객체가 생성되고 해제되면서 메모리가 조각나게 되고, 결국 새로운 객체 할당 시 성능 저하의 원인이 될 수 있다.

4. 캐시 미스 증가

  • 객체가 너무 많으면 CPU 캐시에서 데이터를 효율적으로 관리하기 어려워져 캐시 미스(cache miss) 빈도가 증가 → 실행 속도 저하

 


결론

래퍼 클래스는 아래 게시물과 같은 장점을 가지고 있지만, 위와 같은 시간 지연과 메모리 차지 등의 문제점을 일으키기 때문에 상황에 맞게 사용하도록 하자.

 

2025.02.25 - [언어/Java] - Wrapper 클래스

 

Wrapper 클래스

Wrapper Class기본 자료형을 객체로 감싸는 클래스즉, 래퍼 클래스는 객체  객체 또는 변수가 담겨있는, 참조형 변수는 데이터의 메모리 주소를 저장하므로, 해당 변수를 출력하면 데이터의 메모

go-getter1kim.tistory.com

 

Wrapper Class

  • 기본 자료형을 객체로 감싸는 클래스
  • 즉, 래퍼 클래스는 객체

 

 

객체 또는 변수가 담겨있는, 참조형 변수는 데이터의 메모리 주소를 저장하므로, 해당 변수를 출력하면 데이터의 메모리 주소값이 출력된다.

하지만 래퍼 클래스가 담겨있는 변수는 출력해도 주소값이 아닌, 할당된 값이 출력된다.

Person personA = new Person("Steve"); // 객체가  담긴 personA 는 참조형 변수
Syetem.out.println(personA.name);
System.out.println(personA); // 출력하면 @123 메모리의 주소값이 출력

int[] arr = {1, 2, 3, 4}; // 배열이 담긴 arr 는 참조형 변수
System.out.println(arr); // 출력하면 @123 메모리의 주소값이 출력


Integer num = 100; 
System.out.println(num); // 출력 100

 

출력할 때 주소값이 아닌 실제 값이 출력되는 이유는 toString() 메서드 때문이다.

toString() 메서드는 객체의 정보를 문자열로 반환하는데, 기본적으로 Object 클래스에서 제공하는 toString()메서드는 객체의 메모리 주소를 문자열로 반환한다.

하지만, 래퍼 클래스 Integer, Double, Boolean 등은 Object 클래스를 상속하면서 자기 자신을 출력할 수 있도록 toString() 메서드를 오버라이딩하여, 객체의 값을 반환하도록 구현되어 있다.

 

 


래퍼 클래스 사용 목적

Integer num = 123; // Wrapper 클래스 객체 생성자 사용
String str = num.toString(); // ✅ Object 클래스 메서드 활용 가능

int a = 100; // 그냥 데이터 100
String str = a.toString(); // ❌ 변환 불가

Integer num3 = 10; 
int num = num3;   // ✅ Wrapper 클래스 메서드 활용

 

주소값을 저장하는 참조형 변수에 정수를 저장할 수 있는 것은 Wrapper 클래스의 내부에 있는 객체 생성자를 사용했기 때문이다.

컴파일 과정에서 내부적으로 `Integer num = Integer.valueOf(123);` 으로 기본형을 래퍼형으로 변환하여 값을 저장한다.

 

`num`을 객체로 변환하면, 객체의 최상위 클래스인 Object 클래스의 메서드들을 활용할 수 있기 때문에,

위와 같이 toString 함수로 편리하게 데이터를 처리할 수 있다.

 

기본형에 참조형 변수를 저장할 때도, Wrapper 클래스의 메서드들을 활용한다.

내부적으로 `int a = num.intValue();` 으로 실행되어 래퍼형을 기본형으로 변환하여 값을 저장한다.

 

https://go-getter1kim.tistory.com/22

 

JDK 패키지와 클래스

주요 패키지- java.langSystem을 비롯하여 문자열, 수학 함수, 입출력 등과 같은 프로그래밍에 필요한 기본적인 클래스와 인터페이스 제공- java.util날짜, 시간, 벡터, 해시맵 등의 유틸리티 클래스와

go-getter1kim.tistory.com

 

 

위에서 설명한 래퍼 클래스의 메서드 활용, 기본형의 객체화 말고도 래퍼 클래스를 사용해야 하는 이유가 있다.

 

1. 컬렉션은 객체만 다룰 수 있기 때문에, 래퍼 클래스가 필요하다.

2. 객체이므로 null 값도 가질 수 있다.

3. 래퍼 클래스는 불변 객체(Immutable Object)이다.

불변 객체란 생성 후 값을 변경할 수 없는 객체로, 새로 값을 설정하려면 새 객체를 생성해야 한다.

Integer a = 100;
a = a + 1;  // 기존 값은 변경되지 않음, 새로운 Integer 객체가 만들어짐

System.out.println(a);  // 101

 

위 코드에서 a+1을 지정한 순간, 새로운 객체가 만들어져서 a는 새로운 객체를 가리키게 된다.

JVM (Java Virtual Machine)

Java가 어떤 운영체제에서도 실행될 수 있도록 운영체제 상위에서 자바 프로그램을 실행하는 가상 기계이다.

  • Class Loader
    • 자바 파일 컴파일 후 생성된 클래스 파일들을 RunTime Data Area로 각각 적재
  • Execution Engine
    • RunTime Data Area에 적재된 클래스들을 기계어로 변경해 명렁어 단위로 실행
  • Garbage Collector
    • heap 메모리 영역에 생성된 객체들 중에 참조되지 않는 객체들을 탐색 후 제거
  • Runtime Data Area
    • JVM의 메모리 영역으로 자바애플리케이션을 실행할때 사용되는 데이터들을 적재하는 영역
  • Method Area
    • 프로그램 시작 시 클래스 정보가 저장되는 영역으로, 
    • 클래스의 메서드 정보, static 변수 등 저장
    • 모든 객체가 공유하는 공용 공간
  • Stack Area
    • 지역 변수, 파라미터 등이 저장되었다가, 해당 영역의 실행 끝나면 다시 데이터가 스택에서 지워지는 임시적으로 생성된 데이터의 영역
    • 객체, 배열을 가리키는 참조형 변수도 이 영역에 생성
  • Heap Area
    • new 키워드로 생성된 객체와 배열이 생성되는 영역
  • PC Register
    • Thread가 생성될때마다 생성되는 영역으로, Program Counter
  • Native Stack Area
    • 자바외 언어로 작성된 네이티브 코드를 위한 메모리 영역

 

'TIL' 카테고리의 다른 글

웹서버 애플리케이션 관점에서의 Thread Pool  (0) 2025.03.21
NullPointerException(NPE) 런타임 에러  (1) 2025.03.11
이스케이프 시퀀스  (0) 2025.02.22
NumberFormat 런타임 에러  (0) 2025.02.21
InputMismatch 런타임 에러  (0) 2025.02.21

문제

boolean[][] board = {
                {true, false},
                {false, true}
        };

 

주어진 배열에서 true를 검은 바둑돌, false를 흰 바둑돌이라고 가정했을 때, 

검은 바둑돌의 좌표를 출력하는 프로그램을 작성하자

 

 

풀이 과정

1. for문을 중첩으로 사용해서 2차원 배열의 각 데이터에 접근

  • for-each는 반복할 때마다 증가하는 값을 가지는 변수가 없으므로 해당 문제에서 사용 불가

2. 조건문으로 해당 값이 true일 때, 중첩된 반복문의 증가된 값 2개를 각 x, y좌표로 출력

 

 

결과

package chap1;

public class BlackStoneFinder {
    public static void main(String[] args) {
        boolean[][] board = {
                {true, false},
                {false, true}
        };

        for(int i=0; i<board.length; i++){
            for(int j=0; j<board[i].length; j++){
                if(board[i][j]){
                    System.out.println("검은돌(●) 위치: (" + i + "," + j + ")");
                }
            }
        }
    }
}

 

☝️ if문은 괄호 안의 조건이 true일 때 실행되는데, `board[i][j]` 자체가 이미 boolean 값이므로 별도의 비교 연산 없이도 바로 조건으로 사용 가능하다.

목적 

배열에 저장되어 있는 정수 중 짝수만 출력

 

 

문제 

package chap1;

public class EvenNumberFinder {
    public static void main(String[] args) {
        int[] intArray = {3,4,7,10,15,20};

        for(int i : intArray){
            if(intArray[i] % 2 == 0) System.out.println(intArray[i]);
            else continue;
        }
    }
}

// 에러 메세지
10
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 
Index 7 out of bounds for length 6
	at chap1.EvenNumberFinder.main(EvenNumberFinder.java:8)

 

 

문제 원인 

위의 for-each문은 변수 i에 배열의 값을 하나씩 할당하며 반복한다.

그러므로 조건문에서 `intArray[i]`는 배열의 값을 인덱스 번호로 인식하고 해당 위치의 값을 출력하는 것이다.

예를 들어, 가장 첫 번째 반복에서는 intArray[0]의 값인 3이 출력되어야 하지만, 3이 `i`에 저장되어 intArray[3]을 출력한다.

배열의 크기는 6인데 세 번째 반복에서 intArray[7]의 값을 출력하라고 명령하니까 컴파일러는 먼저 intArray[3]의 값을 무사히 출력한 후,`Index 7 out of bounds for length 6`이라는 에러 메세지를 출력하게 된다.

 

 

해결 방법

package chap1;

public class EvenNumberFinder {
    public static void main(String[] args) {
        int[] intArray = {3,4,7,10,15,20};

        for(int i : intArray){
            if(i % 2 == 0) System.out.println(i);

            else continue;
        }
    }
}

Keep

이번 프로젝트에서 진행한 과정 중 다음 프로젝트에서도 유지했으면 하는 부분.

 

1️⃣ WBS 문서 사용

2️⃣ 폴더 세분화해서 관리 (js, css, img)

3️⃣ 주석 달기

4️⃣ 프로젝트 기간 중의 트러블 슈팅 정리

5️⃣ 결과물 문서화(readme, ERD, api)

6️⃣ 활발한 의사소통 (모르는 건 바로바로 물어보고, 같이 고민하기)

7️⃣ 하루 회고 진행

 

Problem

문제점 : 이번 프로젝트에서 발생한 문제점을 객관적으로 판단
해결 방안 : 해당 문제점을 해결할 수 있는 현실적인 방안 제시

 

1️⃣ 이번 프로젝트는 미니 프로젝트여서 와이어 프레임을 간단하게 블록을 배치하는 방법으로 제작해도 문제가 없었지만, 규모가 큰 프로젝트를 진행할 때는 팀원들이 통일된 디자인으로 개발할 수 있도록 해야할 것 같다.

-> 피그마 등의 더 직관적이고 구체적인 도구로 와이어 프레임 제작

 

Try

다음 프로젝트를 위해 해야 할 노력 또는 시도해볼 것

 

1️⃣ Restful API 문서화 공부

2️⃣ 표기법 규칙(이스케이프 시퀀스), 주석 통일

3️⃣ 개인적으로 백엔드 구현 해보기

 

Feel

이번 프로젝트를 통해 느낀 점

 

장시간 혼자 고민하면서 코딩하는 것보다 모르는 부분은 바로 도움을 얻으면서 진행하니까 짧은 시간에도 생각보다 많은 것을 배울 수 있었다.

구글링을 통해 알게 된 부분을 적극적으로 활용하는 게 오히려 내가 성장하는 데에 좋은 역할을 해준다는 것을 깨달아서 앞으로 적극적으로 새로운 방법을 찾아 내 것으로 만드는 연습을 해야겠다는 생각이 들었다.

첫 프로젝트를 좋은 팀원분들과 하게 되어서 더 용기를 가지고 적극적으로 부트캠프에 임하기로 결심하게 된 것 같다.

 

1. addDoc

  • Firestore database의 컬렉션에 새로운 문서 추가
  • 자동으로 고유한 문서 ID를 생성하고, 그 안에 데이터 저장
import { collection, addDoc } from "firebase/firestore"; 

const docRef = await addDoc(collection(db, "collectionName"), {
  name: "홍길동",
  comment: "좋은 댓글입니다!"
});
 

2. setDoc

  • Firestore database의 컬렉션에 새로운 문서 추가
  • 사용자가 문서 ID 지정
  • 문서 ID를 사용자가 알기 때문에, 기존 문서 업데이트 가능
import { doc, setDoc } from "firebase/firestore"; 

const docRef = doc(db, "collectionName", "customId123");  // customId123 문서 ID를 사용
await setDoc(docRef, {
  name: "홍길동",
  comment: "좋은 댓글입니다!"
});

 

 

 

동기와 비동기의 차이점

  1. 동기적 실행:
    • 코드가 위에서 아래로 순차적으로 실행 (하나의 작업이 끝난 후에 다음 작업 실행)
    • `console.log()`와 같은 동기적인 함수는 호출 순서대로 즉시 실행
  2. 비동기적 실행:
    • 비동기 함수는 즉시 실행을 시작하지만, 그 실행 결과가 완료될 때까지 기다리지 않고 다른 작업을 진행
    • `setTimeout()`, `setInterval()`, `fetch()`, `setDoc()`와 같은 함수들은 백그라운드에서 실행되며, 결과를 기다리는 동안 다른 코드실행
    • 비동기 함수가 `Promise`를 반환
    • `Promise` : 비동기적으로 실행하는 작업의 결과(성공 or 실패)를 나타내는 객체

 

비동기 코드를 동기적으로 실행하는 방법

1. `promise` / `.then()` / `.catch()`

  • `.then()`은 `Promise`가 완료된 후 호출될 콜백을 지정하는 방식으로, 코드가 여러 줄로 나누어져 가독성이 떨어질 수 있음
$("#addCommentBtn").click(function () {
    let name = $('#name').val();
    let content = $('#content').val();
    let customId = Date.now().toString();
    const docRef = doc(db, "Dotori", customId);

    setDoc(docRef, {
        id: customId,
        name: name,
        coment: content
    }).then(() => {
        // 문서 저장이 완료되면 페이지를 리로드
        window.location.reload();
    }).catch(error => {
        console.error("문서 추가 중 오류 발생:", error);
    });
});

 

 

   

2. `async` / `await`

  • `async`
    • 함수 앞에 async 키워드를 붙이면 해당 함수를 비동기 함수로 정의
    • 이 함수는 항상 Promise를 반환하며, 비동기 작업을 처리하는 데 사용
  • `await`
    • `await`은 `async` 함수 내부에서만 사용할 수 있으며, `Promise`가 해결될 때까지 대기
    • `await` 뒤에 오는 `Promise`가 완료되면, 그 결과 값을 반환
    • 즉, 비동기 코드가 완료될 때까지 기다린 후에 다음 코드 실행
$("#addCommentBtn").click(async function () {
    let name = $('#name').val();
    let content = $('#content').val();
    let customId = Date.now().toString();
    const docRef = doc(db, "Dotori", customId);
    
    await setDoc(docRef, {
        id: customId,
        name: name,
        coment: content
    });
    
    window.location.reload();
})

목적

음료의 이름과 금액 목록이 2차원 배열로 저장되어 있는 `drinks`와 사용자가 입력한 음료의 이름을 저장한 `drink`를 for-each문으로 비교하고, `drinks` 각 행의 첫 번째 값인 음료 이름과 `drink`가 동일한 값이면 그 음료의 금액을 출력하는 반복문을 작성하고자 했다.

for-each문의 선언된 배열 변수 `string`에 `drinks`의 각 행이 저장되고, 행을 차례대로 반복하도록 코드를 작성했다.

 

 

시도

1차 시도

for(String[] string:drinks){
	if(string[0]==drink) {
		price = Integer.valueOf(string[1]);
		System.out.println(price);
        break;
	}
}

 

-> 반복문이 price값을 출력하지 않고 종료하는 문제 발생

 

2차원 배열을 for-each문으로 반복시키는 건 처음하는 시도라 구글링을 했더니,

2차원 배열을 for-each문으로 반복하려면 반복문을 중첩해서 사용해야 했다.

// 2차원 배열의 for-each문 예시
int[][] array = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};

for (int[] row : array) {
    for (int value : row) {
        System.out.print(value + " ");
    }
    System.out.println();
}

 

 

2차 시도

코드를 조금 더 간편히 쓰기 위해서 for-each문을 사용했던 건데 더 복잡해졌기 때문에 for문으로 반복문을 작성했다.

for(int i=0;i<drinks.length;i++){
	if(drinks[i][0].equals(drink)) {
		price = Integer.valueOf(drinks[i][1]);
		System.out.println(price);
		break;
	}
}

 

=> 성공

 

 

결과