JAVA/Effective Java 90

[아이템 20] 추상 클래스보다는 인터페이스를 우선하라

자바가 제공하는 다중 구현 방식은 아래와 같이 두 가지입니다. 추상 클래스 인터페이스 Java 8+ 버전부터 인터페이스도 default method를 제공할 수 있게 되어 두 메커니즘 모두 인스턴스 메서드를 구현 형태로 제공할 수 있다는 공통점이 있습니다. 한편 이 둘의 가장 큰 차이점은 아래와 같습니다. 추상 클래스 추상 클래스가 정의한 메서드를 구현하는 클래스는 반드시 추상 클래스의 하위 클래스가 되어야 같은 타입으로 취급합니다. 자바는 단일 상속만을 지원하기 때문에, 추상 클래스를 이용한 방식은 새로운 타입을 정의하는데 큰 제약이 따릅니다. 인터페이스 반면 인터페이스에서 정의한 메서드를 모두 정의한 클래스라면 다른 어떤 클래스를 상속했든 같은 타입으로 취급합니다. 추상클래스보다 확장에 용이하기 때문..

JAVA/Effective Java 2024.02.07

[아이템 19] 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라

설계 원칙 1. 상속용 클래스는 내부 구현을 문서로 남겨야 한다 "좋은 API 문서란 '어떻게'가 아닌 '무엇'을 하는지를 설명해야 한다"라는 격언과 달리 상속용 클래스는 재정의할 수 있는 메서드들을 내부적으로 어떻게 이용하는지 문서로 남겨야 합니다. 이는 상속을 하는 순간 캡슐화가 깨지기 때문입니다. 만약 상위 클래스 메서드의 내부 구현을 모르는 상태로 개발을 진행할 경우 아이템 18에서 다루었던 문제가 또다시 발생할 것입니다. 복습하자면 HashSet을 상속한 InstrumentedHashSet 클래스가 원소가 추가될 때마다 계측하는 용도로 add()와 addAll() 메서드를 재정의 재정의한 addAll() 메서드가 내부적으로 count 값을 올리고 원소 추가를 위해 상위 클래스의 addAll() ..

JAVA/Effective Java 2024.02.06

[아이템 18] 상속보다는 컴포지션을 사용하라

클래스가 다른 클래스를 확장하는 구현 상속 은 코드를 재사용하는 장점을 제공하지만, 이를 활용하는 경우에는 아래와 같은 상황에서만 고려해야 합니다. 상위 클래스와 하위 클래스를 모두 같은 프로그래머가 통제하는 패키지 내부일 경우 확장할 목적으로 클래스가 설계되었고 문서화도 잘 된 클래스 위 두 케이스에 해당하지 않는 경우, 즉 패키지 경계를 넘어 다른 패키지의 구체 클래스를 상속하면 아래의 이유로 인해 위험합니다. 상위 클래스에서 제공하는 메서드 구현이 변경되는 경우 상위 클래스에서 새로운 메서드가 생기는 경우 1. 상위 클래스에서 제공하는 메서드 구현이 변경되는 경우 하위 클래스의 동작은 하위 클래스의 구현 내용에 따라 변경될 수 있습니다. 즉 상위 클래스가 새로운 릴리스 때 내부 구현이 달라질 경우 ..

JAVA/Effective Java 2024.02.05

[아이템 17] 변경 가능성을 최소화하라

불변 클래스 불변 클래스란 인스턴스의 내부 값을 수정할 수 없는 클래스이며 immutable class라고 지칭합니다. 불변 클래스는 가변 클래스보다 설계, 구현 및 사용하기 쉽고 오류가 생길 여지가 적기 때문에 훨씬 안전합니다. 특히 멀티 쓰레드 환경에서 안전하게 사용할 수 있으며 값이 바뀌지 않기 때문에 캐싱을 할 수 있어 성능적으로도 유리합니다. 불변 클래스를 만드는 원칙 불변 클래스를 만드는 원칙은 아래와 같이 총 다섯 가지입니다. 객체의 상태를 변경하는 메서드를 제공하지 않는다 클래스를 확장할 수 없도록 한다 모든 필드를 final로 선언한다 모든 필드를 private으로 선언한다 자신 외에는 내부의 가변 컴포넌트에 접근할 수 없도록 한다. 1. 객체의 상태를 변경하는 메서드를 제공하지 않는다...

JAVA/Effective Java 2024.02.05

[아이템 16] public 클래스에서는 public 필드가 아닌 접근자 메서드를 사용하라

public 클래스 내 데이터 필드를 public으로 선언하여 직접 접근할 수 있게 할 경우 아이템 15에서 정리한 캡슐화의 이점을 취할 수 없습니다. 문제가 되는 이유 위 코드처럼 데이터 필드에 직접 접근할 경우 아래와 같은 문제점이 발생할 수 있습니다. 필드를 변경할 때 API 또한 변경해야 함 필드에 접근할 때 부가 작업 불가 불변식을 보장할 수 없음 1. 필드를 변경할 때 API 또한 변경해야 함 필드명을 변경하려면 해당 필드를 사용하는 모든 코드를 수정해야 합니다. 그러나 클래스를 public으로 선언하면 이는 공개 API로 간주되어, 실제로는 사용 중인 클라이언트 코드를 완전히 파악하는 것이 사실상 불가능합니다. 2. 필드에 접근할 때 부가 작업 불가 클라이언트가 필드에 직접 접근하면, 해당 ..

JAVA/Effective Java 2024.02.01

[아이템 15] 클래스와 멤버의 접근 권한을 최소화하라

클래스가 얼마나 잘 설계되었는지 평가하는 중요한 지표 중 하나는 캡슐화(encapsulation)입니다. 이는 내부 데이터와 구현 세부 정보가 외부 컴포넌트로부터 얼마나 효과적으로 숨겨져 있는지를 나타냅니다. 잘 설계된 컴포넌트의 경우 오직 API를 통해서만 다른 컴포넌트와 소통하며 서로의 내부 동작 방식에는 전혀 영향을 받지 않습니다. 자바는 캡슐화를 위한 다양한 장치를 제공하는데 그중 접근 제어 메커니즘은 클래스, 인터페이스, 멤버의 접근 허용 범위를 명시하며 해당 접근 제한자를 제대로 활용하는 것이 정보 은닉의 핵심입니다. 캡슐화 장점 컴포넌트를 캡슐화함으로써 취할 수 있는 장점은 아래와 같이 크게 5가지가 있습니다. 시스템 개발 속도를 높임 시스템 관리 비용을 낮춤 성능 최적화에 도움을 줌 소프트..

JAVA/Effective Java 2024.02.01

[아이템 14] Comparable을 구현할지 고려하라

Comparable 인터페이스의 compareTo() 메서드는 Object 클래스에서 지원하는 메서드는 아니지만 아이템 10에서 다룬 Object.equals() 메서드를 확장한 느낌입니다. compareTo 메서드 규약 compareTo 메서드의 규약은 아래와 같습니다. Object.equals() 메서드 규약인 반사성, 대칭성, 추이성, 그리고 일관성을 만족하면서 순서까지 비교 비교당하는 주체 this가 compareTo에 전달된 객체보다 작으면 음수, 같으면 0, 크다면 양수를 반환 -1, 0, 1이 아니라 음수, 0, 양수로 생각해야 함 comparetTo 메서드는 Generic을 지원하기 때문에 컴파일 시점에 타입 체킹 가능 웬만하면 compareTo 메서드의 결과가 0이라면 equals 메서드..

JAVA/Effective Java 2024.01.30

[아이템 13] clone 재정의는 주의해서 진행하라

Cloneable 인터페이스 Cloneable은 Object 클래스에 정의된 protected 메서드인 clone의 동작 방식을 결정하는 인터페이스입니다. Cloneable을 구현한 클래스의 인스턴스에서 clone을 호출할 경우 해당 객체의 필드들을 하나하나 복사한 객체를 반환하고 Clonable을 구현하지 않은 클래스에서 clone()을 호출할 경우 CloneNotSupportedException을 던집니다. 일반적으로 인터페이스를 구현한다는 것은 해당 클래스가 그 인터페이스에서 정의한 기능을 제공한다고 선언하는 행위인데 Cloneable의 경우 상위 클래스인 Object에 정의된 protected 메서드의 동작 방식을 변경한 것이기 때문에 인터페이스를 잘 못 사용한 예시라고 볼 수 있습니다. 정리하자..

JAVA/Effective Java 2024.01.29

[아이템 12] toString을 항상 재정의하라

모든 클래스는 암묵적으로 Object 클래스를 상속하기 때문에 별도로 toString 메서드를 오버라이딩하지 않았을 경우 Object의 toString 메서드를 사용합니다. 문제는 Object의 toString 메서드의 반환값이 아래와 같이 "[패키지를 포함한 클래스명]@[hashCode]" 형태를 띠기 때문에 유의미한 데이터가 아닙니다. toString은 보통 로깅할 때 사용되므로 간결하면서 사람이 읽기 쉬운 형태의 정보를 표출해야 하며 라이브러리의 도움을 받거나 직접 정의하는 방식을 선택해야 합니다. toString 구현 저자가 꾸준히 언급하는 구글의 AutoValue 혹은 Lombok의 도움을 통해 toString 구현이 가능합니다. 대부분 케이스에서는 Lombok에서 생성해주는 toString 메..

JAVA/Effective Java 2024.01.27

[아이템 11] equals를 재정의하려거든 hashCode도 재정의하라

앞서 아이템 10에서도 언급했다시피 equals를 오버라이딩했다면 hashCode 메서드도 같이 재정의해야 합니다. hashCode 메서드를 재정의하지 않을 경우 아래에 명시할 hashCode 일반 규약을 어기게 되어 해당 클래스의 인스턴스를 HashMap 혹은 HashSet 같은 컬렉션의 원소로 사용할 때 문제를 일으킬 것입니다. 두 객체에 대한 equals가 같다면, hashCode의 값도 동일해야 함 equals 비교에 사용하는 정보가 변경되지 않았다면 hashCode는 매번 같은 값을 반환 단, 정보가 변경되었거나 애플리케이션을 재기동했을 경우 변경될 수 있음 두 객체에 대한 equals가 다르더라도 hashCode의 값은 같을 수 있지만 해시 테이블 성능을 고려해 다른 값을 리턴하는 것이 좋음 ..

JAVA/Effective Java 2024.01.27