effective java

135
Effective Java SOMA mentor 이해일 ([email protected] ) 2014.02.21

Upload: haeil-yi

Post on 22-Jan-2017

2.720 views

Category:

Software


1 download

TRANSCRIPT

Page 1: Effective java

Effective JavaSOMA

mentor 이해일([email protected])

2014.02.21

Page 2: Effective java

들어가며

요구사항은변화한다. 복잡하다.

변화를 생각하고 설계하라.복잡함은 제거할 수 없다, 제어하라.

숙명

시스템은 진화한다.2

Page 3: Effective java

지혜

복잡성을 나눠라.

변경이 미치는 범위를 최소화하라.

들어가며

3

Page 4: Effective java

모듈화

결합도는 낮게 모듈 사이 의존 관계는 최소로!

응집도는 높게 한 모듈은 한가지 책임만!

들어가며

4

Page 5: Effective java

모듈화

변경은 최소로 최대한 숨기기!

최대한 변하지 않기!

계약은 철저히 계약 준수

• 계약만 지킨다면 답을 내놓는 방법은 중요하지 않다.

• 답은 내놓은 방법이 변한다고 계약이 변하진 않는다.

계약 불변• 한 번 맺은 계약은 최대한 변하지 않아야 한다.

• 계약이 변하면 계약 맺은 고객은 번거로울 수 밖에 없다.

들어가며

5

Page 6: Effective java

모듈화들어가며

관심범위

우리시스템

관련시스템

6

Page 7: Effective java

모듈화들어가며

정보계

계정계채널계

OASIS

인터넷 뱅킹 시스템(OIS)

ATM 시스템(OAS)

환전소 시스템(OXS)

일괄처리 시스템(OBS)

온라인 시스템(OOS)

경영정보 시스템(OMS)

외부 시스템

단독 환전소 어플리케이션

(OXA)

7

Page 8: Effective java

객체 지향

8

들어가며

소프트웨어 시스템

?비즈니스 시스템

Page 9: Effective java

객체 지향

객체는 기능 집합 객체는 메소드라는 함수가 있는 자료구조로 메소드가 자료를

조작한다라는 개소리! (Holub)

위임 필요한 정보를 요청해서 직접 가져와 처리하려 하지 말고 정보

를 가진 객체를 찾아 계약에 따라 일을 시켜라. 만약 정보가 부족하면 제공해라.

구현 은닉 최대한 구현을 감춰 계약 크기를 최소화하라.

들어가며

9

Page 10: Effective java

SOLID

모두 지킬 수는 없다.

깰 수도 있다.

하지만, 원칙을 이해하라.

무슨 원칙을 깨는지, 왜 원칙을 깨야 하는지 이해하라.

Working is better than perfect!

들어가며

10

Page 11: Effective java

SRP

Single Responsibility Principle 한 객체는 한 책임을 맡고 한 책임은 한 객체에 모인다.

낮은 결합도, 높은 응집도

들어가며

11

Page 12: Effective java

OCP

Open Closed Principle 확장엔 열려있고 변경엔 닫혀있다.

새로운 요구사항이 발생• 감춰진 구현은 자유롭게 재구성할 수 있어야 한다. (Open)

• 공개된 인터페이스는 변하지 않아야 한다. (Close)

Open은 지키기 쉽지만 Closed는 지키기 어렵다.

들어가며

12

Page 13: Effective java

OCP

왜 나쁜 설계인가? 다른 도형을 추가하면?

들어가며

public void drawAll(Shape[] shapes)

{

for (int i = 0; i < shapes.length; i++)

{

Shape shape = shapes[i];

if (shape.shapeType() == Shape.CIRCLE)

{

((Circle)shape).drawCircle();

}

else if (shape.shapeType() == Shape.SQUARE)

{

((Square)shape).drawSquare();

}

}

}

13

Page 14: Effective java

OCP

왜 나쁜 설계인가? 다른 제약 사항을 추가하면?

들어가며

public void drawAll(Shape[] shapes)

{

for (int i = 0; i < shapes.length; i++)

{

Shape shape = shapes[i];

if (shape.shapeType() ==

Shape.CIRCLE)

{

if (((Circle)shape).radius() > 10.0)

{

shape.draw();

}

}

else

{

shape.draw();}

}

}

14

Page 15: Effective java

LSP

Liscov Substitution Principle 서브 클래스는 슈퍼 클래스를 대체할 수 있어야 한다.

완벽한 is-a 관계가 되도록 상속 구조를 정의해야 한다.• 슈퍼 클래스의 행위를 서브 클래스가 거부하면 안 된다.

• 서브 클래스가 슈퍼 클래스를 대신하기 위해 뭔가 더 필요하면 안 된다.

예외• Arrays.asList(new String[] {“0”, “1”, “2”}).add(“3”) Exception

• UnmodifiableList를 반환하기 때문

• Collection API 크기를 줄이기 위한 선택

들어가며

15

Page 16: Effective java

ISP

Interface Segregation Principle 특화된 인터페이스가 통합된 범용 인터페이스보다 낫다.

클라이언트에게 용도가 명확한 인터페이스를 제공해야 한다.

들어가며

16

Page 17: Effective java

DIP

Dependency Inversion Principle 클라이언트는 구체 클래스가 아닌 인터페이스에 의존한다.

바람직한 방향으로 의존성을 재설정

들어가며

Framework User

login

Framework

ILogin

Authorizer UserProfile

Authorizer

loginUser

UserProfile

17

Page 18: Effective java

왜, 이펙티브 자바인가?들어가며

생각(객체지향)

언어(자바)

18

Page 19: Effective java

왜, 이펙티브 자바인가?들어가며

기초

어휘, 문법숙련

어법

19

Page 20: Effective java

이펙티브 자바 구조

객체 생성과 소멸 생성

소멸

계약 공통 계약

클래스/인터페이스

메소드

들어가며

프로그래밍 기본 일반

예외

동시성

심화 제너릭

열거형

주석

직렬화

20

Page 21: Effective java

I. 객체 생성과 소멸

객체는 시스템 구성 기본 단위

객체 == 메모리

객체 생성 방법

객체 소멸 방법

객체 생성과 소멸

21

Page 22: Effective java

1. Static Factory Method

왜? 적절한 시그니처

객체 재사용

다양한 서브타입 제공

간결한 코드

요약 무심코 생성자를 만들기 전에 static factory method를 먼저

고려하라.

객체 생성과 소멸

22

Page 23: Effective java

1. Static Factory Method

어떻게? 인스턴스를 생성하는 static 메소드

GoF Factory Method와 비교• 의도 : . 인스턴스 생성을 하위 클래스에게 미룬다.

객체 생성과 소멸

Client

Creator c = new ConcreteCreator();

String result = c.anOperation();

23

Page 24: Effective java

1. Static Factory Method

적절한 시그니처 new BigInteger(int, int, Random) vs

BigInteger.probablePrime(int, Random)

Foo(int, String) Foo(String, int) vsFoo.createFoo1(int, String) Foo.createFoo2(int, String)

Human(String name) Human(String location) vsHuman.find(String name) Human.from(String location)

객체 생성과 소멸

24

Page 25: Effective java

1. Static Factory Method

객체 재사용 Boolean.valueOf(boolean)

• 미리 만들어 놓은 Boolean.TRUE, Boolean.FALSE 재사용

• 복잡한 객체라면?

인스턴스 제어• 인스턴스 개수 제한 : Singleton

• 인스턴스 생성 방지 : Utility class

• 동일한(== && equals) 인스턴스 생성 방지 : 불변 클래스, Enum

객체 생성과 소멸

25

Page 26: Effective java

1. Static Factory Method

서브타입 생성 사악한 new

• 항상 구체 클래스가 나와야 한다.

인터페이스 기반 프레임워크• public이 아닌 class의 인스턴스 제공

• List<T> Collections.unmodifiableList(List<? Extends T>)

• List<T> Collections.synchronizedList(List<T>)

• 작은 규모 API 가능

• 다양한 구현체 제공

객체 생성과 소멸

Collections

List

UnmodifableList

SynchronizedList

<<생성한다>>

ClientunmodifableList()

synchronizedList()

26

Page 27: Effective java

1. Static Factory Method

서브타입 생성 서비스 제공자 프레임워크

객체 생성과 소멸

Client

JNDI API

Naming Manager

LDAPActive

DirectoryNDSDNS

COSNaming

JNDI SPI

업체가 구현하는 부분

Client

JDBC API

Driver Manager

Oracle MySQLSybaseDB2MSSQL

JDBC Dirver API

업체가 구현하는 부분

27

Page 28: Effective java

1. Static Factory Method

서브타입 생성 서비스 제공자 프레임워크

• 인터페이스만 존재해도 클라이언트를 구현할 수 있다.

• JDBC, JNDI, JTA 같이 다양한 구현체가 존재할 때 유용한 기법이다.

객체 생성과 소멸

DriverManager

Connection

XXXConnection

YYYConnection

<<생성한다>>

Client getConnection()DB2 JDBC 드라이버

9i JDBC 드라이버

28

Page 29: Effective java

1. Static Factory Method

서브타입 생성 서비스 제공자 프레임워크

• 동작

• 구조

객체 생성과 소멸

ServicesClient Provider Service

newInstance(name)

newService()

<<instantiate>>

goodService()

Provider Service

CProvider

Service newService()

CService

goodService()

<<instantiate>>

Services

registerProvider(name, Provider)

Service newInstance(name)

ClientSystem

Register

providers

newInstance

providers

goodService

29

Page 30: Effective java

1. Static Factory Method

간결한 코드

객체 생성과 소멸

VS

30

Page 31: Effective java

1. Static Factory Method

단점 드러난 생성자가 없는 경우 서브 클래스를 만들 수 없다.

다른 static 메소드와 구분하기 어렵다.• 명명 규칙을 따르자.

• valueOf : 형변환 메소드로 인자와 같은 값을 갖는 인스턴스 반환한다.

• of : valueOf와 같다. EnumSet에서 주로 쓴다.

• getInstance : 인자에 따라 인스턴스가 결정되나 인자와 같은 값을 가지지 않는다. 인자가 없는 경우 singleton인 경우가 많다.

• newInstane : getInstance와 같지만 항상 새로운 인스턴스를 반환한다.

• getType : getInstance와 같지만 메소드가 속한 클래스가 아닌 다른 타입을 생성한다.

• newType : newInstance와 같지만 메소드가 속한 클래스가 아닌 다른타입을 생성한다.

객체 생성과 소멸

31

Page 32: Effective java

2. Builder

왜? 객체 생성에 필요한 인자가 4개가 넘어가면 헷갈린다.

인자가 같은 타입이라면 그야말로 지옥.

요약 객체 생성에 필요한 인자가 많다면 builder를 고려하라. 특

히, 선택 인자가 많은 경우에 유용하다.

객체 생성과 소멸

32

Page 33: Effective java

2. Builder

이전 해법 Telescoping Constructor

• 가독성 떨어진다.

• 작성하기 어렵다.

객체 생성과 소멸

33

Page 34: Effective java

2. Builder

이전 해법 Java Beans

• 객체 생성을 완성할 때까지 객체가 일관성을 유지할 수 없다.

• 객체 불변 조건을 만족하지 못하는 순간이 있다.

• 동시성 문제가 발생할 수 있다.

객체 생성과 소멸

34

Page 35: Effective java

2. Builder

어떻게? Builder

• 의도 : 복잡한 객체를 구성하는 일을 표현과 분리하여 같은 구성 절차로 다양한 표현을 만들어 내고 싶다.

객체 생성과 소멸

35

Page 36: Effective java

2. Builder객체 생성과 소멸

장점 VS Telescoping

• 작성하기 쉽다.

• 가독성이 좋다.

Vs JavaBeans• 불변규칙을 검사할 수 있다.

• 불변 객체를 만들 수 있다.

유연성• 다수 가변인자

• 빌더 객체 재사용

36

Page 37: Effective java

2. Builder

장점 추상 팩토리

• 의도 : 실체 클래스(concrete class)를 정의하지 않고도 관련 객체군을 생성하는 인터페이스를 제공한다.

• Builder를 이용한 추상 팩토리

• java.lang.Class도 추상 팩토리로 동작하지만 newInstance()는 항상기본 생성자를 호출하는 한계가 있다.

단점 Builder 객체 생성 비용

객체 생성과 소멸

37

Page 38: Effective java

3. Singleton

왜? 정확히 하나의 인스턴스만 생성하는 클래스

요약 public static final field나 method를 제공하는 방법과 Enum

을 이용하는 방식이 있다.

직렬화, 동시성도 고려해야 진정한 singleton을 얻을 수 있다.

객체 생성과 소멸

38

Page 39: Effective java

3. Singleton

어떻게? public static final field

• Serializable로 바꾸면 문제 발생• 모든 field transient

• readResolve 구현

• Reflection으로 생성자 접근 가능

객체 생성과 소멸

39

Page 40: Effective java

3. Singleton

어떻게? public static final method

• 늦은 초기화• 동시성 문제 발생

• 동기화 필요

• 성능 감소

• Reflection으로 생성자 접근 가능

객체 생성과 소멸

40

Page 41: Effective java

3. Singleton

어떻게? SingletonHolder

객체 생성과 소멸

41

Page 42: Effective java

3. Singleton

직렬화 문제

객체 생성과 소멸

JVM

JVM

싱글톤 직렬화 바이트 스트림

싱글톤 직렬화 바이트 스트림

싱글톤

직렬화

역직렬화X

42

Page 43: Effective java

3. Singleton

직렬화 문제 해결 역직렬화로 인스턴스를 생성하자마자 readResolve 자동 호출

해서 readResolve가 리턴하는 인스턴스로 대체한다.

객체 생성과 소멸

ZZZ 인스턴스 직렬화

바이트 스트림

역직렬화로 만들어 낸

ZZZ 인스턴스

1. 역직렬화

요청

class ZZZ implements Serializable

{

…}

private Object readResolve() …{

ZZZ zzz = …;

return zzz;

}

직렬화 시스템

readResolve가 리턴한

ZZZ 인스턴스

2. 역직렬화로

인스턴스 생성

3. readResolve가

정의되어 있기

때문에 호출

4. 새로운 ZZZ

인스턴스를

생성해서 리턴

JVM

X5. 가비지 컬렉션

대상

O

가비지 컬렉터

43

Page 44: Effective java

3. Singleton

어떻게? Enum

• 요소를 하나만 가지는 Enum

• 가장 바람직한 방법

객체 생성과 소멸

44

Page 45: Effective java

4. 객체 생성 제한

왜? static member만 모인 클래스

• java.lang.Math

• java.util.Arrays

• java.util.Collections

어떻게? 기본 생성자를 막는다.

객체 생성과 소멸

45

Page 46: Effective java

5. 불필요한 객체 생성 막기

왜? 객체 생성 비용

기능이 같은 객체 재사용

객체 생성과 소멸

46

Page 47: Effective java

5. 불필요한 객체 생성 막기

문제 String s = new Stirng(“foolish”) vs

String s = “foolish”

new Boolean(“true”) vsBoolean.valueOf(“true”)

객체 생성과 소멸

47

Page 48: Effective java

5. 불필요한 객체 생성 막기

문제

객체 생성과 소멸

48

Page 49: Effective java

5. 불필요한 객체 생성 막기

고려 사항 생성자가 하는 일이 거의 없는 객체 생성은 비용이 적다. 소득

없이 명확성과 단순성을 희생하지 말자.

데이터베이스 연결 같이 엄청나게 무거운 객체가 아니라면 직접 객체 풀을 만들지 말자.

객체 생성과 소멸

49

Page 50: Effective java

6. 쓸모 없는 객체 참조 제거

왜? 메모리 누수

• 자바에서?

• 스택 : 시스템 전역에서쓰임

객체 생성과 소멸

50

Page 51: Effective java

6. 쓸모 없는 객체 참조 제거

원인 자신의 메모리를 스스로 관리해서 참조가 쓸모 없는지 개발자

만 아는 경우

캐시에 넣어두고 까먹기

콜백을 리스너에 등록해 놓고 지우지는 않기

해법 가비지 컬렉터가 알아차리지 못하는 쓸모 없는 참조는 null로!

캐시, 콜백은 자동 소멸하도록!

객체 생성과 소멸

51

Page 52: Effective java

6. 쓸모 없는 객체 참조 제거

Weak, Soft, Phantom Reference

객체 생성과 소멸

52

Page 53: Effective java

7. Finalizer 쓰지 말기

Finalizer GC 전에 호출되는 메소드

protected void finalizer() throws Throwable

System.runFilnalizerOnExit

Runtime. runFilnalizerOnExit

문제 신속하게 실행된다는 보장이 없다.

반드시 실행된다는 보장도 없다.

예외가 발생하면 스택도 출력하지 않고 죽는다.

성능이 떨어진다.

객체 생성과 소멸

53

Page 54: Effective java

7. Finalizer 쓰지 말기

유혹 자원 회수

• 자원 회수는 자원을 가진 객체가 담당하고 try-finally에서 호출한다.

• Stream의 close, Connection의 close, Timer의 cancel 따위

용도 자원 회수는 try-finally로 한다.

혹시 자원 회수를 못했을 때 안전망

네이티브 객체 처리 안전망

객체 생성과 소멸

54

Page 55: Effective java

7. Finalizer 쓰지 말기

그래도 써야 하는 경우 최악의 경우 자원 회수를 못했을 때 안전 장치

• Stream, Connection, Timer는 finalizer 구현하고 있다.

네이티브 객체 처리 안전 장치• GC는 new로 생성한 객체만 처리

• 중요한 자원은 별도 종료 메소드로

웬만하면 쓰지 마라!

객체 생성과 소멸

55

Page 56: Effective java

7. Finalizer 쓰지 말기

그래도 써야 한다면 반드시 클래스 계층 구조의 모든 finalizer가 호출되도록 한다.

서브 클래스가 반드시 이렇게 구현하리란 보장이 없어……

객체 생성과 소멸

56

Page 57: Effective java

7. Finalizer 쓰지 말기

그래도 써야 한다면 Finalizer가 필요하면 Finalizer Guardian 방식으로 구현한다.

객체 생성과 소멸

57

Page 58: Effective java

II. 계약

공통 계약 equals, hashCode, toString, finalize, clone, compareTo

다른 클래스(특히 Collection)와 문제를 일으키지 않으려면 계약을 반드시 지켜야 한다.

클래스/인터페이스 자바 기본 단위

계약

58

Page 59: Effective java

8. equals

equals를 재정의하지 않는 경우 참조가 같은 메모리를 가리킨다.

• == true

같은지 비교할 이유가 없다. • Radom

슈퍼 클래스가 알맞게 구현• AbstractSet << HashSet

equals를 재정의하는 경우 값 자체가 같은지 판단해야 한다.

• Value class

• Map의 key, Set의 element

계약

59

Page 60: Effective java

8. equals계약 조건

재귀성• Null 아닌 x

x.equals(x) : true

대칭성• Null 아닌 x, y

x.equals(y) : true y.equals(x) : true

이행성• Null 아닌 x, y, z

x.equals(y) : true, y.equals(z) : true z.equals(x) : true

일관성• Null 아닌 x, y

x.equals(y) : true면 x, y가 변하지 않았다면 x.equals(y) : true

Null 아님• Null 아닌 x

x.equals(null) : false

계약

60

Page 61: Effective java

8. equals

계약 이행 대칭성 파괴

계약

61

Page 62: Effective java

8. equals

계약 이행 재귀성

• 일부러 어기지 않는 한 어길 수 없다.

대칭성• 어기기 쉽다.

계약

62

Page 63: Effective java

8. equals

계약 이행 전이성

• Point와 Point를 상속받은 ColorPoint가 있다. Point p2와ColorPoint p1, ColorPoint p3가 있다.

• 대칭성• ColorPoint.equals에서 Point인 경우와 ColorPoint인 경우를 나눠서 처

리하면 된다.

• 전이성• p1.equals(cp2) : true, p2.equals(p3) : true p1.equals(p3) false

일 수 있다. (세 점이 위치는 같고 p1, p3가 색이 다른 경우)

값을 표현하는 구체 슈퍼 클래스를 상속받아 값을 추가하는 구체 서브 클래스를 만드는 경우 대칭성과 전이성을동시에 지킬 수 있나? 불가능!

계약

63

Page 64: Effective java

8. equals

왜? 구체 클래스를 상속하려는 의도는 좋지 않다.

• 구체 클래스의 ‘구현’에 의존성이 생기기 때문이다.

• 상속 구조를 포기하고 합성(composition)을 택한다.

• 그나마 추상 클래스를 상속 받는 경우 equals 계약을 지킬 수 있다.

문제 사례

계약

java.util.Date

java.sql.TimeStamp

nanoseconds

64

Page 65: Effective java

8. equals

계약 이행 일관성

• 신뢰할 수 없는 자원에 의존하여 equals를 검사하는 경우 깨진다.• java.net.URL : IP 주소를 얻어와서 equals 실행

널이 아님• 당연하다.

• 따로 null 확인하는 것보다 instanceOf를 쓰면 된다.

계약

65

Page 66: Effective java

8. equals

equals 잘 만들기 == 를 이용해서 먼저 검사한다. 많은 값을 비교해야 하면 성능

에 ‘조금’ 이득이 있다.

instanceOf로 검사한다.

Object 타입인 인자를 형변환한다.

중요한 필드부터 비교한다.• 기본형은 ==로 비교한다. (float, double 제외)

• float과 doubl은 Float.compare, Doble.compar를 이용한다.

• 객체는 equals로 비교한다.

• 배열은 Arrays.equals로 비교한다. (>JDK 1.5)

• 필드가 null인 경우가 있으므로 null을 확인한다.

계약

66

Page 67: Effective java

8. equals

equals 잘 만들기 == 를 이용해서 먼저 검사한다. 많은 값을 비교해야 하면 성능

에 ‘조금’ 이득이 있다.

instanceOf로 검사한다.

Object 타입인 인자를 형변환한다.

중요한 필드부터 비교한다.• 기본형은 ==로 비교한다. (float, double 제외)

• float과 doubl은 Float.compare, Doble.compar를 이용한다.

• 객체는 equals로 비교한다.

• 배열은 Arrays.equals로 비교한다. (>JDK 1.5)

• 필드가 null인 경우가 있으므로 null을 확인한다.

계약

67

Page 68: Effective java

8. equals

equals 잘 만들기

계약

68

Page 69: Effective java

8. equals

equals 잘 만들기 equals()를 재정의했으면 반드시 hashCode()도 재정의한다.

너무 심하게 같은지 비교하지 마라.

중첩(Overloading)하지 마라.

@override 주석을 달아라.

계약

69

Page 70: Effective java

9. hashCode

equals를 재정의했다면 반드시 hashCode도 재정의해야한다.

왜? Hash 기반 Collection에서 문제가 발생한다.

계약

70

Page 71: Effective java

9. hashCode

계약 조건 hashCode는 일관성 있는 정수를 반환한다.

x.equals(y) : true x.hashCode() == y.hashCode()

x.equals(y) : false x.hashCode() != y.hashCode() 면Hash Collection 성능이 좋아진다.

계약

PhoneNumber p1 = new PhoneNumber(10, 8728, 7627);

PhoneNumber p2 = new PhoneNumber(10, 8728, 7627);

Map<PhoneNumber, String> m = new HashMap<PhoneNumber, String>();

m.put(p1, “YHI”);

m.get(p2); // null or “YHI”?

71

Page 72: Effective java

9. hashCode

좋은 hashCode equals가 false인 객체들은 최대한 다른 값 반환

• P47 참조

계약

72

Page 73: Effective java

12. compareTo

Comparable<T> 자연스러운 순서를 가지는 객체들

• String : 사전순

• Date : 연대순

public int comapteTo(T t)

순서를 다룰 때• Arrays.sort, Collections.sort

• TreeSet, TreeMap

계약

73

Page 74: Effective java

12. compareTo

계약 조건 sgn(x.compareTo(y)) == - sgn(y.compareTo(x))

x.compareTo(y) > 0 && y.compareTo(z) > 0 x.comapreTo(z) > 0

x.compareTo(y) == 0 sgn((x.compareTo(z)) == sgn(y.compareTo(z))

x.compareTo(y) == 0 x.equals(y) == true (선택)

상속 구조일 때 equals와 똑같은 문제 내포

계약

74

Page 75: Effective java

12. compareTo

구현 방법 네 번째 조건을 지키지 않았을 때 문서에 명시해야 한다.

• New BigDeciaml(“1.0”) vs New BigDeciaml(“1.00”)• equals false, compareTo true

• HashSet에는 둘 다 들어간다.

• TreeSet에는 하나만 들어간다.

타입을 비교할 필요 없다.• Generic Interface

너무 똑똑하게 구현하지 마라.• Overflow 위험

계약

75

Page 76: Effective java

10. toString

좋은 toString 간결하면서 사람이 읽고 이해하기 쉬운 형태로 표현한다.

클라이언트가 이 문자열을 파싱해서 쓰는 일이 없도록 한다.

계약

76

Page 77: Effective java

11. clone

Cloneable 복제를 허용한다는 의미를 가진 Mixin interface다.

정작 clone 메소드는 Object에 protecte로 선언한다.

Cloneable인 객체가 clone을 재정의하지 않은 경우 clone을호출하면 Object.clone이 그 객체를 복제한다.

Cloneable 인터페이스는 슈퍼 클래스인 Object의 메소드clone이 어떻게 동작하나 규정한다.

계약

77

Page 78: Effective java

11. clone

계약 조건 x.clone() != x

x.clone().getClass() == x.getClass()

x.clone().equals(x)

반환하는 객체는 생성자로 생성하지 않는다.

계약

78

Page 79: Effective java

11. clone

clone을 overriding 하려면 super.clone을 호출해서 복사본을 얻어 반환해야 한다.

계약

Object

SuperClass

SubClass

super.clone()

super.clone()

79

Page 80: Effective java

11. clone

clone 문제점

elements 필드가 final이라면?

객체(result)는 모든 값이 복제 되어야 한다.• deepCopy vs shalowCopy

계약

80

Page 81: Effective java

11. clone

clone 잘 만들기 clone을 재정의하면

• public

• 반환값은 Object가 아닌 자기 타입

• CloneNotSupportedException 생략

상속을 목적으로 만든 추상 클래스• Cloneable하지 않아야

• Object처럼 clone 구현해야

계약

@override public Foo clone()

81

Page 82: Effective java

11. clone

객체 복제는? 복제 생성자, static 팩토리 메소드

• final 사용 제약 없음

• 예외 처리 없음

• 타입 변환 가능 (예: Collection끼리 변환)

계약

82

Page 83: Effective java

13,14. 정보 은닉

모듈 설계 무엇을 드러낼 것인가?

드러내는 순간, 귀찮아 진다. 최대한 감추자.

정보 은닉/캡슐화• 인터페이스로만 메시지 주고 받는다.

• 내부에서 어떻게 하든 상관없다.

클라이언트 중심 설계• 클라이언트가 쓸 것만 드러낸다.

• 클라이언트가 가능하면 수정하는 일이 없게 드러낸다.

계약

83

Page 84: Effective java

13,14. 정보 은닉

무엇이 드러나는가?

계약

pacakge

public class

Protected field

Public field

Serializable field

Public method

84

Page 85: Effective java

13,14. 정보 은닉

클래스 public

패키지 전용

private inner class/interface

계약

pacakge

public class

Protected field

Public field

Serializable field

Public method

Package-only class

public class

Private

nested class

85

Page 86: Effective java

13,14. 정보 은닉

멤버 Public

Protected

Package-only

Private

계약

86

Page 87: Effective java

13,14. 정보 은닉

클래스 설계 Public API를 신중하게 선택한다.

나머지는 private으로 설정한다.

패키지 내부에서 꼭 접근해야 하는 멤버라면 package-only로변경한다.

Package-only가 자주, 집중해서 한 곳에서 발생하면 응집도가떨어지고 결합도가 커진 경우(SRP 위배)다.

Protected는 정말 필요한지 고민한다.

Serializable을 구현할 때 주의한다.

인스턴스 필드는 public으로 만들지 마라.

계약

87

Page 88: Effective java

13,14. 정보 은닉

클래스 설계 public static final 필드

• Enum을 쓴다.

• 꼭 필요하다면 불변이거나 변하더라도 영향이 없어야 한다.• 원래 불변객체 : String, BingInteger 따위

• 불변으로 만들기 : Arrays.asList

• 복사본 만들기

계약

88

Page 89: Effective java

13,14. 정보 은닉

접근자와 변경자 클라이언트가 접근자와 변경자를 이용해서 뭔가 한다면, 해당

객체가 해야 하는 일이 아닌지 고민한다.

외부에 정보를 제공해야 한다면 자기 책임을 다하는 객체를 제공한다.

잘 만들어진 객체라면 setter는 거의 필요없다.

데이터를 주고 받지 말고, 메시지를 주고 받으면서 책임을 가진객체에게 위임한다.

계약

Money a, b, c;

c.setValue(a.getValue() + b.getValue());

Money a, b, c;

c = a.add(b);

public double getBalance(); Public Money getBalance();

89

Page 90: Effective java

13,14. 정보 은닉

접근자와 변경자 데이터베이스 연결 같은 최전선 맞닿은 경계에서는 value

object와 getter/setter가 필요하다.

패키지 전용 클래스, private 내부 클래스는 필드를 그대로 드러내도 된다.

계약

90

Page 91: Effective java

22. Static 멤버 클래스가 좋아

중첩(nested) 클래스 Static 멤버

Non-static 멤버

Anonymous

Local

계약

91

Page 92: Effective java

22. Static 멤버 클래스가 좋아

Static 멤버 외곽 클래스의 모든 인스턴스가 공유

외곽 클래스의 모든 static 멤버에 접근

Non-static 멤버 외곽 클래스의 특정 인스턴스(Enclosing.this)마다 클래스 하

나씩 생성

외곽 클래스의 모든 멤버에 접근

계약

92

Page 93: Effective java

22. Static 멤버 클래스가 좋아

Anonymous 필요한 시점에 선언하고 생성해서 쓰고 버리는 객체

static 환경이면 static으로, non-static 환경이면 non-static으로 동작

제약• 이름이 없다.

• Static 멤버 못 가진다.

• 인터페이스 구현 불가, 상속 불가하다.(new Type() {} 형태니까)

계약

93

Page 94: Effective java

22. Static 멤버 클래스가 좋아

Local {}로 둘러 쌓인 영역에서 유효한 클래스

메소드 내부에서 지역 변수들을 하나로 묶어서 쓰고 싶을 때

계약

void foo()

{

class Point

{

int x;

int y;

Point(int x, int y)

{

this.x = x;

this.y = y;

}

}

Point p1 = new Point(0, 0);

}

94

Page 95: Effective java

21. 전략 클래스

함수 포인터, 람다식처럼 특정 기능을 수행하는 메소드를전달하는 방법

Comparable vs Comparator Comparable

• 자연스러운 객체의 순서

Comparator• 상황에 따른 여러 가지 객체 순서 정의

95

Page 96: Effective java

21. 전략 클래스

함수 포인터, 람다식처럼 특정 기능을 수행하는 메소드를전달하는 방법

Comparable vs Comparator Comparable

• 자연스러운 객체의 순서

Comparator• 상황에 따른 여러 가지 객체 순서 정의

96

Page 97: Effective java

21. 전략 클래스

구현 익명 클래스

• 자주 쓰이면 상수로 정의하고 재사용한다.

97

Page 98: Effective java

21. 전략 클래스

구현 구체 클래스

• 익명 클래스는 다른 인터페이스를 추가로 구현할 수 없기 때문에 다른타입이 되려면(예를 들어, Serializable) 별도 장치가 필요하다.

98

Page 99: Effective java

15. 불변 객체

불변 객체란? 일단 생성되면 상태가 바뀌지 않는 객체

String, Integer, BigDecimal, BigInteger 따위의 인스턴스

왜? 불변조건을 만족하게 만들기가 쉽다.

쓰레드 안전!

안전하게 다른 객체의 한 부분을 구성할 수 있다.

안전하게 상수로 공유할 수 있다.

같은 타입의 불변 객체들은 내부 구조를 공유할 수 있다.

계약

99

Page 100: Effective java

15. 불변 객체

어떻게? 객체 상태를 변경하는 메소드가 없다.

서브 클래스를 만들지 못하게 한다.• 클래스를 final로 지정 : 패키지 내부에서 확장도 불가능

• static final factory method를 제공하고 생성자를 감추는 방법

모든 필드를 final로 지정한다.

모든 필드를 private으로 지정한다.

가변 객체를 멤버로 가진다면 외부에서 접근하지 못하게 한다. 외부에서 가변 객체를 공급받는다면 방어 복사한다.

계약

100

Page 101: Effective java

15. 불변 객체

단점 객체가 가지는 값마다 별개 객체가 필요하다.

• BigInteger는 내부에 100만 비트 저장 공간을 가진다.

• 달랑 1비트만 바뀐 BigInteger가 또 생성

• 패키지 전용 가변 객체를 써서 해결

• 불변 객체에 대응하는 가변 객체 제공• String StringBuilder

• BingInteger BitSet

계약

101

Page 102: Effective java

16. 상속보다 합성

상속(inheritance) 클래스 상속

인터페이스 상속

합성(composition) 이미 존재하는 객체들을 조합해서 원하는 객체를 만든다.

계약

EngineCar

Tire

102

Page 103: Effective java

16. 상속보다 합성

왜? 화이트 박스 vs 블랙 박스

계약

AdvancedList

List(from util)

<<Interface>>

ArrayList(from util)

AdvancedList

List(from util)

<<Interface>>

103

Page 104: Effective java

16. 상속보다 합성

클래스 상속 슈퍼 클래스 내부 구현을 알아야 한다.

계약

104

Page 105: Effective java

16. 상속보다 합성

클래스 상속 슈퍼 클래스 내부 구현을 알아야 한다.

슈퍼 클래스가 변하면 서브 클래스들도 변한다.

Overriding해서 생긴 문제가 아니다.• 슈퍼 클래스가 나중에 같은 이름을 가진 메소드를 추가하면 문제가 발

생한다.

슈퍼 클래스가 상속에 맞게 설계되지 않았기 때문이다.• OCP 위배!

계약

105

Page 106: Effective java

16. 상속보다 합성

합성 Set을 구현한 모든 객체로부터 생성 가능

Set이 쓰이는 모든 곳에 이용 가능

계약

합성

전달

106

Page 107: Effective java

16. 상속보다 합성계약

합성 vs 상속 정말 is-a 관계일 때만 상속

LSP를 만족할 때

107

Page 108: Effective java

16. 상속보다 합성계약

합성 vs 상속

108

Page 109: Effective java

18. 추상 클래스보다 인터페이스계약

왜? 인터페이스는 기존 클래스에 쉽게 추가할 수 있다.

• 시그니처가 같은 메소드가 없다면 바로 추가하고 구현하면 된다.

• 추상 클래스는 불가능하거나(이미 다른 클래스를 상속하고 있어서) 부작용이 발생(상속받은 클래스의 서브 클래스도 모두 클래스 계층 구조에 포함되므로)한다.

인터페이스는 믹스인을 정의하기 쉽다.• 자그마한 기능들을 추가하기 쉽다.

• Comparable, Serializable

많은 클래스를 만들어 내지 않고도 복잡한 타입 구조를 만들수 있다.

109

Page 110: Effective java

18. 추상 클래스보다 인터페이스계약

인터페이스 + 뼈대 구현 추상 클래스 Set, List, Map + AbstractSet, AbstractList, AbstractMap

해당 인터페이스 빠르게 구현할 수 있게 지원한다.

110

Page 111: Effective java

18. 추상 클래스보다 인터페이스계약

인터페이스 + 단순 구현 구체 클래스 android.widget.SimpleAdapter

상황에 따라 그대로 쓰거나 상속 받는다.

111

Page 112: Effective java

17. 상속을 위한 클래스 설계계약

상속을 위한 클래스란? 메소드를 재정의(overriding)해도 문제가 없는 클래스

문제 재정의하는 순간 슈퍼 클래스의 구현이 드러날 수 밖에 없다.

112

Page 113: Effective java

17. 상속을 위한 클래스 설계계약

규칙 재정의 가능한 메소드가 소속 클래스의 다른 메소드를 호출하

면 상세한 동작을 문서화한다.• Iterator.remove가 영향을 준다.

113

Page 114: Effective java

17. 상속을 위한 클래스 설계계약

규칙 제대로 동작하는 서브 클래스를 만들 때 도움이 될 만한

protected 메소드(드물게 필드)를 제공하고 문서화 한다.

114

Page 115: Effective java

17. 상속을 위한 클래스 설계계약

규칙 생성자에서 절대 재정의 가능한 메소드를 호출하지 않는다.

clone(Cloneable), readObject(Serializable)에서도 마찬가지다.

115

Page 116: Effective java

17. 상속을 위한 클래스 설계계약

규칙 private helper method

Public Class

Constuctor

Overridable

Method

Public Class

Constuctor

Overridable

Method

Private

Helper

116

Page 117: Effective java

20. 딱지 클래스는 죄악계약

OCP를 기억하라.

public void drawAll(Shape[] shapes)

{

for (int i = 0; i < shapes.length; i++)

{

Shape shape = shapes[i];

if (shape.shapeType() == Shape.CIRCLE)

{

((Circle)shape).drawCircle();

}

else if (shape.shapeType() == Shape.SQUARE)

{

((Square)shape).drawSquare();

}

}

}

117

Page 118: Effective java

21. 인터페이스는 타입정의 할 때만

타입?

계약

타조 기러기

비행기

여객기 전투기

레이더

날 수 있는

고도를

알려달라

118

Page 119: Effective java

21. 인터페이스는 타입정의 할 때만

상수 정의

계약

119

Page 120: Effective java

38. 인자 유효성 검사

유효성 검사 메소드 제일 처음에 인자 유효성을 검사한다.

Public 메소드면 적절한 예외를 던지고 예외상황을 문서화한다.

Public 메소드가 아니면 assert로 검사한다.

나중에 쓰려고 보관한 인자는 특히 신경 써서 검사한다.

계약

120

Page 121: Effective java

39. 방어 복사

왜? 클라이언트는 악의든 무지든 객체의 불변 규칙을 깨려고 노력

한다.

계약

121

Page 122: Effective java

39. 방어 복사

왜? 클라이언트는 악의든 무지든 객체의 불변 규칙을 깨려고 노력

한다.

계약

122

Page 123: Effective java

39. 방어 복사

공격

클라이언트가 공급하는 모든 가변 객체는 방어 복사한다.• 유효성 검사 전에 복사해서 보관한다.

• 인자가 아니라 복사본을 대상으로 검사해야 한다.

• Date.clone이 Date 서브 클래스 인스턴스를 반환할 수 도 있기 때문에 clone으로 복사하면 안 된다.

계약

123

Page 124: Effective java

39. 방어 복사

공격

클라이언트에게 가변 객체를 제공할 때 복사한다.

원흉은?

계약

124

Page 125: Effective java

40. 시그니처 설계

이해하기 쉽고 일관성 있는 이름을 지어라.

너무 편리한 메소드를 제공하려고 애쓰지 마라. 여러 기능을 한 방에 처리하는 메소드를 제공하지 마라. 만약,

정말 꼭 필요하고 자주 쓰일 때만 제공한다.

인자 타입은 클래스보다 인터페이스를 써라. Hashtable보다 Map이 낫다.

Boolean보다 요소가 두 개인 Enum을 써라.

계약

125

Page 126: Effective java

40. 시그니처 설계

너무 많은 인자를 피한다. 인자가 3개 넘어가면 문서 없으면 안 된다. 타입이 같은 인자라

면 지옥.

인자 줄이는 법• 메소드 쪼개기

• 리스트의 일부에서 특정 객체의 위치를 찾는 메소드 : findInRange(int, int, Object) subList(int, int).indexOf(Object)

• 인자를 묶어주는 static 멤버 클래스 도입

• 빌더

계약

126

Page 127: Effective java

41. 오버로딩

출력은?

계약

127

Page 128: Effective java

41. 오버로딩

오버로딩 규칙 오버로딩 규칙만 명세서 34쪽! 헷갈린다 헷갈려.

인자 개수가 같은 메소드는 오버로딩하지 않는다.

가변인자를 사용하면 오버로딩하지 않는다.

인자가 확실히 다르면 인자 개수와 상관없이 오버로딩할 수 있다.• BigInteger(byte[]) vs BingInteger(String)

• 생성자는 어쩔 수 없지만 static factory method가 더 바람직하다.

• List.remove(int) vs List.remove(Object)• 서로 혼동할 경우는 거의 없지만 바람직하지 않다.

계약

128

Page 129: Effective java

41. 오버로딩

오버로딩 규칙 오토박싱을 조심하라.

• List<E>.remove(int) vs List<E>.remove(E)

계약

129

Page 130: Effective java

41. 오버로딩

오버로딩 규칙 기존 클래스가 진화하는 경우

• 어쩔 수 없는 오버로딩

• 오버로딩 메소드들이 똑같은 일을 처리

계약

130

Page 131: Effective java

42. 가변인자

0..n개 인자

계약

131

1..n개 인자

Page 132: Effective java

43. 가변인자

Final 배열을 인자로 받는 메소드는 가변인자로 바꿀 수있다. Arrays.asList(Object[]) Arrays.asList(T... a)

• JDK <= 1.4 compile error

• JDK >= 1.5 [[I@3e25a5]

배열 출력법(>= 1.5)

계약

132

Page 133: Effective java

43. 가변인자

호출 비용 호출할 때마다 배열을 생성하고 초기화하므로 비용이 크다.

인자 3개 이하 호출이 대부분이면 오버로딩한다.

계약

133

Page 134: Effective java

43. Null 반환

Null 반환 뭔가 없을 때 null을 반환하면 좋지 않다.

• 클라이언트에서 null을 확인해야 한다.

• Null을 검사해서 따로 처리해야 하므로 구현이 복잡하다.

계약

134

Page 135: Effective java

43. Null 반환

길이가 0인 배열과 컬렉션 비용이 거의 들지 않는다.

• 불변 객체

• 재사용

계약

135