[멋사 클라우드 5기] Day 9 - Enum 활용, BigNumber, Lombok, 객체 설계

2026. 2. 3. 00:53·Learning Log

3주차가 되니 1주차에 비해 실습 시간이 많이 늘어난 것이 느껴진다.
지금까지 배운 문법들을 바탕으로 코드를 확장하고,
디자인 패턴을 적용해보면서
현실의 개념을 점점 더 구조적으로 표현해가는 과정이 흥미롭다.

JS와 비슷하면서도 다른 부분들이 있어 헷갈릴 때도 있지만,
복습을 통해 차근차근 익숙해져 가면 될 것 같다.


1. Enum 활용 - 할인 정책을 객체로 표현하기

요구사항 다시 보기

  • 할인 정책은 다음 3가지
    • FIXED: 고정 1,000원 할인
    • PERCENT: 10% 할인
    • NONE: 할인 없음
  • 각 정책은 서로 다른 할인 로직을 가진다

구현 코드

public enum DiscountPolicy {
    FIXED("고정 금액 1000 할인") {
        @Override
        public int applyDiscount(int price) {
            return price - 1000;
        }
    },
    PERCENT("10% 할인") {
        @Override
        public int applyDiscount(int price) {
            return (int) (price * 0.9);
        }
    },
    NONE("할인 없음") {
        @Override
        public int applyDiscount(int price) {
            return price;
        }
    };

    private final String description;

    DiscountPolicy(String description) {
        this.description = description;
    }

    public String getDescription() {
        return description;
    }

    public abstract int applyDiscount(int price);
}

2. DiscountPolicy Enum의 의미

위의 Enum은 상수묶음 이상의 역할을 한다.

할인 정책(행동)을 캡슐화한 Enum

  • FIXED, PERCENT, NONE는
    • 값이면서
    • 동시에 서로 다른 로직을 가진 객체

👉 if / switch 없이
👉 정책을 객체로 분리한 구조

헷갈리는 문법: Enum 상수 뒤의 { ... }

FIXED("고정 1,000원 할인") {
    @Override
    public int applyDiscount(int price) {
        return price - 1000;
    }
}

이 문법의 정체는? Enum 상수별 익명 클래스(anonymous class)

컴파일러는 아래처럼 이해한다:

DiscountPolicy FIXED =
    new DiscountPolicy("고정 1,000원 할인") {
        @Override
        public int applyDiscount(int price) {
            return price - 1000;
        }
    };
  • Enum 상수 하나 = DiscountPolicy의 하위 클래스 인스턴스
  • 그래서 상수마다 메서드를 다르게 구현 가능

override 대신 람다로 구현한다면?

가능하다. (사실 이전 포스트에서 다뤘다)
단, 조건이 있는데

행동을 함수형 인터페이스로 분리해야 한다

람다 기반 Enum으로 재작성

import java.util.function.IntUnaryOperator;

public enum DiscountPolicy {
    FIXED("고정 1,000원 할인", price -> price - 1000),
    PERCENT("10% 할인", price -> (int)(price * 0.9)),
    NONE("할인 없음", price -> price);

    private final String description;
    private final IntUnaryOperator operator;

    DiscountPolicy(String description, IntUnaryOperator operator) {
        this.description = description;
        this.operator = operator;
    }

    public String getDescription() {
        return description;
    }

    public int applyDiscount(int price) {
        return operator.applyAsInt(price);
    }
}

3. BigInteger - 아주 큰 정수 다루기

BigInteger란?

  • int, long 범위를 초과하는 임의 정밀도 정수
  • 메모리가 허용하는 한 크기 제한 없음
  • 불변(immutable) 객체
BigInteger big1 = new BigInteger("12345678901234567890");
BigInteger big2 = BigInteger.valueOf(100);

BigInteger sum = big1.add(big2);
BigInteger power = big2.pow(100);

BigDecimal — 정확한 소수 계산

왜 필요한가?

0.1 + 0.2 == 0.3  // false (double)

👉 금융, 금액 계산에서 double은 부정확

BigDecimal 특징

  • 정확한 소수 계산
  • 스케일(소수점 자리수) 제어 가능
  • 불변 객체
  • 연산자는 사용 불가 (메서드 호출)
BigDecimal price = new BigDecimal("19.99");
BigDecimal quantity = new BigDecimal("3");

BigDecimal total = price.multiply(quantity);
BigDecimal result =
    total.divide(new BigDecimal("7"), 2, RoundingMode.HALF_UP);

주의사항 1 - divide 예외

bd1.divide(bd2);

❌ ArithmeticException 발생

이유

  • 나눗셈 결과가 무한 소수
  • BigDecimal은 정확한 결과를 기본으로 요구

해결

bd1.divide(bd2, RoundingMode.HALF_UP);

반올림 전략을 명시해야 함


주의사항 2 - equals vs compareTo

BigDecimal n1 = new BigDecimal("1.0");
BigDecimal n2 = new BigDecimal("1.00");

n1.equals(n2);    // false
n1.compareTo(n2); // 0
  • equals: 값 + 스케일 비교
  • compareTo: 수학적 값만 비교

👉 금액 비교는 compareTo 권장


4. Lombok - 보일러플레이트 제거 도구

Lombok이란?

  • Getter, Setter, equals 등 반복 코드 자동 생성
  • 어노테이션 기반
  • 컴파일 시점에 코드 생성

“컴파일 시점에 동작한다”는 의미

  • 실행 중에 동작 ❌
  • 컴파일 단계에서 소스/바이트코드를 수정
  • 애노테이션 프로세서(annotation processor)가 핵심

module-info.java 와 Lombok 충돌 원인

  • module-info.java 존재 → 모듈 프로젝트
  • Lombok은 전통적인 Classpath + annotation processing 흐름을 기대
  • Eclipse에서 모듈 경로 + Lombok 설정이 꼬이면:
    • import문이 정상적으로 인식되지 않고
    • 어노테이션도 당연히 동작하지 않는다

👉 module-info.java 제거 → Classpath 기반 → 정상 동작


@EqualsAndHashCode

equals()와 hashCode()는 해시 기반 컬렉션(HashSet, HashMap)에서 항상 같이 맞물려 동작한다.
equals()가 true면 hashCode()도 같아야 한다는 규칙을 어기면, 중복 제거/조회가 깨지는 버그가 생길 수 있다.
그래서 Lombok은 두 메서드를 “세트”로 안전하게 자동 생성해주는 @EqualsAndHashCode를 제공한다.

기본 설정은 모든 필드를 비교 기준으로 삼기 때문에 위험할 수 있다.
“pno가 같으면 동일한 Person”이라는 규칙일땐 다음처럼 특정 필드만 비교 기준으로 잡을 수 있다.

@EqualsAndHashCode(of = "pno")
public class Person {
  private int pno;
  private String name;
  private String mbti;
}

Lombok 남용 시 주의점

  • 모든 필드 비교 → 도메인 규칙 흐려짐
  • 무분별한 Setter → 불변성 깨짐

Lombok이 잘 어울리는 경우

  • DTO (Data Transfer Object)
  • VO (Value Object)

5. 객체 생성 패턴

1. 정적 팩토리 메서드

  • 생성자 대신 static 메서드
  • 이름으로 의도 표현
  • 반환 타입 유연
// ❌ 생성자만 쓸 때 (의미가 안 보임)
User user = new User("jc", true);

// ✅ 정적 팩토리 메서드 사용
public class User {
    private final String name;
    private final boolean admin;

    private User(String name, boolean admin) {
        this.name = name;
        this.admin = admin;
    }

    public static User normal(String name) {
        return new User(name, false);
    }

    public static User admin(String name) {
        return new User(name, true);
    }
}

// ✅ 직관적인 객체 생성
User user1 = User.normal("jc");
User user2 = User.admin("root");

 

 

2. 빌더 패턴

  • 필드 많을 때 유용
  • @Builder 활용 가능(선언 위치에 따라 통제가 달라짐)
    • 클래스에 붙이면 모든 필드를 대상으로 빌더가 생성되며,
    • 생성자에 붙이면 “생성자 파라미터로 노출된 필드만” 빌더에 포함
      👉 외부 노출을 통제하고 필수값 검증 로직을 생성자에서 설계
public class User {
    private final String name;
    private final int age;
    private final String city;

    private User(Builder b) {
        this.name = b.name;
        this.age = b.age;
        this.city = b.city;
    }

    public static class Builder {
		...

        public Builder(String name, int age) {
            this.name = name;
            this.age = age;
        }

        public Builder city(String city) {
            this.city = city;
            return this;
        }

        public User build() {
            return new User(this);
        }
    }
  }

}

// ✅ 사용
User user = new User.Builder("jc", 30)
        .city("Seoul")
        .build();

6. Maven

Maven이란?

  • 빌드 + 의존성 관리 도구
  • 라이브러리 다운로드/버전 관리 자동화

pom.xml 역할

  • 프로젝트 설정 파일
  • 의존성, 플러그인, 빌드 설정 정의
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.42</version>
</dependency>

👉 jar 직접 추가보다 훨씬 안전하고 편리


 

'Learning Log' 카테고리의 다른 글

[멋사 클라우드 5기] Day 11 - DBMS 기초(2), DQL  (0) 2026.02.05
[멋사 클라우드 5기] Day 10 - 객체 다루기, DBMS 기초(1)  (0) 2026.02.04
[멋사 클라우드 5기] Day 8 - 입출력, 직렬화, 스레드, Enum  (0) 2026.02.02
[멋사 클라우드 5기] Day 7 - Lambda · Stream 심화 + Optional  (0) 2026.01.30
[멋사 클라우드 5기] Day 6 - 자료구조, Lambda, Stream  (0) 2026.01.29
'Learning Log' 카테고리의 다른 글
  • [멋사 클라우드 5기] Day 11 - DBMS 기초(2), DQL
  • [멋사 클라우드 5기] Day 10 - 객체 다루기, DBMS 기초(1)
  • [멋사 클라우드 5기] Day 8 - 입출력, 직렬화, 스레드, Enum
  • [멋사 클라우드 5기] Day 7 - Lambda · Stream 심화 + Optional
allluck777
allluck777
allluck777
    • 분류 전체보기 (44) N
      • AWS (0)
      • Network (0)
      • Linux (0)
      • Docker (0)
      • Project (4)
        • CloudNote (4)
      • Learning Log (36) N
      • Lecture (3)
        • 스프링 입문 - 코드로 배우는 스프링 부트, 웹 .. (3)
  • 전체
    오늘
    어제
  • hELLO· Designed By정상우.v4.10.6
allluck777
[멋사 클라우드 5기] Day 9 - Enum 활용, BigNumber, Lombok, 객체 설계
상단으로

티스토리툴바