본문 바로가기

JAVA/Effective Java10

Item 32. 제네릭과 가변인수를 함께 쓸 때는 신중하라 ☁️ 가변인수와 제네릭은 궁합이 좋지 않다. 가변인수 기능은 내부적으로 배열을 사용하는데, 배열과 제네릭의 타입 규칙이 달라서 타입 안전하지 않다. (다만 제네릭 배열과 달리 제네릭 가변인수는 실무에서 매우 유용하게 사용되므로 제네릭 가변인수의 사용을 허용했다.) 제네릭 가변인수를 사용할 때는 배열에 값을 저장하거나 배열 참조를 외부에 노출해서는 안된다. 두 조건을 만족한다면 타입 안전한 것이므로 @SafeVarags을 사용해 경고를 무시한다. 혹은 가변인수 대신 List를 사용한다. Item 28. 제네릭과 배열 제네릭과 배열은 매우 다른 타입 규칙이 적용된다. 배열 : 공변이므로 컴파일타임에 안전하지 않지만, 실체화되므로 런타임에는 안전하다. 제네릭 : 공변이 아니므로 컴파일타임에 안전하고, 실체화되.. 2023. 7. 11.
Item27. 비검사 경고를 제거하라 요약 비검사 경고는 런타임에 ClassCastException을 일으킬 수 있는 잠재적 가능성을 뜻하므로, 가능한 모든 비검사 경고를 제거해야한다. 비검사 경고를 없앨 방법을 찾지 못한다면, 그 코드가 타입 안전함을 증명하고 가능한 범위를 좁혀서 @java.lang.SuppressWarnings("unchecked") 애노테이션으로 경고를 숨겨라. 그리고 경고를 숨기기로 한 근거를 주석으로 남겨라. 비검사 경고의 제거 비검사(unchecked) 경고는 컴파일러가 타입 안정성을 확인하는데 필요한 정보가 충분하지 않을 때 발생시키는 경고이다. 모든 비검사 경고는 런타임에 ClassCastException을 일으킬 수 있는 잠재적 가능성을 뜻하므로, 가능한 모든 비검사 경고를 제거해야한다. 대부분의 비검사 경.. 2023. 7. 11.
Item24. 멤버 클래스는 되도록 static으로 만들라 중첩 클래스는 자신을 감싼 바깥 클래스에서만 사용된다면 적절하다. 중첩 클래스에는 네 가지가 있으며, 쓰임이 각각 다르다. 멤버 클래스 인스턴스가 바깥 인스턴스를 참조한다면 non static으로, 인스턴스와 상관없이 독립적으로 존재한다면 static으로 만든다. 재사용되지 않는다면 익명 클래스로 만든다. 로컬 클래스는 거의 사용하지 않는다. 중첩 클래스 vs 톱 레벨 클래스 중첩 클래스는 자신을 감싼 바깥 클래스에서만 사용되어야 한다. 그 외의 쓰임새가 있다면 톱 레벨 클래스를 사용한다. 중첩 클래스는 외부 클래스를 통해서만 접근 가능하므로, 논리적인 의미로 클래스를 그룹핑해야할 때 사용할 수 있다. public class OuterClass { public static class NestedClass.. 2023. 6. 29.
Item23. 태그 달린 클래스보다는 클래스 계층 구조를 활용하라 💡 태그 달린 클래스는 응집도가 낮다. 응집도 높은 여러 클래스로 쪼개야 한다. 클래스 계층구조가 존재한다면 상속을 사용해 서브타입으로 구현하라. 태그 달린 클래스 태그란, 두 가지 이상의 의미를 표현하는 플래그이다. 태그 달린 클래스는 현재 표현하는 의미를 태그 값으로 알려주는 클래스이다. 다음은 원과 사각형을 표현하는 클래스이다. // Tagged class - vastly inferior to a class hierarchy! (Page 109) public class Figure { enum Shape { RECTANGLE, CIRCLE }; // Tag field - the shape of this figure final Shape shape; // These fields are used onl.. 2023. 6. 29.
Item18. 상속보다는 컴포지션을 사용하라 요약 구현 상속은 부모 클래스의 구현을 자식 클래스가 그대로 물려받으므로, 부모와 자식이 구현에 의해 강하게 결합되어 캡슐화가 깨진다. 만약 상위 클래스의 메서드 구현이 하위 클래스에 영향을 받지 않도록 만들고 싶다면, 상속보다 캡슐화를 잘 지키는 컴포지션을 사용하는 것이 좋다. 컴포지션은 기존 클래스를 새로운 클래스의 구성요소로 사용하는 것이며, 새 클래스의 인스턴스 메소드는 기존 클래스의 대응하는 메소드를 호출해 그 결과를 반환한다. 이 방식을 전달이라 한다. 컴포지션과 전달의 조합은 넓은 의미로 위임에 해당한다. 위임은 상속과 달리 캡슐화를 깨뜨리지 않으면서 코드를 재사용할 수 있다. 상속은 서브 타입을 사용할 경우에 유효하다. 코드를 재사용하는 목적이라면 상속은 부모와 자식의 강한 결합을 유발하므.. 2023. 5. 29.
Item10. equals는 일반 규약을 지켜 재정의하라 이 문서가 다루는 것 String Constant Pool equals의 일반 규약과 규약을 어기는 경우 리스코프 치환 원칙 바람직한 equals 구현 방법 세줄 요약 equals는 필요하지 않다면 재정의하지 않는다. 필요하다면 동치관계(반사, 대칭, 추이, 일관, null 아님)을 지켜야한다. 특히 상속 관계에서 equals를 비교하게 되면 하위 타입에서 사용하는 필드를 포함해서 상위 타입과 하위 타입을 비교하지 말아라. 상위 타입과 하위 타입 비교는 상위 타입의 필드로만 해라. 하위 클래스에서 자신의 필드를 포함한 equals를 사용하고 싶다면 상속 말고 합성으로 구현하고 포인트 뷰를 열어라. equals의 바람직한 정의 : 물리적 동치성 비교 → instanceOf 체크 후 변환 → 필드 비교 참고.. 2023. 5. 29.