EffectiveJava
-
[Effective Java] 한정적 와일드카드를 사용해 API 유연성을 높이라Java 2023. 2. 2. 11:05
매개변수화 타입은 불공변이다. 서로 다른 Type1과 Type2가 있을 때 List는 List의 하위 타입도 상위 타입도 아니다. 즉 List은 List의 하위타입이 아니다. List에는 어떤 객체든지 넣을 수 있지만 List에는 문자열만 넣을 수 있다. 불공변 방식의 문제점1 다음과 같이 Stack 클래스의 public API가 있을 때 public class Stack{ public Stack(); public void psuh(E,e); public E pop(); public boolean isEmpty(); } 여기에 일련의 원소를 스택에 넣는 메서드를 추가해야 한다고 해보자. public void pushAll(Iterable src){ for(E e : src) push(e); } 이 메서드..
-
[Effective Java] 로 타입은 사용하지 말라Java 2023. 2. 2. 11:04
제네릭 제네릭을 지원하기 전에는 컬렉션에서 객체를 꺼낼 때 마다 형변환을 해야 했다. 반면, 제네릭을 사용하면 컬렉션이 담을 수 있는 타입을 컴파일러에게 알려주게 된다. 그래서 컴파일러는 알아서 형변환 코드를 추가할 수 있게 되고, 엉뚱한 타입의 객체를 넣으려는 시도를 컴파일 과정에서 차단하여 더 안전하고 명확한 프로그램을 만들어 준다. 제네릭 클래스, 제네릭 인터페이스 클래스와 인터페이스 선언에 타입 매개변수가 쓰이면, 이를 제네릭 클래스 혹은 제네릭 인터페이스라 한다. public class Box { // T는 타입을 의미한다. private T data; public void set(T data) { this.data = data; } public T get() { return data; } } ..
-
[Effective Java] 톱레벨 클래스는 한 파일에 하나만 담으라Java 2023. 2. 2. 11:04
소스 파일 하나에 톱레벨 클래스를 여러 개 선언하더라도 자바 컴파일러는 불평하지 않는다. 하지만 아무런 득이 없을 뿐더러 심각한 위험을 감수해야 하는 행위다. 이렇게 하면 한 클래스를 여러 가지로 정의할 수 있으며, 그 중 어느 것을 사용할지는 어느 소스 파일을 먼저 컴파일하냐에 따라 달라지기 때문이다. 톱레벨 클래스를 중복 정의한 경우 Utensil(집기)와 Dessert(디저트)를 참조하는 Main 클래스 public class Main{ public static void main(String[] args){ System.out.println(Utensil.NAME + Dessert.NAME); } } Utensil 파일에 함께 선언된 utensil 클래스와 Dessert 클래스 class Utens..
-
[Effective Java] 추상 클래스보다는 인터페이스를 우선하라Java 2023. 2. 2. 11:03
자바가 제공하는 다중 구현 메커니즘은 인터페이스와 추상 클래스, 이렇게 두 가지다. 자바 8 부터 인터페이스도 디폴트 메서드를 제공할 수 있게 되어, 이제는 두 메커니즘 모두 인스턴스 메서드를 구현 형태로 제공할 수 있다. 둘의 가장 큰 차이는 추상 클래스가 정의한 타입을 구현하는 클래스는 반드시 추상 클래스의 하위 클래스가 되어야 한다는 점이다. 자바는 단일 상속만 지원하니, 추상 클래스를 상속받은 클래스는 다른 클래스를 상속받을 수 없게되는 것이다. 반면 인터페이스가 선언한 메서드를 모두 정의하고 그 일반 규약을 잘 지킨 클래스라면 다른 어떤 클래스를 상속했든 같은 타입으로 취급된다. 디폴트 메서드(default method) 디폴트 메서드는 인터페이스에 있는 구현 메서드를 의미한다. 기존의 추상 메..
-
[Effective Java] 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라Java 2023. 2. 2. 11:02
상속을 고려한 설계와 문서화란? 1. 메서드를 재정의하면 어떤 일이 일어나는지를 정확히 정리하여 문서로 남겨야 한다. 즉, 상속용 클래스는 재정의할 수 있는 메서드들을 내부적으로 어떻게 이용하는지(자기사용) 문서로 남겨야 한다. 클래스의 API로 공개된 메소드에서 클래스 자신의 또 다른 메소드를 호출할 수도 있다. 이때 호출되는 메소드가 하위 클래스에서 재정의 가능한 메소드라면 이 사실을 호출하는 메소드의 API 설명에 명시해야 한다. 재정의 가능 메소드를 호출할 수 있는 모든 상황을 문서로 남겨두어야 한다. API 문서의 메서드 설명 끝에서 종종 "Implementation Requirements"로 시작하는 절을 볼 수 있는데, 그 메서드의 내부 동작 방식을 설명하는 곳이다. (메서드 주석에 @imp..
-
[Effective Java] clone 재정의는 주의해서 진행하라Java 2023. 2. 2. 11:01
Clonable은 메서드가 없는 인터페이스이다. clone 메서드는 원본 객체의 필드 값과 동일한 값을 가지는 새로운 객체를 생성해준다. clone 메서드를 사용하기 위해서는 해당 클래스에서 Cloneable 인터페이스를 구현해주어야 한다. 클래스에서 clone을 재정의하기 위해선 해당 클래스에 Cloneable 인터페이스를 상속받아 구현하여야 한다. 그런데 정작 clone 메소드는 Cloneable 인터페이스가 아닌 Object에 선언되어있다. Cloneable 인터페이스는 아무것도 선언되어 있지 않은 빈 인터페이스이다. Cloneable 인터페이스의 역할 /** * A class implements the Cloneable interface to * indicate to the {@link java...
-
[Effective Java] toString을 항상 재정의하라Java 2023. 2. 2. 11:00
Object 클래스의 기본 toString 메서드 Object 클래스 자바의 Object 클래스는 모든 자바 클래스의 최상위 클래스로, 전체 이름은 java.lang.Object 이다. Object클래스는 가장 최상위 클래스이므로 자바의 모든 클래스들은 Object 클래스를 상속받는데, 컴파일 과정에서 컴파일러가 자동으로 extends 해준다. toString 메서드 toString은 말 그대로 객체의 정보를 String(문자열)형으로 형변환 해준다. Object 클래스를 상속받은 클래스들은 toString()을 오버라이딩(재정의)하여 사용할 수 있다. 자주 쓰이는 String이나 Integer 클래스에는 toString()이 이미 재정의 되어 있다. 예) Book 클래스 public class Book..
-
[Effective Java] try-finally보다는 try-with-resources를 사용하라Java 2023. 2. 2. 11:00
자바 라이브러리에는 InputStream, OutputStream, java.sql.Connection 등 close메서드를 호출해 직접 닫아줘야 하는 자원이 많다. 전통적으로 이러한 자원을 닫기 위한 수단으로 try-finally가 사용되었다. try-finally - 자원을 회수하는 최선의 방책이 아니다 static String firstLineOfFile(String path) throws IOException{ BufferedReader br = new BufferedReader(new FileReader(path)); try { return br.readLine(); } finally { br.close(); } } 자원이 둘 이상이면 try-finally 방식은 코드가 매우 복잡해진다. sta..