TrouBle 1. Calculator 클래스를 분리하라는데, 어디서부터 어떻게 해야 하는지 몰랐다.
Lv.1에서는 main 메서드 하나 안에 입력, 계산, 출력이 전부 들어가 있었다. Lv.2에서 Calculator를 따로 만들라는 요구사항을 보고 머리론 알겠는데도 감이 안 잡혔다. 어떤 코드를 어디로 옮겨야 하는 건지, 두 파일이 어떻게 연결되는 건지가 강의를 그렇게도 많이 봤건만 막상 시작하려니 막막했다.
// Lv.1 방식: main이 모든 걸 다 함
public static void main(String[] args) {
// 입력 받고, 계산하고, 출력까지 전부 여기서
if (operator == '+') result = num1 + num2;
System.out.println("결과: " + result);
}
// Lv.2 방식: 역할 분리
// Calculator.java → 계산만 담당
public class Calculator {
public Integer calculate(int num1, int num2, char operator) {
// 계산 로직만 여기에
}
}
// App.java → 흐름 관리만 담당
public class App {
public static void main(String[] args) {
Calculator calculator = new Calculator(); // Calculator 인스턴스화
Integer result = calculator.calculate(num1, num2, operator); // 결과 받기
}
}
Lv.1은 혼자 주문받고 요리하고 서빙까지 다 하는 구조다. Lv.2는 홀 직원(App)이 주문을 받아서 주방(Calculator)에 넘기고, 주방이 결과를 돌려주는 구조다. App은 "어떻게 계산하는지" 알 필요가 없고, Calculator는 "사용자가 뭘 입력했는지" 알 필요가 없다.
TrouBle 2. Calculator 인스턴스를 왜 new로 만들어야 하는지 몰랐다
App.java에서 Calculator의 메서드를 쓰려고 바로 calculator.calculate()를 호출했더니 오류가 났다. 클래스 파일이 있는데 왜 안 된다는 건지 이해가 안 됐다.
클래스는 설계도 일뿐, 실제로 쓰려면 new로 인스턴스(실체)를 먼저 만들어야 한다. 설계도만 있고 실제 객체가 없는 상태에서 메서드를 부르면 오류 발생.
public class App {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
Calculator calculator = new Calculator(); // 인스턴스화 - 이 줄이 없으면 오류
// 이제 calculator.calculate(), calculator.getResults() 사용 가능
}
}
클래스 = 설계도, new 클래스명() = 설계도로 실제 물건 만들기. 물건이 있어야 쓸 수 있다.
TrouBle 3. 결과를 어떻게 저장해야 하는지 몰랐다
계산할 때마다 결과를 쌓아야 하는데, 배열(int[])을 쓰려니 크기를 미리 정해야 해서 몇 번 계산할지 모르는 상황에선 안 됐다.
배열은 선언할 때 크기가 고정된다. 계산 횟수가 정해지지 않은 상황에선 크기가 자동으로 늘어나는 컬렉션이 필요하다.
import java.util.ArrayList;
import java.util.List;
public class Calculator {
private List<Integer> results = new ArrayList<>();
// ArrayList는 크기 자동 증가
// Integer = int의 포장 버전 (ArrayList는 기본형 int를 바로 못 담음)
}
기본 동작:
results.add(result); // 결과 추가
results.get(0); // 첫 번째 값 조회
results.remove(0); // 첫 번째 값 삭제
구분 배열 int[] ArrayList
| 크기 | 선언 시 고정 | 자동 증가 |
| 추가 | 불가 | add() |
| 삭제 | 불가 | remove() |
| 이번 과제 적합성 | 부적합 | 적합 |
TrouBle 4. calculate() 메서드에서 return 쓰면 빨간줄이 떴다
Lv.1에서는 0으로 나누거나 잘못된 연산자를 입력하면 sout으로 메시지 출력하고 return으로 종료했다. Lv.2 Calculator 클래스에서 그걸 그대로 옮겼더니 빨간줄이 뜨면서 컴파일이 안 됐다.
main 메서드의 반환 타입은 void라서 return으로 그냥 끝낼 수 있다. 하지만 calculate() 메서드의 반환 타입은 Integer다. return만 쓰면 반환값이 없어지는데, Integer를 돌려줘야 하는 메서드가 아무것도 안 돌려주면 컴파일 오류가 난다.
// Lv.1 방식 (void 메서드에서는 가능)
if (num2 == 0) {
System.out.println("0으로 나눌 수 없습니다.");
return; // void니까 그냥 끝낼 수 있음
}
// Lv.2 방식 (반환 타입이 있는 메서드에서)
if (num2 == 0) {
throw new ArithmeticException("0으로 나눌 수 없습니다.");
// throw는 예외를 던지고 끝내기 - 반환값 없어도 됨
}
throw를 쓰면 "이 상황은 비정상"이라는 신호를 보내고 메서드를 끝낼 수 있다. 반환값이 없어도 된다.
예외 종류 언제 쓰나
| ArithmeticException | 수학적으로 불가능한 연산 (0으로 나누기) |
| IllegalArgumentException | 허용되지 않는 입력 (지원 안 하는 연산자) |
TrouBle 5. 캡슐화를 왜 해야 하는지 몰랐다
상황 results 필드를 public으로 만들었다. App에서 값을 불러오면 되니까 문제없다고 생각했다.
원인 public이면 외부에서 마음대로 수정할 수 있다. calculator.results.add(999)나 calculator.results.clear() 같은 코드가 App 어디서든 실행될 수 있어서 내가 의도한 대로 동작하지 않을 수 있다.
해결
public class Calculator {
private List<Integer> results = new ArrayList<>(); // private으로 변경
public List<Integer> getResults() { // getter - 읽기만 허용
return results;
}
public void removeResult() { // 삭제는 이 메서드로만
if (!results.isEmpty()) {
results.remove(0);
}
}
}
App에서는 직접 접근 대신 getter를 쓴다.
// 직접 접근 (캡슐화 전)
calculator.results.add(999); // 마음대로 수정 가능 - 위험
// getter 사용 (캡슐화 후)
System.out.println(calculator.getResults()); // 읽기만 가능
기억 포인트: private = 외부에서 직접 건드리기 불가. getter = 읽기 전용 창구.
학습 메모
Lv.2에서 제일 당황했던 건 파일이 두 개로 쪼개지면서 어디서부터 읽어야 할지, 또 어디서부터 설계를 해야할지 감이 안 왔다는 거다. App이 Calculator를 부르고, Calculator가 결과를 돌려주고, 그 결과를 App이 출력한다는 흐름을 머릿속에 잡아야 전체 구조가 보인다.
return 대신 throw로 바꿔야 한다는 것도 처음엔 왜 그런지 몰랐는데, 반환 타입이 있는 메서드에서 아무것도 안 돌려주면 컴파일이 안 된다는 점을 알게됐다.
캡슐화는 개념도 약하고 "왜 굳이 막나"가 이해가 안 됐는데, 외부에서 특강 때 들었던 네이버 인턴인 내가 회사 코드를 마음대로 수정하면 벌어지게될 참사를 생각하니 납득이 됐다.
다음 과제 목표: Lv.3 - Enum, 제네릭, 스트림 적용
핵심 요약
개념 내용
| 클래스 분리 | Calculator = 계산 담당 / App = 입출력 + 흐름 담당 |
| 인스턴스화 | new Calculator()로 실체를 만들어야 메서드 사용 가능 |
| ArrayList | 크기 자동 증가 / add(), remove(), get() |
| throw | 반환 타입 있는 메서드에서 예외 상황 처리 (return 대신) |
| 캡슐화 | private 필드 + getter로 외부 직접 접근 차단 |
'Camp > 과제' 카테고리의 다른 글
| [Java] 계산기 과제 Lv.2 트러블 슈팅- 클래스 분리가 왜 이렇게 헷갈렸나 (0) | 2026.06.19 |
|---|---|
| [Java] 코드카타 트러블 슈팅 (0) | 2026.06.17 |
| [TIL] CH2 Java 계산기 과제 again (트러블 슈팅) (0) | 2026.06.15 |
| [TIL] CH2 Java 계산기 과제 (트러블 슈팅) (0) | 2026.06.12 |
| [TIL]웹개발 기초 과제 맛집 관리 API (1) | 2026.05.29 |