JAVA 95

[아이템 40] @Override 애너테이션을 일관되게 사용하라

자바가 기본으로 제공하는 어노테이션 중 보통의 개발자에게 가장 중요한 것은 @Override 어노테이션입니다. @Override는 메서드 선언에만 달 수 있으며, 해당 어노테이션이 달렸다는 것은 상위 타입의 메서드를 재정의했음을 뜻합니다. 오버라이딩과 오버로딩 차이는 꼭 숙지 필요 상위 타입과 동일한 메서드 시그니처가 같으면 오버라이딩, 시그니처가 다르면 오버로딩 @Override를 선언하지 않은 메서드 코드 부연 설명 똑같은 소문자 2개로 구성된 바이그램 26개를 10번 반복해 Set에 추가한 후 해당 Set의 크기를 출력하는 프로그램 Set은 중복을 허용하지 않기 때문에 26이 출력될 것으로 예상하지만 실제 값은 260 HashSet은 내부적으로 equals 메서드를 기반으로 객체의 논리적 동치성 검..

JAVA/Effective Java 2024.02.28

[아이템 39] 명명 패턴보다 애너테이션을 사용하라

1. 명명 패턴의 문제점 메서드나 타입의 이름을 특정 규칙으로 짓고 해당 규칙을 지켜 만든 메서드나 타입 등에 추가적인 처리를 제공하는 것을 명명 패턴이라고 합니다. JUnit은 3 버전까지 테스트 메서드의 이름을 "test"로 시작하도록 규정하였습니다. 그러나 이러한 명명 패턴에는 다음과 같은 단점이 있어서, JUnit 4부터는 @Test 어노테이션을 사용하는 방식으로 변경되었습니다. 오타에 취약 올바른 프로그램 요소에서만 사용되리라 보증할 수 없음 프로그램 요소를 매개변수로 전달할 방법이 없음 1.1 오타에 취약 명명 패턴은 메서드명이나 타입명을 기준으로 구분하기 때문에 오타에 취약합니다. 이전에 언급한대로 JUnit 3 버전까지는 테스트 메서드의 이름이 "test"로 시작해야 했습니다. 그러나 사용..

JAVA/Effective Java 2024.02.28

[아이템 38] 확장할 수 있는 열거 타입이 필요하면 인터페이스를 사용하라

아이템 34에서 언급한 대로 열거 타입은 거의 모든 상황에서 타입 안전 열거 패턴보다 우수합니다. 단, 한가지 예외 사항이 있습니다. Enum 클래스는 밖에서 접근할 수 있는 생성자를 제공하지 않으므로 상속이 안되기 때문에 확장 불가 반면 타입 안전 열거 패턴은 확장이 가능 Enum 타입이 확장 불가한 이유 대부분 상황에서 열거 타입을 확장하는 것은 좋지 않을 가능성이 높으며 이유는 다음과 같습니다. Enum 타입은 각각 고유한 상수 값의 집합을 나타내며, 서로 다른 enum 타입 간에는 상수 값들이 일치하지 않아 서로 호환되지 않기 때문에 상속과 확장이 어려움 기반(enum) 타입에서 파생된(enum을 확장한) 타입의 원소는 기반 타입의 원소로 취급되지만, 그 반대는 성립하지 않음 즉, 확장한 타입의 ..

JAVA/Effective Java 2024.02.27

[아이템 37] ordinal 인덱싱 대신 EnumMap 사용하라

ordinal() 메서드를 배열 인덱스로 사용하면 발생하는 문제점 아이템 35에서 ordinal 메서드 사용을 자제하라고 권장했음에도 불구하고, 다음 코드처럼 배열이나 리스트에서 원소를 추출할 때 ordinal 메서드를 사용하여 인덱스를 얻는 경우가 있습니다. 코드 부연 설명 정원에 심은 식물들을 배열 하나로 관리하고 이들을 생애주기 별로 묶음 생애주기별로 총 3개의 집합을 만들고 정원을 한 바퀴 돌며 각 실물을 해당 집합에 넣음 집합들을 배열 하나에 넣고 생애주기의 ordinal 값을 그 배열의 인덱스로 사용 위 코드는 정상적으로 컴파일되고 동작은 하지만 문제가 한가득입니다. 배열은 제네릭과 호환되지 않으므로 비검사 형변환을 수행해야 하기 때문에 타입 안전성을 보장할 수 없음 배열은 각 인덱스의 의미를..

JAVA/Effective Java 2024.02.27

[아이템 36] 비트 필드 대신 EnumSet을 사용하라

비트 필드 열거 타입 내 상수들이 단독이 아닌 집합으로 사용될 경우 기존에는 각 상수에 서로 다른 2의 거듭제곱 값을 할당한 정수 열거 패턴을 사용했습니다. 다음과 같은 식으로 비트별 OR 연산을 사용해 여러 상수를 하나의 집합으로 모을 수 있으며 이렇게 만들어진 집합을 비트 필드라고 합니다. 하지만 비트 필드를 사용할 경우 앞서 아이템 34에서 언급한 정수 열거 상수의 단점을 그대로 지니며 추가로 다음과 같은 문제까지 안게 됩니다. 비트 필드 값이 그대로 출력될 경우 단순 정수 열거 상수를 출력할 때보다 해석하기 훨씬 어려움 비트 필드 하나에 녹아 있는 모든 원소를 순회하기 까다로움 최대 몇 비트가 필요한지를 API 작성 시 미리 예측하여 적절한 자료형을 선택해야 함 보통은 int, long 타입 선택..

JAVA/Effective Java 2024.02.26

[아이템 35] ordinal 메서드 대신 인스턴스 필드를 사용하라

대부분의 열거 타입 상수는 자연스럽게 하나의 정수값에 대응되며 모든 Enum 타입은 해당 상수가 그 열거 타입에서 몇 번째 위치인지를 반환하는 ordinal() 메서드를 제공합니다. 그러나 ordinal()은 대부분의 개발자가 사용할 일이 없는 메서드로, EnumSet과 EnumMap과 같이 열거 타입 기반의 범용 자료구조를 구현하지 않는 이상 사용을 피해야 합니다. ordinal을 잘 못 사용한 예 다음 코드는 합주단의 종류를 연주자가 1명인 솔로부터 10명인 디텍트까지 정의한 Enum 타입입니다. 위 코드는 동작하지만 유지보수 측면에서는 끔찍한 코드입니다. 상수 선언 순서를 바꾸는 순간 numberOfMusicians() 메서드가 오동작 이미 사용 중인 정수와 같이 같은 상수는 추가할 방법 없음 ex..

JAVA/Effective Java 2024.02.26

[아이템 34] int 상수 대신 열거 타입을 사용하라

자바에서는 열거 패턴의 한계로 인해 5 버전에서 열거 타입을 도입했습니다. C, C++, C#과 비슷해 보이지만 자바의 열거 타입은 완전한 형태의 클래스이기 때문에 다른 언어의 enum 타입보다 훨씬 강력합니다. 1. 열거 패턴의 한계 1.1 정수 열거 패턴의 단점 1.1.1 타입 안전을 보장할 방법이 없음 문자열로 인식되기 때문에 서로 다른 타입을 ==로 비교하더라도 컴파일 에러 발생 X 1.1.2 표현력이 좋지 않음 자바가 정수 열거 패턴을 위한 별도 namespace를 지원하지 않기 때문에 접두어를 써서 이름 충돌 방지 ex) 수은과 수성을 비교하려면 ELEMENT_MERCURY, PLANET_MERCURY와 같이 접두어를 붙여야 함 1.1.3 프로그램이 깨지기 쉬움 평범한 상수를 나열한 것 뿐이라..

JAVA/Effective Java 2024.02.25

[Java] 동기화 개념

1. 싱글 쓰레드 vs 멀티 쓰레드 프로세스는 오직 한 개의 쓰레드로만 구성하는 싱글 쓰레드 프로세스와 하나 이상의 쓰레드로 구성하는 멀티 쓰레드 프로세스로 구분할 수 있습니다,. 멀티 쓰레드가 항상 좋은 것은 아니며, 자원을 효율적으로 활용하고 성능을 고려한 후에 적절한 방식을 선택해야 합니다. 현재 시중에 나온 CPU는 대부분 멀티코어를 지원하기 때문에 병렬적 성능 및 동시적 자원을 사용하는 관점에서는 대부분 멀티 쓰레드 기반 프로그래밍이 유리한 것은 맞으나 비동기 논블로킹 프로그래밍 같이 싱글 쓰레드 혹은 적은 쓰레드를 활용하는 것이 좋은 성능 및 응답성을 보여줄 수도 있음 1.1 싱글 쓰레드 장점 context switching으로 인한 딜레이가 없음 동시성 문제없음 자원을 적게 사용 앞서 언급한..

JAVA/RxJava 2024.02.24

[아이템 33] 타입 안전 이종 컨테이너를 고려하라

타입 안전 이종 컨테이너 일반적으로 "컨테이너"라고 언급되면, Set, Map와 같이 다른 객체를 포함할 수 있는 객체를 가리키는 것으로 이해될 수 있습니다. 여태까지 다룬 제네릭은 오로지 한 가지 타입만 사용할 수 있는 컨테이너를 만드는 것이었습니다. ex) List에는 문자열만 넣을 수 있고 다른 타입을 넣으려고 하면 컴파일 에러 발생 하지만 더 유연한 수단이 필요할 때도 있습니다. 가령 데이터베이스의 행은 임의 개수의 열을 가질 수 있는데, 모두 열을 타입 안전하게 이용하기 위해서는 다음과 같이 구현하면 됩니다. 컨테이너 대신 키를 매개변수화한 후 컨테이너에 값을 넣거나 뺄 때 매개변수화 한 키를 함께 제공 위와 같이 구현하면 제네릭 타입 시스템이 값의 탕비이 키와 같음을 보장해 주며 이러한 설계 ..

JAVA/Effective Java 2024.02.22

[아이템 32] 제네릭과 가변인수를 함께 쓸 때는 신중하라

제네릭 가변인수 앞서 아이템 28에서 다루었다시피 제네릭의 불공변 특성으로 인해 배열과 어울리지 않습니다. 이로 인해 자바 컴파일러는 제네릭 배열을 직접 정의하는 것을 막지만, 제네릭과 가변인자를 함께 사용할 경우 제네릭 배열을 만들 수 있으며 이때 비검사 경고만 발생하고 컴파일은 정상적으로 진행됩니다. 제네릭을 사용하는 이유는 컴파일 타임에 타입 안전성을 확인하고 런타임 에러를 방지하기 위함입니다. 그러나 위와 같이 코드를 작성하면 런타임에 힙 오염이 발생할 가능성이 있어 장점이 상쇄될 수 있습니다. 따라서 제네릭 varargs 배열 매개변수에 값을 저장하는 것은 안전하지 않습니다. 자바 컴파일러가 제네릭 가변인수를 용인하는 이유 제네릭 배열이 안전하지 않은 것을 인지하고 있음에도 자바 컴파일러가 제네..

JAVA/Effective Java 2024.02.22