[Effective Java] 아이템 25 : 톱 레벨 클래스는 한 파일에 하나만 담으라

Loopy·2022년 7월 23일
0

이펙티브 자바

목록 보기
24/76
post-thumbnail

소스 파일 하나에 톱 레벨 클래스를 여러개 선언하는 것은, 심각한 위험을 감수해야 하는 행위이다. 한 클래스를 여러 가지로 정의할 수 있으며, 그 중 어느 것을 사용할지는 어느 소스를 먼저 컴파일하느냐에 따라 달라지기 때문이다.

구체적인 예시를 들어보자.

public class Main {
    public static void main(String[] args) {
        System.out.println(Utensil.NAME + Dessert.NAME);
    }
}

다음은 두 클래스를 한 파일에 담아보았다.

class Utensil {
    static final String NAME = "pan";
}

class Dessert {
    static final String NAME = "cake";
}
class Utensil {
    static final String NAME = "pot";
}

class Dessert {
    static final String NAME = "pie";
}

javac Main.java Dessert.java 명령으로 컴파일 한다면, 운좋게 오류가 나며 두 클래스를 중복 정의했다고 알려줄 것이다.

📚 컴파일 과정
1. Main.java 컴파일
2. Utensil 참조를 보고 Utensil.java 파일에서 Utensil + Dessert를 찾아냄
3. 두 번째 명령어 인수줄의 Dessert.java 를 처리하려 할때 에러 발생

하지만 javac Main.java 혹은 javac Main.java Utensil.java 로 컴파일을 하면은 pancake을 출력하고, javac Dessert.java Main.java 로 컴파일을 하면은 potpie를 출력한다.

"이처럼 컴파일러에 어느 소스 파일을 먼저 건네느냐에 따라 동작이 달라지는 문제가 발생하는 것이다."

☁️ 문제의 해결책: 파일 분리

단순히 톱 레벨 클래스들(Utensil, Dessert)를 서로 다른 소스 파일로 분리하기만 하면 문제가 해결된다.

굳이 여러 톱레벨 클래스를 한 파일에 담고 싶다면, 정적 멤버 클래스를 고려해보자. 읽기도 좋고, private 으로 선언 하면 접근 범위도 최소로 관리할 수 있기 때문이다.

▶️ 톱레벨 클래스들을 정적 멤버 클래스로 변경

public class Test {
    public static void main(String[] args) {
        System.out.println(Utensil.NAME + Dessert.NAME);
    }

    private static class Utensil {
        static final String NAME = "pan";
    }

    private static class Dessert {
        static final String NAME = "cake";
    }
}

📚 핵심 정리
소스 파일 하나에는 반드시 톱레벨 클래스(혹은 톱레벨 인터페이스)를 하나만 담자. 이 규칙만 따른다면 컴파일러가 한 클래스에 대한 정의를 여러 개 만들어내는 일은 사라진다. 소스 파일을 어떤 순서로 컴파일하든 바이너리 파일이나 프로그램의 동작이 달라지는 일은 결코 일어나지 않을 것이다.

profile
개인용으로 공부하는 공간입니다. 잘못된 부분은 피드백 부탁드립니다!

0개의 댓글