반응형

스터디 50

[Effective Java] Item30. 이왕이면 제네릭 메서드로

클래스와 마찬가지로 메서드도 제네릭으로 만들 수 있습니다. 매개변수화 타입을 받는 정적 유틸 메서드는 보통 제네릭입니다. 제네릭 메서드 작성법은 제네릭 타입 작성법과 비슷합니다. public static Set union(Set s1, Set s2) { Set result = new HashSet(s1); result.addAll(s2); return result; } 컴파일은 정상적으로 되지만 2개의 경고 메시지가 발생합니다. 이 경고를 없애려면 메서드를 type-safe하게 만들어야 합니다. 타입 매개변수 명시 public static Set union(Set s1, Set s2) { Set result = new HashSet(s1); result.addAll(s2); return result; }..

[Effective Java] Item29. 이왕이면 제네릭 타입으로

클라이언트에서 직접 형변환해야 하는 타입보다 제네릭 타입이 더 안전하고 쓰기 편합니다. 이를 위해서는 제네릭 타입으로 만들어야 할 경우가 많습니다. 새로운 타입을 설계할 때 뿐만 아니라 기존 타입 중 제네릭이있어야 하는 게 있다면 제네릭 타입으로 변경하는 것이 좋습니다. 간단한 실습을 통해서 기존 코드를 제네릭 타입으로 바꾸는 것을 알아보겠습니다. 기존 코드 public class Stack { private Object[] elements; private int size = 0; private static final int DEFAULT_INITIAL_CAPACITY = 16; public Stack() { this.elements = new Object[DEFAULT_INITIAL_CAPACITY];..

[Effective Java] Item28. 배열보다는 리스트

리스트가 사용하기 더 편한 것을 제외하고서라도 배열보다는 리스트의 사용을 권장하는 이유가 있습니다. 배열은 공변이고 실체화되는 반면, 제네릭은 불공변이고 타입 정보가 소거됩니다. 그 결과 배열은 런타임에는 타입 안전하지만 컴파일타임에는 그렇지 않습니다. 제네릭은 반대로 런타임에는 타입 안전하지 않지만 컴파일타임에는 안전합니다. 배열은 공변(covariant) Sub가 Super의 하위 타입이라면 Sub[]는 Super[]의 하위 타입입니다. 이를 공변이라고 합니다. 반면 제네릭은 불공변(invariant, 무변성)입니다. public class Application { public static void main(String[] args) { Object[] objArr = new Integer[1]; L..

[Effective Java] Item27. 비검사 경고를 제거

제네릭을 사용하면 비검사 형변환 경고, 비검사 메서드 호출 경고, 비검사 매개변수화 가변인수 타입 경고, 비검사 변환 경고 등 수 많은 컴파일 경고를 볼 수 있습니다. 이 중 제거하기 쉬운 경고도 있지만 제거하기 어려운 경고도 있습니다. 하지만 할 수 있는 한 모든 비검사 경고를 제거해야 합니다. 이러한 경고를 모두 제거 했다면 타입의 안전성이 보장됩니다. 즉, 런타임에 ClassCastException이 발생할 일이 없고, 의도대로 잘 작동하리라 확신 할 수 있습니다. 경고를 제거할 수는 없지만 타입이 안전하다고 확인할 수 있다면 @SuppressWarnings("unchecked")어노테이션을 달아 경고를 숨길 수 있습니다. 하지만 이를 오,남용하게 된다면 진짜 문제를 알리는 새로운 경고가 나와도 눈..

[Effective Java] Item26. 로(raw) 타입은 사용하지 말라

로 타입(raw type)을 알기전에 제네릭을 알아야 합니다. 제네릭 클래스와 인터페이스 선언에 타입 매개변수(type parameter)가 쓰이면, 이를 제네릭 클래스, 제네릭 인터페이스라 합니다. List인터페이스는 원소의 타입을 나타내는 타입 매개변수 E를 받습니다. 그래서 List인터페이스의 완전한 이름은 List입니다. 이와 같은 제네릭 클래스, 제네릭 인터페이스를 통틀어 제네릭 타입(generic type)이라 합니다. 로 타입(raw type) 제네릭 타입에서 타입 매개변수를 사용하지 않은 타입을 말합니다. List의 로 타입은 List입니다. 로 타입은 타입선언에서 제네릭 타입 정보가 전부 지워진 것 처럼 동작합니다. jdk5.0 이전의 코드와 (제네릭이 나오기 이전) 호환되도록 하기 위한..

[Effective Java] Item24. 멤버 클래스는 되도록 static

중첩 클래스(nested class) 클래스 안에 정의된 클래스로 자신을 감싼 바깥 클래스에서만 쓰여야 합니다. 만약 그 외에 쓰임새가 있다면 톱레벨 클래스로 만들어야합니다. 중첩 클래스의 종류는 정적 멤버 클래스, (비정적) 멤버 클래스, 익명 클래스, 지역 클래스로 네 가지입니다. 이 중 첫 번째 정적 멤버 클래스를 제외한 나머지는 내부 클래스(inner class)에 해당합니다. 정적 멤버 클래스 정적 멤버 클래스는 다른 클래스 안에 선언되고 바깥 클래스의 private 멤버에도 접근할 수 있다는 점만 빼면 일반 클래스와 똑같습니다. 바깥 클래스와 함께 쓰일 때만 유용한 public 도우미 클래스로 쓰입니다. 중첩 클래스의 인스턴스가 바깥 클래스의 인스턴스에 독립적일 수 있다면 정적 멤버 클래스로 ..

[Effective Java] Item23.태그달린 클래스보다는 클래스 계층구조 활용

public class Figure { enum Shape { RECTANGLE, CIRCLE } //태그 필드 final Shape shape; //Shape가 RECTANGLE일 때만 사용 double length; double width; //Shape가 CIRCLE일 때만 사용 double radius; //RECTANGLE용 생성자 public Figure(double length, double width) { this.shape = Shape.RECTANGLE; this.length = length; this.width = width; } //CIRCLE용 생성자 public Figure(Shape shape, double radius) { this.shape = Shape.CIRCLE; th..

[Effective Java] Item22. 인터페이스는 타입을 정의하는 용도로만 사용

인터페이스의 용도 자신을 구현한 클래스의 인스턴스를 참조할 수 있는 타입 역할을 합니다. 인터페이스는 오로지 이 용도로만 사용해야 합니다. 상수 인터페이스 안티패턴 상수 인터페이스란 메서드 없이, static final 필드로만 가득찬 인터페이스를 말합니다. 클래스 내부에서 사용하는 상수는 외부 인터페이스가 아니라 내부 구현에 해당합니다. 이는 내부 구현을 클래스의 API로 노출하는 행위입니다. 또한 클래스가 어떤 상수 인터페이스를 사용하든 사용자에게는 아무런 의미가 없습니다. 오히려 사용자에게 혼란을 주기도 하며, 클라이언트 코드가 내부 구현에 해당하는 상수들에 종속되게 됩니다. 상수 공개 특정 클래스나 인터페이스와 강하게 연관된 상수라면 그 클래스 자체에 추가 열거 타입 인스턴스와할 수 없는 유틸리티..

[Effective Java] Item21. 인터페이스는 구현하는 쪽을 생각해 설계

인터페이스에 메서드를 추가 자바 8이후 디폴트 메서드를 통해 기존 인터페이스에 메서드를 추가할 수 있게 되었습니다. 하지만 아래와 같은 이유로 디폴트 메서드의 추가는 신중해야합니다. 디폴트 메서드를 재정의하지 않은 모든 클래스에서 디폴트 구현이 쓰이게 됩니다. 생각할 수 있는 모든 상황에서 불변식을 해치지 않는 디폴트 메서드를 작성하기란 매우 어렵습니다. 디폴트 메서드는 기존 구현체에 런타임 오류를 일으킬 수 있습니다. 정리 디폴트 메서드는 인터페이스로붙터 메서드를 제거하거나 기존 메서드의 시그니처를 수정하는 용도가 아닙니다. 인터페이스를 설계할 때 세심한 주의를 기울여야 합니다.