독서찰기(讀書札記) (90) 썸네일형 리스트형 1장 깨끗한 코드 우리 모두는 자신이 짠 쓰레기 코드를 쳐다보며 나중에 손보겠다고 생각한 경험이 있다. … 나중은 결코 오지 않는다. 기한을 맞추는 유일한 방법은, 그러니까 빨리 가는 유일한 방법은, 언제나 코드를 최대한 깨끗하게 유지하는 습관이다. 나쁜 코드는 나쁜 코드를 ‘유혹’한다! Grady Booch “깨끗한 코드는 잘 쓴 문장처럼 읽힌다.” “캠프장은 처음 왔을 때보다 더 깨끗하게 해놓고 떠나라.” 한꺼번에 많은 시간과 노력을 투자해 코드를 정리할 필요가 없다. 변수 이름 하나 개선하고, 조금 긴 함수 하나를 분할하고, 약간의 중복을 제거하고, 복잡한 if 문 하나를 정리하면 충분하다. [아이템 28] 배열보다는 리스트를 사용하라 [Why] 배열과 제네릭 타입의 차이 첫 번째 배열은 공변(covariant; 共變)이다. Sub가 Super의 하위 타입이라면 Sub[]는 Super[]의 하위 타입 제네릭은 불공변(invariant; 不共變)이다. 서로 다른 타입 Type1과 Type2이 있을 때, List은 List의 하위 타입도, 상위 타입도 아니다. 문제는 배열 쪽에 있다. Object[] objectArray = new Long[1]; objectArray[0] = "타입이 달라 넣을 수 없다."; // ArrayStoreException을 던진다. 위 코드는 문법 상 허용되지만, 런타임에 에러를 발생시킨다. List ol = new ArrayList(); // 호환되지 않는 타입이다. ol.add("타입이 달라 넣을 수 없다.. [아이템 27] 비검사 경고를 제거하라 [Why] 할 수 있는 한 모든 비검사 경고를 제거하라. 제네릭을 사용하기 시작하면 수많은 컴파일러 경고를 보게 될 것이다. 모두 제거한다면 그 코드는 타입 안정성이 보장된다! [How] 경고를 제거할 수는 없지만 타입 안전하다고 확신할 수 있다면 @SuppressWarnings("unchecked") 애너테이션을 달아 경고를 숨기자. 경고없이 컴파일될 수는 있지만, 런타임에 여전히 ClassCastException을 던질 수 있다. 경고를 무시해도 안전한 이유를 항상 주석으로 남겨야 한다. 한편, 안전하다고 검증된 비검사 경고를 숨기지 않고 그대로 두면, 진짜 문제를 알리는 새로운 경고가 나와도 파묻힐 수 있다. @SuppressWarnings 애너테이션은 항상 가능한 한 좁은 범위에 적용하자. 심각한.. [아이템 26] 로 타입(raw type)은 사용하지 말라 용어 정리 제네릭 클래스/제네릭 인터페이스: 클래스/인터페이스 선언에 타입 매개변수(type parameter)가 쓰인 것 제네릭 타입(generic type): 제네릭 클래스와 제네릭 인터페이스를 통틀어 칭함 매개변수화 타입(parameterized type): e.g.) List은 원소의 타입이 String인 리스트를 뜻하는 매개변수화 타입 여기서 String이 정규(formal) 타입 매개변수 E에 해당하는 실제(actual) 타입 매개변수 로 타입(raw type): 제네릭 타입에서 타입 매개변수를 전혀 사용하지 않을 때 e.g.) List의 로 타입은 List 자바에 제네릭 기능이 생기기 전 코드와 호환되도록 하기 위한 궁여지책 한글 용어 영문 용어 예 아이템 매개변수화 타입 parameteri.. [아이템 25] 톱레벨 클래스는 한 파일에 하나만 담으라 [Why] class Utensil { static final String NAME = "pan"; } class Dessert { static final String NAME = "cake"; } // 두 클래스가 한 파일(Utensil.java)에 정의되었다. public class Main { public static void main(String[] args) { System.out.println(Utensil.NAME + Dessert.NAME); } } Main을 실행하면 pancake를 출력한다. class Utensil { static final String NAME = "pot"; } class Dessert { static final String NAME = "pie"; } // 두 클.. [아이템 24] 멤버 클래스는 되도록 static으로 만들라 중첩 클래스란? 정의 다른 클래스 안에 정의된 클래스 사용법 중첩 클래스는 자신을 감싼 클래스에서만 쓰여야 하며, 그 외의 쓰임새가 있다면 톱레벨 클래스로 만들어야 한다. 종류 중첩 클래스의 종류에는 정적 멤버 클래스, (비정적)멤버 클래스, 익명 클래스, 지역 클래스가 있다. 첫번째를 제외한 나머지는 내부 클래스(inner class)에 해당한다. 정적 멤버 클래스 특징 다른 클래스 안에 선언 바깥 클래스의 private 멤버에 접근 가능 활용 바깥 클래스와 함께 쓰일 때만 유용한 public 도우미 클래스로 쓰인다. e.g.) 계산기가 지원하는 연산 종류를 정의하는 열거 타입 비정적 멤버 클래스 특징 비정적 멤버 클래스의 인스턴스와 바깥 인스턴스 사이의 관계는 멤버 클래스가 인스턴스화될 때 확립되며,.. [아이템 23] 태그 달린 클래스보다는 클래스 계층구조를 활용하라 [Why] class Figure { enum Shape { RECTANGLE, CIRCLE }; // 태그 필드 - 현재 모양을 나타낸다. final Shape shape; // 다음 필드들은 모양이 사각형(RECTANGLE)일 때만 쓰인다. double length; double width; // 다음 필드는 모양이 원(CIRCLE)일 때만 쓰인다. double radius; // 원용 생성자 Figure(double radius) { shape = Shape.CIRCLE; this.radius = radius; } // 사각형용 생성자 Figure(double length, double width) { shape = Shape.RECTANGLE; this.length = length; this.wi.. [아이템 22] 인터페이스는 타입을 정의하는 용도로만 사용하라 [Why] 인터페이스는 자신을 구현한 클래스의 인스턴스를 참조할 수 있는 타입 역할을 한다. 즉, 클래스가 어떤 인터페이스를 구현한다는 것은 자신의 인스턴스로 무엇을 할 수 있는지를 클라이언트에 얘기해주는 것이다. 인터페이스는 오직 이 용도로만 사용해야 한다. [How] 안티 패턴으로 상수 인터페이스라는 것이 있다. 상수 인터페이스란 메서드 없이, 상수를 뜻하는 static final 필드로만 가득 찬 인터페이스를 말한다. 클래스 내부에서 사용하는 상수는 외부 인터페이스가 아니라 내부 구현에 해당한다. 상수 인터페이스를 구현하는 것은 이 내부 구현을 클래스의 API로 노출하는 행위다. 클래스가 어떤 상수 인터페이스를 사용하든 사용자에게는 아무런 의미가 없으며 오히려 혼란을 준다. 클라이언트 코드가 내부 .. 이전 1 ··· 5 6 7 8 9 10 11 12 다음