Book/Effective Java
-
[Effective Java] Item 31. 한정적 와일드카드를 사용해 API 유연성을 높이라Book/Effective Java 2024. 12. 6. 23:13
아이템 28에서 이야기 했듯 매개변수화 타입은 불공변이다. 하지만 때론 불공변 방식보다 유연한 방식이 필요한데 그것이 바로 한정적 와일드카드다.한정적 와일드 카드 사용법Stack에서 일련의 원소를 스택에 넣는 메서드를 추가해야 한다고 해보자.public void pushAll(Iterable src) { for (E e : src) push(e);}이 메서드를 사용한 코드는 다음과 같다.Stack numberStack = new Stack();Iterable integers = ...;numberStack.pushAll(integers); // 에러 발생이 코드가 잘 동작할 것 같지만, 매개변수화 타입이 불공변이기 때문에 Integer은 Iterable의 하위 타입이 아니라는 오류 메시지가 뜬다. 여기..
-
[Effective Java] Item 30. 이왕이면 제네릭 메서드로 만들라Book/Effective Java 2024. 12. 4. 22:11
클래스와 마찬가지로, 메서드도 제네릭으로 만들 수 있다. 매개변수화 타입을 받는 정적 유틸리티 메서드가 보통 제네릭 메서드이며 대표적으로 Collections의 binarySearch, sort가 있다. 제네릭 메서드제네릭 메서드 작성법은 제네릭 타입 작성법과 비슷하지만 하나 추가되어 하는 게 있다. 타입 매개변수 목록을 메서드의 제한자와 반환 타입 사이에 넣어야 한다. 예시 코드를 살펴보자.public static Set union(Set s1, Set s2) { Set result = new HashSet(s1); result.addAll(s2); return result;} 이 메서드는 경고 없이 컴파일되며, 타입 안전하고, 쓰기도 쉽다. 한정적 와일드카드 타입을 사용하여 더 유연하게 개선할 수 ..
-
[Effective Java] Item 29. 이왕이면 제네릭 타입으로 만들라Book/Effective Java 2024. 12. 3. 22:42
JDK가 제공하는 제네릭 타입과 메서드를 사용하는 일은 일반적으로 쉬운 편이지만, 제네릭 타입을 새로 만드는 일은 조금 더 어렵다. 하지만, 클라이언트에서 직접 형변환하는 타입보다 제네릭 타입이 더 안전하고 쓰기 편하다. 그러므로 새로운 타입을 설계할 때는 형변환 없이도 사용할 수 있도록 제네릭 타입을 사용하는 것이 좋다. 그렇다면, 어떻게 제네릭 타입을 사용하여 코드를 짜야 하는지 아이템 7에서 다룬 단순한 스택 코드를 다시 살펴보며 알아보자.public class Stack { private Object[] elements; private int size = 0; private static final int DEFAULT_INITIAL_CAPACITY = 16; public Stack() { el..
-
[Effective Java] Item 28. 배열보다는 리스트를 사용하라Book/Effective Java 2024. 12. 2. 21:24
배열보다 리스트를 사용해야 하는 이유를 알기 전에 배열과 제네릭의 차이에 대해 알아보자. 배열은 공변이고 제네릭은 불공변이다.Sub가 Super의 하위타입이면 배열 Sub[]는 Super[]의 하위 타입이 된다. 이러한 특징 떄문에 다음과 같은 문제가 발생할 수 있다.Object[] objectArray = new Long[1];objectArray[0] = "타입이 달라 넣을 수 없다"; // ArrayStoreException을 던진다. 하지만, 제네릭은 불공변이기 때문에 애초에 컴파일 되지 않는다.List ol = new ArrayList(); // 컴파일 에러 배열은 실체화되지만 제네릭은 타입 정보가 런타임에 소거된다.배열은 런타임에도 자신이 담기로 한 원소 타입을 인지하고 확인하여 위 코드처럼 ..
-
[Effective Java] Item 27. 비검사 경고를 제거하라Book/Effective Java 2024. 12. 1. 12:25
제네릭을 사용하면 하기와 같은 컴파일러 경고를 보게 될 것이다.// Raw use of parameterized class 'HashSet' 경고가 뜬다.Set exaltation = new HashSet(); 이 경고는 자바7부터 지원하는 다이아몬드 연산자() 만으로 쉽게 해결할 수 있다.Set exaltation = new HashSet(); 이러한 경우처럼 쉽게 경고를 제거할 수 있지만 그렇지 않은 경우도 생길 것이다. 하지만 곧바로 해결 안된다고 포기하지 말고 할 수 있는 한 모든 비검사 경고를 제거해야한다. 모두 제거한다면 그 코드의 타입 안정성이 보장되어 ClassCastException이 발생하지 않는다. @SuppressWarnings이 애너테이션은 개별 지역변수 선언부터 클래스 전체까지 ..
-
[Effective Java] Item 26. 로 타입은 사용하지 말라Book/Effective Java 2024. 12. 1. 11:38
raw type로 타입(raw type)이란 제네릭 타입에서 타입 매개변수를 전혀 사용하지 않을 때를 말한다. 제네릭 타입은 제네릭 클래스와 제네릭 인터페이스를 포함한 개념으로 클래스와 인터페이스 선언에 타입 매개변수가 쓰이는 것을 말한다. List를 예시로, List은 원소의 타입이 String인 리스트를 뜻하는 매개변수화 타입이다. 여기서 String은 정규 타입 매개변수 E에 해당하는 실제타입 매개변수이다. raw type을 사용하면 안되는 이유제네릭이 지원되기 이전에는 다음과 같이 사용하였다.private final Collection stamps = ...; 이렇게 선언하게 되면, 실수로 stamp가 아닌 coin을 넣게되도 컴파일 에러 없이 실행이 되어 실제 사용할 때 ClassCastExce..
-
[Effective Java] Item 25. 톱레벨 클래스는 한 파일에 하나만 담으라Book/Effective Java 2024. 12. 1. 10:37
소스 파일 하나에는 반드시 톱레벨 클래스를 하나만 담아야한다. 물론 톱레벨 클래스를 여러개 선언한다 해도 자바 컴파일러는 신경도 쓰지 않지만 심각한 에러가 발생할 수 있다. 문제가 생길 수 있는 코드를 살펴보자.public class Main { public static void main(String[] args) { System.out.println(Utensil.NAME + Dessert.NAME); }} 위 코드를 작성하고 실행시켰을 때 문제가 없어 보이지만, 만약 서로 다른 파일에서 동일한 이름을 가진 톱레벨 클레스가 있다면 문제가 생길 수 있다. 다음과 같이 서로 다른 파일인 Utensil과 Dessert가 있다.class Utensil { static final String NAME = "p..
-
[Effective Java] Item 24. 멤버 클래스는 되도록 static으로 만들라Book/Effective Java 2024. 11. 30. 12:01
중첩 클래스(nested class, inner class)란 다른 클래스 안에 정의된 클래스를 말한다. 중첩 클래스는 자신을 감싼 바깥 클래스에서만 쓰여야 하며, 그 외의 쓰임새가 있다면 톱레벨 클래스로 만들어야 한다. 중첩 클래스의 종류는 4가지가 있는데 각각 언제 그리고 왜 사용해야 하는지 알아보자. 그리고 그 중 멤버 클래스는 왜 되도록 static으로(정적 멤버 클래스로) 만들어야 하는지 중점적으로 살펴보자. 정적 멤버 클래스다른 클래스 안에 선언되고, 바깥 클래스의 private 멤버에도 접근할 수 있다는 점을 제외하면 일반 클래스와 똑같다.public class OuterClass { private int x = 10; // 바깥 클래스에서만 접근 가능 private static cla..