JAVA 102

[아이템 29] 이왕이면 제네릭 타입으로 만들라

개발을 할 때 클래스 내에서 다른 객체들을 담는 역할을 수행하는 클래스를 생성하는 경우가 많습니다. 이런 경우 중 대표적인 예시로 스택이 있으며 다음 코드는 아이템 7에서 다룬 스택 코드입니다. 위 코드처럼 범용적으로 사용하기 위해 Object 객체를 담는 경우, 제네릭을 사용하면 ClassCastException을 미연에 방지할 수 있어 좋습니다. 제네릭을 사용하지 않을 경우, Object 배열 내 어떤 타입의 객체가 들어갈지 미리 알 수 없음 pop() 메서드에서 스택에서 꺼낸 객체를 형변환할 때, 제네릭을 사용하지 않으면 런타임 오류인 ClassCastException 발생 위험이 존재 정리하자면, 클래스 내에서 다른 객체들을 담는 역할을 수행하는 클래스는 제네릭으로 선언하는 것이 좋습니다. 이에 ..

JAVA/Effective Java 2024.02.19

[아이템 28] 배열보다는 리스트를 사용하라

배열 vs 제너릭 배열과 제네릭 타입에는 다음과 같이 두 가지 차이점이 존재합니다. 배열은 공변(covariant)인 반면 제네릭은 불공변 배열은 실체화(reify) 되는 반면 제네릭은 실체화되지 않음 1. 배열은 공변인 반면 제네릭은 불공변 공변은 간단히 말하면 함께 변한다는 의미이며, 반면에 불공변은 함께 변하지 않는다는 뜻입니다. 1.1 배열은 공변 자바에서 Object는 최상위 계층이므로 String과 Object 클래스는 호환이 됩니다. 따라서 Object[] 배열에 String을 담을 수 있으며 위 코드에서 anything을 Object[] 배열로 선언했지만 실제 인스턴스는 String 배열입니다. 해당 코드는 문법적으로 문제가 없기 때문에 컴파일은 되지만 한 가지 문제가 존재합니다. 배열은 ..

JAVA/Effective Java 2024.02.18

[아이템 27] 비검사 경고를 제거하라

비검사 경고 (unchecked warning) 비검사 경고란 컴파일러가 타입 안전성을 확인하는데 필요한 정보가 충분치 않을 때 발생시키는 경고입니다. 비검사 경고가 발생했다고 해서 컴파일이 안되거나 코드가 동작하는데 문제가 생기는 것은 아니지만 개선 포인트가 존재하기 때문에 비검사 경고가 발생하면 조치를 취하여 비검사 경고를 제거하는 것을 권장합니다. 아이템 26에서 다루었던 로 타입을 사용할 경우에도 비검사 경고가 발생하는데 경고 메시지를 읽어보면 제네릭 타입 사용을 권장하는 것을 확인할 수 있습니다. @SuppressWarnings 만약 비검사 경고를 제거할 수 없을 경우 @SuppressWarnings("unchecked") 어노테이션을 달아 경고를 숨기는 것을 권장합니다. 인지하고 있는 경고고 ..

JAVA/Effective Java 2024.02.16

[아이템 26] 로 타입은 사용하지 말라

용어 정리 아이템 26부터 33까지의 내용은 제네릭 타입과 관련된 챕터이며, 이에 따라 제네릭 관련 용어 정리부터 진행하겠습니다. 1. 로 타입 (raw type) 제네릭 타입을 하나 정의하면 그에 딸린 로 타입도 함께 정의되며 로 타입이란 제네릭 타입에서 타입 매개변수를 전혀 사용하지 않을 때를 말합니다. ex) List 2. 제네릭 타입 (generic type) 클래스와 인터페이스 선언에 타입 매개변수가 쓰이면 제네릭 클래스 혹은 제네릭 인터페이스라고 합니다. 제네릭 클래스와 제네릭 인터페이스를 통틀어 제네릭 타입이라고 합니다. ex) List 3. 매개변수화 타입 (parameterized type) 각각의 제네릭 타입은 일련의 매개변수화 타입을 정의합니다. 먼저 클래스 혹은 인터페이스 명이 나오..

JAVA/Effective Java 2024.02.16

[아이템 25] 톱레벨 클래스는 한 파일에 하나만 담으라

하나의 소스 파일에 여러 개의 톱레벨 클래스를 선언해도 컴파일 에러는 발생하지 않지만, 이러한 구현은 혜택이 없을 뿐만 아니라 심각한 위험을 초래할 수 있습니다. 한 소스 파일에 톱 레벨 클래스를 여러 개 선언할 경우 컴파일 순서에 따라 결과가 달라질 수 있음 구체적인 예를 보면 아래와 같습니다. 다음과 같이 톱 레벨 클래스인 Utensil과 Dessert를 참조하는 Main 클래스가 있습니다. Utensil.java 파일에 다음과 같이 Utensil과 Dessert 클래스가 정의되어 있을 경우 Main 클래스를 실행할 경우 pancake를 출력합니다. 이 상태에서 우연히 똑같은 두 클래스를 다음 Dessert.java 파일을 생성했을 경우 명령어에 따라 다른 상황이 발생할 수 있습니다. 1. javac..

JAVA/Effective Java 2024.02.09

[아이템 24] 멤버 클래스는 되도록 static으로 만들라

중첩 클래스(nested class)란 다른 클래스 안에 정의된 클래스를 지칭하며 다음과 같이 네 가지 종류가 있습니다. 정적 멤버 클래스 비정적 멤버 클래스 익명 클래스 지역 클래스 1. 정적 멤버 클래스 정적 멤버 클래스는 바깥 클래스의 private 멤버에도 직접 접근이 가능하며 이외에는 일반 클래스와 같음 정의되어 있는 scope 범위가 클래스 바깥 클래스와 함께 쓰일 때만 유용한 public 도우미 클래스 바깥 클래스와 독립적이기 때문에 바깥 클래스 인스턴스 필요하지 않음 이전에 언급한 대로 OuterClass를 통해 함께 사용될 때 유용하며, 아래의 코드처럼 계산기 내 연산을 담당하는 enum 클래스를 선언하는 것이 대표적인 예시입니다. 계산기의 연산 작업을 수행하는 Operation 클래스는..

JAVA/Effective Java 2024.02.08

[아이템 23] 태그 달린 클래스보다는 클래스 계층 구조를 활용하라

태그 달린 클래스두 가지 이상 의미를 표현할 수 있으며, 그중 현재 표현하는 의미를 태그 값으로 알려주는 클래스를 태그 달린 클래스라고 정의합니다. 아래 Figure 클래스가 대표적인 태그 클래스입니다. 태그 달린 클래스에는 다음과 같은 단점들이 있습니다. 쓸데없는 코드가 많아 가독성이 떨어짐 다른 의미의 코드가 항상 함께 하기 때문에 최적화된 코드보다 메모리 많이 사용 필드를 final로 선언하기 위해서는 불필요한 필드까지 초기화 필요 클래스가 여러 의미를 가지므로 인스턴스 타입만으로 현재 인스턴스가 나타내는 의미를 알 수가 없음 태그 필드인 shape을 통해서만 알 수 있음 SOLID 원칙의 단일 책임 원칙 위반 요약하면 태그 달린 클래스는 장황하고, 오류를 내기 쉽고, 비효율적입니다. 태그 달린 클..

JAVA/Effective Java 2024.02.07

[아이템 22] 인터페이스는 타입을 정의하는 용도로만 사용하라

클래스가 어떤 인터페이스를 구현한다는 것은 자신의 인스턴스가 무엇을 할 수 있는지를 클라이언트에게 얘기해 주는 것이며 인터페이스는 오직 이러한 용도로 사용해야 합니다. 인터페이스를 잘 사용한 예 아래 예시 코드는 인터페이스를 효과적으로 활용한 좋은 예입니다. 자전거 인스턴스가 이동수단의 타입이라는 것을 잘 표현하고 있습니다. 인터페이스를 잘 못 사용한 예 상수 인터페이스 안티패턴은 인터페이스를 부적절하게 활용하는 대표적인 예시입니다. 앞서 언급한 대로, 인터페이스는 주로 타입을 정의하는 데 사용되어야 합니다. 그러나 PhysicalConstant 인터페이스는 상수만을 정의하고 있어서 MyClass를 PhysicalConstant 타입이라고 정의할 수 없습니다. 물론 위 코드처럼 기술적으로 정의할 수는 있..

JAVA/Effective Java 2024.02.07

[아이템 21] 인터페이스는 구현하는 쪽을 생각해 설계하라

아이템 20에서 Java 8 이후 도입된 default 메서드는 인터페이스에 새로운 기능을 추가할 수 있으면서도 컴파일 에러를 발생시키지 않기 때문에 장점이라고 소개헀지만 이러한 특성은 단점으로 작용할 수도 있습니다. 추가된 default 메서드를 해당 인터페이스 구현체와 합의 없이 무작정 삽입된 형태 추가된 디폴트 메서드는 경우에 따라 기존 구현체에 런타임 오류를 야기할 수 있음 1. 추가된 default 메서드를 해당 인터페이스 구현체와 합의 없이 무작정 삽입된 형태 디폴트 메서드를 선언하면 해당 인터페이스를 구현한 클래스 중 디폴트 메서드를 재정의하지 않은 모든 클래스에서는 디폴트 구현이 적용됩니다. 자바 8에서는 람다를 활용하기 위해 핵심 컬렉션 인터페이스들에 다수의 default 멤서드가 추가되..

JAVA/Effective Java 2024.02.07

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

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

JAVA/Effective Java 2024.02.07