자바 지원타입 : 인터페이스, 클래스, 배열 기본타입
어노테이션은 인터페이스 일종, 열거타입은 클래스 일종
인터페이스, 클래스, 배열은 참조타입
클래스 멤버는 필드 메서드 멤버 클래스, 멤버 인터페이스가 있음
클래스는 생성자 별도로 정적 팩토리 메서드를 제공한다
public static Boolean valueOf(boolean b){
return b ? Boolean.TRUE : Boolean.FALSE;
}
장점
단점
Date d = Date.from(instant);
Set<Rank> faceCards = EnumSet.of(jack, queen, king)
BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE)
StackWalker = luke = StackWalker.getInstance(options)
Object newArray = Array.newInstance(classObject, arrayLen);
FileStore fs = Files.getFileStore(path)
BufferedReader br = Files.newBufferedReader(path)
List<Complaint> litany = Collections.list(legacyLitany)
package com.springandjava.Test.effectivejava.chapter2;
public class ex2 {
private final int size;
private final int servings;
private final int fat;
private final int sodium;
private final int cal;
public static class Builder {
private final int size;
private final int servings;
private int fat = 0;
private int sodium = 0;
private int cal = 0;
public Builder(int size, int servings){
this.size = size;
this.servings = servings;
}
public Builder calories(int val){
cal = val;
return this;
}
public Builder fat(int val){
fat = val;
return this;
}
public Builder sodium(int val){
sodium = val;
return this;
}
public ex2 build() {
return new ex2(this);
}
}
private ex2(Builder builder) {
servings = builder.servings;
size = builder.size;
fat = builder.fat;
cal = builder.cal;
sodium = builder.sodium;
}
}
싱글톤 : 인스턴스를 오직 하나만 생성할 수 있는 클래스를 말함
클래스를 싱글톤으로 만들면 이를 사용하는 클라이언트를 테스트하기가 어려워짐
일반적으로 생성자는 private으로 만들고, 접근 수단으로 public static을 만든다
public class ex3 {
public static final ex3 INSTANCE = new ex3();
public ex3(){}
public void sss(){}
}
public class ex3 {
public static final ex3 INSTANCE = new ex3();
public ex3(){}
//추가
public static ex3 getInstacne() {
return INSTANCE;
}
public void sss(){}
}
getInstance는 항상 같은 객체의 참조를 반환
위 두방식 모두 직렬화 구현시 Serializable 구현만으로 안됨
모든 인스턴스 필드를 일시적이라고 선언, readresolve 메서드를 제공해주어야함
안그러면 역직렬화 때마다 새로운 인스턴스가 만들어짐
//싱글턴임을 보장하는 readResolve 메서드
private Object readResolve(){
//진짜 반환하고 가짜는 GC에 맡긴다
return INSTANCE;
}
public enum ex {
INSTANCE;
public void sss(){}
}
원소가 하나인 열거 타입을 선언
추상클래스로 만드는 것으로는 인스턴스화를 막을 수 없다
package com.springandjava.Test.effectivejava.chapter2;
public class ex4 {
private ex4() {
throw new AssertionError();
}
}
명시적 생성자가 private → 밖에서 접근 불가, 상속 불가능
→ 사용처 → 정적 메서드만 따로 모아 놓은 클래스
사용하는 자원에 따라 동작이 달라지는 클래스에는 정적 유틸리리 클래스나 싱글턴 방식이 적합하지 않음
public class ex5 {
private final Lexicon dict;
public ex3(Lexicon dict){
this.dict = Objects.requiredNonNull(dict)
}
}
의존 객체 주입으로 유연성을 부여
비싼 객체 → 캐싱하여 재사용
public class ex6 {
static boolean isRomanNumeral (String s){
return s.matches("^(?=.)" + (X));
}
}
String.matches 는 반복사용시 재새용 비용이 높음, pattern 인스턴스는 바로 GC 로 감
public class ex6 {
private static final Pattern ROMAN = Pattern.compile(
"^(?=.)");
static boolean ex6 (String s){
return ROMAN.matcher(s).matches();
}
}
불변 pattern 인스턴스 클래스 초기화 과정(정적초기화) 직접 생성 및 캐싱, 나중에 ex6 매서드가 호출될 떄마다 이 인스턴스 재사용
불필요한 객체 생성 : 오토박싱
오토박싱이란? 기본 타입과 그에 대응하는 박싱된 기본타입의 구분을 흐려주지만 완전히 없애는 것은 아님
→ 박싱된 기본타입보다 기본타입을 사용하고, 의도치 않은 오토박싱이 숨어들지 않도록 주의하자
private static long sum(){
Long sum = 0L;
for(long i = 0; i<= Integer.MAX_VALUE; i++)
sum +=i;
return sum;
}
package com.springandjava.Test.effectivejava.chapter2;
import java.util.Arrays;
import java.util.EmptyStackException;
public class ex7 {
private Object[] elements;
private int size = 0;
private static final int DEFAULT = 16;
private ex7(){
elements = new Object[DEFAULT];
}
public void push(Object e){
ensureCapacity();
elements[size++] = e;
}
public Object pop(){
if (size == 0){
throw new EmptyStackException();
}
return elements[--size];
}
private void ensureCapacity(){
if (elements.length == size)
elements = Arrays.copyOf(elements, 2 * size + 1);
}
}
스택에서 꺼내진 객체는 GC가 회수하지 않음
→ 왜? 그 객체들이 다 쓴 참조를 갖고 있기 때문
다쓴 참조란?
→ 다시 쓰지 않을 참조라는 뜻
가비지 컬렉션은 객체 참조 하나를 살려두면 그 연관된건 다 회수 못함
→ 해결법?
→ 해당 참조 다 썼을시 null 처리
여기서는 스택에서 꺼내지는 pop 메서드에 처리
public Object pop(){
if (size == 0){
throw new EmptyStackException();
}
Object result = elements[--size];
elements[size] = null;
return result;
}
elemets[size] = null 처리 해준다
Null 처리 언제 해주어야 하나?(3가지 방법)
자기 메모리를 직접 관리하는 클래스라면(ex 스택) 메모리누수 주의
참조동안만 엔트리가 살아있는 캐시가 필요할 때 사용
Java - Collection - Map - WeakHashMap (약한 참조 해시맵) - 조금 늦은, IT 관습 넘기 (JS.Kim)
public class WeakHashMapTest {
public static void main(String[] args) {
WeakHashMap<Integer, String> map = new WeakHashMap<>();
Integer key1 = 1000;
Integer key2 = 2000;
map.put(key1, "test a");
map.put(key2, "test b");
key1 = null;
System.gc(); //강제 Garbage Collection
map.entrySet().stream().forEach(el -> System.out.println(el));
}
}
결과 (null 로 할당된 key1이 Map 내에서 사라졌다.)
2000=test b
Process finished with exit code 0
위 코드에서보면 null 처리된 key1 이 약한 참조가 되어 GC되고, 출력하면 key1 값은 안나옴
1) ScheduledThreadPoolExecutor
Java - ScheduledThreadPoolExecutor 사용 방법
2) LinkedHashmap의 removeEledestEntry
[java] HashMap 업그레이드 ! 순서 있는 HashMap ! LinkedHashMap 이란 ??
3)java.lang.ref
자바 레퍼런스와 가비지 컬렉션(Java Reference & Garbage Collection)
fiinalizer, cleaner → 객체 소멸자
c++ → destructor
대체 방법?
AutoCloseable 구현, 인스턴스 종료시 close 메소드 호출 예외처리시 try-with-resource 사용
그럼 언제 사용?
대체망 역할 → 클라이언트가 늦게라도 자원 회수 처리 해줄 경우 , FileInputStream, FileOutputStream, ThreadPoolExecutor
package com.springandjava.Test.effectivejava.chapter2;
import java.lang.ref.Cleaner;
public class ex8 implements AutoCloseable {
private static final Cleaner cleaner = Cleaner.create();
//State -> runnalbe 구현
private static class State implements Runnable {
int numJunkPiles;
State(int numJunkPiles){
this.numJunkPiles = numJunkPiles;
}
@Override
public void run(){
System.out.println("방 청소");
numJunkPiles = 0;
}
}
//clenable과 광유
private final State state;
private final Cleaner.Cleanable cleanable;
public ex8(int numJunkPiles) {
state = new State(numJunkPiles);
cleanable = cleaner.register(this, state);
}
//안전망
@Override
public void close(){
cleanable.clean();
}
}
자원닫기중 대부분은 finalizer를 활용하지만 이는 좋지 못하다
대신 try-finally를 사용했다
하지만 자원이 2개 이상이면 가독성이 안좋음 → try-with-resources 사용
public class ex9 {
static void copy(String src, String dst) throws IOException{
try(InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dst)) {
byte[] buf = new byte[BUFFER_SIZE];
int n;
while ((n = in.read(buf)) >= 0)
out.write(buf, 0,n);
}
}
}
아래것을 try-with-resources로 구현
//
// InputStream in = new FileOutputStream(dst);
// try {
// OutputStream out = new FileOutputStream(dst);
// try{
// byte[] buf = new byte[BUFFER_SIZE];
// int n;
// while ((n = in.read(buf)) >= 0)
// out.write(buf,0,n);
// } finally {
// out.close();
// } finally {
// in.close();
// }
// }
}