이펙티브 자바 1장

송은우·2022년 10월 3일
0

TIL

목록 보기
19/61

1장

enum은 클래스의 일종이고, annotation은 인터페이스의 일종이다
인터페이스, 클래스, 배열은 참조 타입. 기본값은 기본값

클래스의 멤버
메서드, 필드, 멤버 클래스, 멤버 인스턴스
메서드 시그니처= 이름+ 인자 타입. 반환값은 의미 없음

이 책 상속=서브클래싱 인터페이스 상속 대신 확장, 구현
아무것도 없는 접근 수준 : 패키지 접근=>패키지-프라이빗
공개 API(API로 명명): 클래스, 인터페이스, 패키지를 통해 접근할 수 있는 모든 클래스, 인스턴스, 생성자, 멤버, 직렬화된 형태를 말한다.
API의 사용자 : user
API를 사용하는 코드 : client
클래스, 인터페이스, 생성자, 멤버, 직렬화된 형태를 총칭해 API요소라 명한다
공개 API는 특정 패키지 바깥에서 접근 가능한 수준

2장

생성자 => 정적 팩토리 메서드를 고려

public static Boolean valueOf(boolean b){
	return b?Boolean.TRUE, Boolean.FALSE;
}

를 통해서 래핑

특정 클래스의 인스턴스를 반환하는 것
Factory패턴과는 살짝 다름

정적 팩토리가 생성자보다 좋은 이유
1. 이름
2. 호출 시마다 인스턴스를 새로 만들 필요가 없다
플라이웨이트 패턴같은 느낌. 이미 생성된 객체를 캐싱해서 계속 제공할 수도 있음
인스턴스의 생명 주기를 관리할 수 있다. 싱글톤도, 인스턴스화 불가 클래스도 가능, 불변성 보장같은 것도 가능
열거타입은 싱글톤을 보장 가능
3. 하위타입의 객체를 마음대로 반환할 수 있다.
인터페이스만 있으면 되기에, overriding 한 것을 내맘대로 쓸 수 있다.
API를 만들 때, 공개할 부분은 당연히 적을 수록 좋다는 법칙을 지키기 용이하다.
Java8전에는 인터페이스 + static이 불가능. 따라서 인스턴스화 불가 클래스인 companion class를 만들어고, 이를 통해 관리. 지금은 아님
java8까지는 interface+priv가 불가능. 9 이후는 아님
4. 입력 매개변수에 따라 다른 클래스의 객체 가능
오버로딩의 장점
예를 들면 Enum관리가 64개보다 적은 경우 Long에 비트연산으로 저장. 64초과는 long배열로 관리하는 것. 하지만 알 필요 없음
5.정적 팩토리 메서드를 작성하는 시점에는 반환할 객체의 클래스가 존재하지 않아도 된다.
서비스 제공자 프레임워크의 핵심을 담당함
구현체의 동작을 정의하는 서비스 인터페이스. 제공자가 구현체를 등록하는 등록 api, 클라이언트가 서비스의 인스턴스를 받는 서비스 접근 api. 서비스 제공자 인터페이스

제공자 인터페이스 없으면 리플렉션을 사용해야 함
브릿지 패턴, di같은 것 역시 서비스 제공자
단점
상속시 public,protected생성자 필요. 따라서 하위 클래스 만들기 힘듦=> 컴포지션(복합체) 패턴 사용
정적팩토리메서드 찾기 귀찮음
from, of, valueof, getinstance, create,gettype, newtype, type
public생성자보다는 정적팩토리가 좋은 경우가 많음

빌더 고려
자바빈스 패턴 => 빈객체 생성 후 setter 반복. 보다는 빌더가 합리적
보통 마지막 생성할 때 있는지 검사, 각각 인자 전달시 예외 처리 가능해서 편함 IllegalArgumentException 던짐
불변 객체 vs 가변객체
불변 : 대충 String 원시타입?
불변식 실행 동안 반드시 만족해야하는 조건. 리스트의 길이는 최소0 같은 무조건 만족해야 하는 조건. 이는 가변도 불변식을 구현함

private생성자나, 열거타입으로 싱글턴을 보장
AccessibleOject.setAccisible? 리플렉션 API?
https://codechacha.com/ko/reflection/

2번째 생성시 예외 던짐 도 관리를 해야 함

다른 방식은 정적 팩터리를 public static으로 제공함.
getInstance()메서드를 사용하기에 무조건 같은 것 보장
45p
열거타입의 싱글턴이 가장 좋은 선택인 경우가 많다. 상속해야 한다면 불가능하긴 함
열거타입이 다른 타입의 인터페이스를 구현하도록 할 수는 있다
인스턴스화를 막으려면 private생성자를 만들어야 한다.
상속해서 써버림.

직접 명시하는 것보다는 객체 주입
단 의존관계가 많아지면 불편하지만, 프레임워크로 처리

불필요한 객체 생성은 피해라
Boolean도 Boolean(String) 생성자 deprecate, Boolan.valueOf(String) 으로 변경

정규표현식용 패턴은 Finite state machine을 만들어서 진짜 처리함
그래서 이를 캐싱해두는 쪽이 좋음
그래서 private static으로 만들어두고, 이를 그냥 단순히 호출하는 메서드를 public static으로 열어두는 쪽이 깔끔함

박싱된 타입은 사용하지 않는 것이 좋다. 성능 차이가 정말 심함. 변환을 계속 해야함

참조 해제 하기
list[1]=null;
weakHashMap, weakSet 같은 것을 사용하는 것을 권장
캐싱도 주의
콜백을 추가만 하는 경우

finalizer는 예측 불가능, 위험도 있음 deprecated 됨
cleaner 역시 일반적으로 불필요, 느리고 예측 불가능
C++의 destructor와 다름
finalizer, cleaner가 즉시 실행되는 개념이 아님. 따라서 close를 여기다 쓰면 큰일남 filepointer overflow남
여기서 참조 해제하는 것도 안좋음. 가비지 컬렉터가 아직 일이 남았다고 생각해서 회수 안해감
Transaction보장을 finalizer에 맡기면 진짜 재밌을듯

[System,Runtime]runFinalizersOnExit 에서 호출 가능하지만, 별 의미 없음 ThreadStop을 불러 일으키기에 쓰면 안됨
여기서 예외 나면 더 이상 진행해버리지 않음
성능도 구림
심지어 보안 역시 위험함. 생성자나 직렬화 과정에서 에러가 나면, 하위 클래스에서 finalizer가 실행될 수 있다.
따라서 final이 아닌 클래스를 finalizer 공격으로부터 방어하려면 finalize 메서드를 만들고, final로 선언하면 됨
AutoCloseable 구현하면, 닫는 과정 처리가 매우 좋지만,

profile
학생의 마음가짐으로 최선을 다하자

0개의 댓글