기술용어
기술 용어는 대부분 자바 8용 언어 명세(The Java Language Specifition, Java SE 8 Edition)[JLS]를 따르며, 주요 사항은 다음과 같습니다.
자바가 지원하는 타입(type; 자료형)은 인터페이스(Ineterface), 클래스(class), 배열(array), 기본타입(primitive)까지 총 네가지 입니다.
애너테이션(annotation)은 인터페이스의 일종이며 열거 타입(enum)은 클래스의 일종입니다.
네 가지 타입 중 처음 세가지는 참조 타입(reference type)이라고 합니다. 즉 클래스의 인스턴스와 배열은 객체(Object)인 반면, 기본 타입 값은 그렇지 않습니다.
클래스의 멤버로는 필드(field), 메서드(method), 멤버 클래스, 멤버 인터페이스가 있습니다.
메서드 시그니처는 메서드 이름과 입력 매개변수(parameter)의 타입들로 이뤄집니다.(반환값의 타입은 시그니처에 포함되지 않습니다.)
API(application programming interface)는 프로그래머가 클래스, 인터페이스, 패키지를 통해 접근할 수 있는 모든 클래스, 인터페이스, 생성자, 멤버, 직렬화된 형태(serialized form)를 말한다.
API를 사용하는 프로그램 작성자(사람)를 그 API의 사용자(user)라 하고, API를 사용하는 클래스(코드)는 그 API의 클라이언트(client)라 한다.
1. 생성자 대신 정적 팩터리 메서드를 고려하라
클래스는 생성자와 별도로 정적 팩터리 메서드(static factory method)를 제공할 수 있다.
정적 팩터리 메서드와 public생성자는 각자의 쓰임새가 있으니 상개적인 장단점을 이해하고 사용하는 것이 좋다. 그렇다고 하더라도 정적 팩터리를 사용하는 게 유리한 경우가 더 많으므로 무작정 public 생성자를 제공하던 습관이 있다면 고치자
정적 팩터리 메서드가 생성자보다 좋은 장점 5가지
- 이름을 가질 수 있다.
- 호출될 떄마다 인스턴스를 새로 할당하지 않아도 된다.
- 반환 타입의 하위 타입 객체를 반환할 수 있다.
- 입력 매개변수에 따라 매번 다른 클래스의 객체를 반환할 수 있다.
- 정적 팩터리 메서드를 작성하는 시점에는 반환할 객체의 클래스가 존재하지 않아도 된다.
단점 2가지
- 상속을 하려면 public이나 protected 생성자가 필요하니 정적 팩터리 메서드만 제공하면 하위 클래스를 만들 수 없다.
- 정적 팩터리 메서든느 프로그래머가 찾기 어렵다.
2. 생성자에 매개변수가 많다면 빌더를 고려하라
생성자나 정적 팩터리가 처리해야 할 매개변수가 많다면 빌더 패턴을 선택하는게 낫다. 매개변수 중 다수가 필수가 아니거나 같은 타입이면 특히 더 그렇다. 빌더는 점층적 생성자보다 클라이언트 코드를 읽고 쓰기가 훤씬 간결하고, 자바빈드보다 훨씬 안전하다.
점층적 생성자 패턴도 쓸 수는 있지만, 매개변수 개수가 많아지면 클라이언트 코드를 작성하거나 읽기 어렵다.
대안으로 자바빈즈패턴(JavaBeans pattern)을 보면, 매개변수가 없는 생성자로 객체를 만든 후 setter 메서드를 호출해서 매개변수의 값을 지정하는 방식이다. 그러므로 객체 하나를 만드려면 메서드를 여러개 호출해야하고, 객체가 완전히 생성되기 전까지 일관성(consistency)가 무너지고, 클래스 불변으로 만들 수 없다.
점층적 생선자 패턴의 안정성과 자바빈즈패턴의 가독성을 겸비한 빌더 패턴(Builder pattern)이 있다.
3. private 생성자나 열거 타입으로 싱글턴임을 보증하라
싱글턴(singleton)이란 인스턴스를 오직 하나만 생성할 수 있는 클래스를 말한다. 싱글턴의 전형적인 예로는 함수와 같은 무상태(stateless) 객체나 설계상 유일해야 하는 시스템 컴포넌트를 들 수 있다.
4. 인스턴스화를 막으려거든 private 생성자를 사용하라
단순히 정적 메서드와 정적 필드만을 담은 클래스를 만들고 있을 때가 있을 것이다.
생성자를 명시하지 않으면 컴파일러가 자동으로 기본 생성자를 만들어준다. 즉, 매개변수를 받지 않는 public 생성자가 만들어지며, 사용자는 이 생성자가 자동 생성된 것인지 구분할 수 없다.
그래서 private 생성자를 추가하면 클래스의 인스턴스화를 막을 수 있다.
5. 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라
클래스가 내부적으로 하나 이상의 자원에 의존하고, 그 자원이 클래스 동작에 영향을 준다면 싱글턴과 정적 유틸리티 클래스는 사용하지 않는 것이 좋다. 이 자원들을 클래스가 직접 만들게 해서도 안 된다. 대신 필요한 자원을(혹은 그 자원을 만들어주는 팩터리를) 생성자에(혹은 정적 팩터리나 빌더에) 넘겨주자. 의존 객체 주입이라 하는 이 기법은 클래스의 유연성, 재사용성, 테스트 용이성을 기막히게 개선해준다.
6. 불필요한 객체 생성을 피하라
똑같은 기능의 객체를 매번 생성하기보다는 객체 하나를 재사용하는 편이 나을 때가 많다.
그 예로 오토박싱(auto boxing)이 있다. 오토박싱은 프로그래머가 기본 타입과 박싱된 기본 타입을 섞어 쓸 때 자동으로 상호 변환해주는 기술이다. 오토박싱은 기본 타입과 그에 대응하는 박싱된 기본 타입의 구분을 흐려주지만, 완전히 없애주는 것은 아니다.
박싱된 기본 타입보다는 기본 타입을 사용하고, 의도치 않은 오토박싱이 숨이들디 않도록 주의해야 한다.
7. 다 쓴 객체 참조를 해제하라
메모리 누수는 잘 드러나지 않아 시스템에 수년간 잠복하는 사례도 있다. 이런 누수는 철저한 코드 리뷰나 힙 프로파일러 같은 디버깅 도구를 동원해야만 발견되기도 한다. 그래서 이런 종류의 문제는 예방법을 익혀두는 것이 매우 중요하다.
8. finalizer와 cleaner 사용을 피해라
clearner(자바 8까지는 finalizer)는 안정망 역할이나 중요하지 않은 네이티브 자원 회수용으로만 사용하자. 물론 이런 경우라도 불확실성과 성능저하에 주의해야 한다.
자바는 두 가지 객체 소멸자를 제공한다. 그중 finalizer는 에측할 수 없고, 상황에 따라 위험할 수 있어서 일반적으로 불 필요하다. clearner는 finalizer보다는 덜 위험하지만, 여전히 예측할 수 없고, 느리고, 일반적으로 불필요하다.
9. try-finally보다는 try-with-resources를 사용하라
꼭 회수해야 하는 자원을 다룰 때는 try-finally말고, try-with-resources를 사용하다. 예외는 없다. 코드는 더 짧고 분명해지고, 만들어지는 예외 정보도 훤씬 유용하다. try-finally로 작성하면 실용적이지 못할 만큼 코드가 지저분해지는 경우라도, try-with-resources로는 정확하고 쉽게 자원을 회수할 수 있다.
https://github.com/oss0202/EffectiveJava/tree/main/src/first
출처
http://www.yes24.com/Product/Goods/65551284
'Effective Jave 3E' 카테고리의 다른 글
[Effective Jave 3E] 이펙티브 자바 들어가며... (0) | 2021.06.07 |
---|