공공부하자개발 · 영어 학습 노트
자바
중급객체지향과 코어 라이브러리0/9 완료
  • 01상속, 다형성, 오버라이딩
  • 02추상 클래스 vs 인터페이스
  • 03예외 처리
  • 04java.lang 심화
  • 05컬렉션 프레임워크 딥다이브
  • 06메서드 활용 패턴 (중급)
  • 07Object 메서드와 비교
  • 08java.time 실무 날짜 계산
  • 09HTTP 와 JSON 기초
사이트 소개개인정보처리방침연락처
© 2026 공부하자
홈 › 중급 › 06 / 9

메서드 활용 패턴 (중급)

섹션 6진행 0 / 9
1왜 배우는가2핵심 원리3패턴 모음4자주 하는 실수 (Tip)5연습 문제6정리‹ 이전다음 ›

4. 자주 하는 실수 (Tip)

❌ 실수 1: equals만 구현하고 hashCode를 빠뜨림

java
public final class Point {
    int x, y;
    @Override public boolean equals(Object o) {
        return o instanceof Point p && p.x == x && p.y == y;
    }
    // hashCode 없음
}
Set<Point> s = new HashSet<>();
s.add(new Point(1, 2));
System.out.println(s.contains(new Point(1, 2)));   // false!

HashSet은 먼저 hashCode로 버킷을 찾고 그 안에서 equals를 봅니다. hashCode가 다르면 equals는 호출조차 되지 않습니다.

✅ 항상 쌍으로 구현합니다.

java
@Override public int hashCode() { return Objects.hash(x, y); }

❌ 실수 2: getter가 내부 컬렉션을 그대로 반환

java
public List<String> getItems() { return items; }

order.getItems().clear();      // 바깥에서 주문 내용이 통째로 사라짐

주소를 돌려줬으므로 호출자가 내 필드를 직접 조작하는 것과 같습니다.

✅ 불변 뷰 또는 복사본을 돌려줍니다.

java
public List<String> getItems() { return Collections.unmodifiableList(items); }

❌ 실수 3: 컬렉션 대신 null 반환

java
public List<String> findTags(String post) {
    if (noTags) return null;
    ...
}
for (String t : findTags(p)) { ... }     // NullPointerException

호출자 모두가 null 검사를 해야 하고, 하나라도 빠지면 NPE입니다.

✅ 빈 컬렉션을 돌려줍니다: return List.of();

❌ 실수 4: compareTo에서 뺄셈으로 비교

java
@Override public int compareTo(Money o) {
    return (int) (amount - o.amount);      // long → int 잘림, 오버플로우
}

amount = Long.MAX_VALUE, o.amount = -1이면 결과가 음수가 되어 순서가 뒤집힙니다. int끼리도 Integer.MIN_VALUE - 1에서 터집니다.

✅ Long.compare(amount, o.amount) 또는 Comparator.comparingLong(Money::amount)를 씁니다.

❌ 실수 5: with-메서드의 반환값을 버림

java
Money m = Money.of(1000);
m.withAmount(5000);
m.plus(Money.of(100));
System.out.println(m);      // 1,000원 — 아무것도 안 바뀜

불변 객체의 메서드는 자신을 바꾸지 않고 새 객체를 돌려줍니다.

✅ 반환값을 받습니다: m = m.withAmount(5000).plus(Money.of(100));

❌ 실수 6: equals 매개변수 타입을 바꿔서 오버로딩이 됨

java
public boolean equals(Money o) {          // Object가 아니라 Money
    return amount == o.amount;
}
List<Money> list = List.of(Money.of(1));
System.out.println(list.contains(Money.of(1)));     // false — Object.equals가 호출됨

컬렉션은 equals(Object)를 부릅니다. equals(Money)는 별개의 오버로딩이라 무시됩니다.

✅ @Override public boolean equals(Object o)로 쓰고 @Override를 붙여 컴파일러가 잡게 합니다.

❌ 실수 7: 템플릿 메서드를 자식이 덮어써서 순서가 깨짐

java
public abstract class Report {
    public String generate(List<String> rows) { ... }     // final이 아님
}
class BadReport extends Report {
    @Override public String generate(List<String> rows) { return "아무거나"; }   // 골격 무시
}

템플릿의 목적은 "순서를 고정"하는 것인데 자식이 통째로 바꿀 수 있으면 의미가 없습니다.

✅ 템플릿 메서드는 public final로 선언합니다.

자주 하는 실수 (Tip)
  • ❌ 실수 1: equals만 구현하고 hashCode를 빠뜨림
  • ❌ 실수 2: getter가 내부 컬렉션을 그대로 반환
  • ❌ 실수 3: 컬렉션 대신 null 반환
  • ❌ 실수 4: compareTo에서 뺄셈으로 비교
  • ❌ 실수 5: with-메서드의 반환값을 버림
  • ❌ 실수 6: equals 매개변수 타입을 바꿔서 오버로딩이 됨
  • ❌ 실수 7: 템플릿 메서드를 자식이 덮어써서 순서가 깨짐
이전 섹션3 패턴 모음4 / 6다음 섹션5 연습 문제