-
아이템13. clone 재정의는 주의해서 진행하라Java/이펙티브 자바 2023. 6. 18. 16:38
핵심정리1 - clone 규약
핵심 정리 : 애매모호한 clone 규약
- clone 규약
ㆍx.clone() != x 반드시 true
ㆍx.clone().getClass() == x.getClass() 반드시 true
ㆍx.clone().equals(x) true가 아닐 수도 있다.
- 불변 객체라면 다음으로 충분하다.
ㆍCloenable 인터페이스를 구현하고
ㆍclone 메서드를 재정의한다. 이때 super.clone()을 사용
핵심정리2 - 가변 객체 clone 정의하는 방법
핵심 정리 : 가변 객체의 clone 구현하는 방법
- 접근 제한자는 public, 반호나 타입은 자신의 클래스로 변경한다.
- super.clone을 호출한 뒤 필요한 필드를 적절히 수정한다.
ㆍ배열을 복제할 때는 배열의 clone 메서드를 사용하라.
ㆍ경우에 따라 final을 사용할 수 없을지도 모른다.
ㆍ필요한 경우 deep copy를 해야한다.
ㆍsuper.clone 으로 객체를 만든 뒤, 고수준 메서드를 호출하는 방법도 있다.
ㆍ오버라이딩 할 수 있는 메서드는 참조하지 않도록 조심해야 한다.
ㆍ상속용 클래스는 Cloneable을 구현하지 않는 것이 좋다.
ㆍCloneable을 구현한 스레드 안전 클래스를 작성할 때는 동기화를 해야 한다.
핵심정리3 - clone 대안
생성자를 써서 copy를 만들 때 장점
- 생성자를 쓰면 명확하다.
- 모호한 규약 X
- final 사용 가능.
- 상위타입인 Collection 타입으로 받을 수 있다. (TreeSet)
public class PhoneNumber implements Cloneable{ private final short areaCode, prefix, lineNum; public PhoneNumber(int areaCode, int prefix, int lineNum) { this.areaCode = rangeChke(areaCode, 999, "area code"); this.prefix = rangeChke(prefix, 999, "prefix"); this.lineNum = rangeChke(lineNum, 9999, "line num"); } public PhoneNumber(PhoneNumber phoneNumber) { this(phoneNumber.areaCode, phoneNumber.prefix, phoneNumber.lineNum); } ... }
핵심정리 : clone 대신 권장하는 방법
- "복사 생성자" 또는 변환 생성자, "복사 팩터리" 또는 변환 팩터리
- 생성자를 쓰지 않으며, 모호한 규약, 불필요한 검사 예외, final 용법 방해 등에서 벗어날 수 있다.
- 또 다른 큰 장점 중 하나로 인터페이스 타입의 인스턴스를 리턴할 수 있다.
ㆍ클라이언트가 복제본의 타입을 결제할 수 있다.
- 읽어볼 것) Josh Bloch on Design, "Copy Constructor, Cloning"
완벽공략
- p80, 비검사 예외(UnChecked Exception)였어야 했다는 신호다.
- p81, HashTable과 LinkedList
- p83, 깊은 복사 (deep copy)
- p83, 리스트가 길면 스택 오버플로를 일으킬 위험이 있기 때문이다.
- p85, clone 메서드 역시 적절히 동기화해줘야 한다.
- p86, TreeSet
완벽공략29 - UncheckedException
왜 우리는 비검사 예외를 선호하는가?
- 컴파일 에러를 신경쓰지 않아도 되며,
- try~catch로 감싸거나
- 메서드 선언부에 선언하지 않아도 된다.
- 그렇다면 우리는 비검사 예외만 쓰면 되는걸까? 검사 예외는 왜 있는 것일까?
그렇다면 우리는 비검사 예외만 쓰면 되는걸까?
- 왜 잡지 않은 예외를 메서드에 선언해야 하는가?
ㆍ메서드에 선언한 예외는 프로그래밍 인터페이스의 일부다.
ㆍ즉, 해당 메서드를 사용하는 코드가 반드시 알아야 하는 정보다.
ㆍ그래야 해당 예외가 발생했을 상황에 대처하는 코드를 작성할 수 있을테니까
- 비검사 예외는 그럼 왜 메서드에 선언하지 않아도 되는가?
ㆍ비검사 예외는 어떤 식으로든 처리하거나 복구할 수 없는 경우에 사용하는 예외다.
ㆍ가령, 숫자를 0으로 나누거나, null 레퍼런스에 메서드를 호출하는 등
ㆍ이런 예외는 프로그램 전반에 걸쳐 어디서든 발생할 수 있기 때문에 이 모든 비검사 예외를 메서드에 선언하도록 강제한다면 프로그램의 명확도가 떨어진다.
* 왜 RuntimeException은 예외를 처리하도록 강제하지 않는가?
- RuntimeException는 복구할 수 있는 방법이 없다. 이 예외가 발생하면 클라이언트가 아무것도 할 수 없다.
언제 어떤 예외를 써야 하는가?
- 단순히 처리하기 쉽고 편하다는 이유만으로 RuntimeException을 선택하지는 말자.
- 가이드라인 : 클라이언트가 해당 예외 상황을 복구할 수 있다면 검사 예외를 사용하고, 해당 예외가 발생했을 때 아무것도 할 수 없다면, 비검사 예외로 만든다.
- https://docs.oracle.com/javase/tutorial/essential/exceptions/runtime.html
완벽공략30 - TreeSet
AbstractSet 을 확장한 정렬된 컬렉션
- 엘리먼트를 추가한 순서는 중요하지 않다.
- 엘리먼트가 지닌 자연적인 순서(natural order)에 따라 정렬한다.
- 오름차순으로 정렬한다.
- 스레드 안전하지 않다.
- 과제) 이진 검색 트리, 레드 블랙 트리에 대해 학습하시오.
'Java > 이펙티브 자바' 카테고리의 다른 글
아이템15. 클래스와 멤버의 접근 권한을 최소화하라 (0) 2023.06.27 아이템 14. Comparable을 구현할지 고민하라 (0) 2023.06.23 아이템 12. toString을 항상 재정의하라 (0) 2023.06.18 아이템11. equals를 재정의하려거든 hashCode도 재정의하라 (0) 2023.06.17 아이템10. equals는 일반 규약을 지켜 재정의하라 (0) 2023.06.07