클래스의 인스턴스를 반환하는 단순한 정적 메소드
클래스의 인스턴스는 기본적으로 public 생성자를 통해서 얻을수 있다. 하지만 생성자와 별도로 정적 팩토리 메소드를 하면 아래와 같은 장점을 얻을수 있다.
static pulib 메소드만 제공하는 클래스는 상속할 수 없다.
생성자는 javadoc에 명확하게 나오지만 static factory method는 일반 메소드일 뿐이므로 특별하게 취급하지 않는다. 알려전 규약에 따라 짓는 식으로 문제를 완화해야 한다.
from : 매개 변수를 받아서 해당 타입의 인스턴스를 반환
Date date = Date.from(today);
of : 여러 매개변수를 받아서 인스턴스 반환
Set<Rank> lol = EnumSet.of(iron,bronze,silver,gold,platinum,diamond,master,grandmaster,challenger);
valueOf : from 과 of의 더 자세한 버전
BigInteger price = BigInteger.valueOf(Integer.MAX_VALUE);
instance / getInstance : 인스턴스를 반환(같은 인스턴스임을 보장 x)
Users users = UserInstance.getInstance(User);
Create / newInstance : 매번 새로운 인스턴스를 생성하여 반환함
Object newArray = Array.newInstance(class, arrayLen);
File file = Files.getFilestore(path);
BufferedReader br = File.newBufferedReader(path);
type : getType과 newType의 간결한 버전
List<custom> customList = Collections.list(list);
생성자와 정적 팩토리 메서드 모두 똑같은 단점이 있는데 Optional parameter가 많다면 불편해진다.
점층적 생성자 패턴 : 확장성이 좋지 않음
User user = new User(1,"신복호",29);
자바빈 패턴 : 일관성이 깨지며, 불변으로 만들수 없다.
User user = new User();
user.setId(1);
user.setName("신복호");
user.setAge(29);
빌더패턴 : 점층적인 생성자 패턴의 안정성과 자바빈 패턴의 가독성을 함께 할수 있다.
User user = new User().bulider(1)
.name("신복호")
.age(29);
singleton - 인스턴스를 오로지 하나만 생성할 수 있는 클래스를 말하며 아래 처럼 3가지 방법이 있다.
public static final을 사용하는 방법
public class User {
public static final User INSTANCE = new User();
private Users() {}
}
정적 펙토리 메소드를 제공하는 방식
public class User {
public static final User INSTANCE = new User();
private Users() {}
public static Users getInstance() { return INSTANCE }
}
-> 두가지 방식의 경우 리플랙션 API를 사용하는 경우 private 에 의해 싱글톤 방식이 깨질수 있다.
Enum을 사용하는 방식
public enum Users {
INSTANCE;
}
생성자를 명시하지 않으면 컴파일러가 기본 생성자를 생성한다. 따라서 인스턴스화를 막으려면 private 생성자를 명시적으로 생성해줘야 한다.
혹시라도 클래스 내부에서 생성자를 호출하지 않도록 오류를 던지는것도 좋다.
public class User {
private User{
throw new AssertionError();
}
}
추상 클래스로 만드는 것은 자기 자신의 인스턴스화를 막을수는 있지만 하위 클래스를 만들어 인스턴스화를 할수 있음
대부분의 클래스가 하나 이상의 자원에 의존한다. 이런 클래스를 정적 유틸리티 클래스로 구현하면 유연하지 않고 테스트도 어렵다.
public class User {
private static final info = new Infomation();
private User() {} // 객체 생성 방지
public static boolean isUsers(String name) {/*구현 생략 */ }
public static List<String> infoList(Integer id) { /* 구현 생략 */ }
}
인스턴스를 생성할때 필요한 자원을 넘겨주면 된다.
불변을 보장하여 같은 자원을 사용하려는 여러 클라이언트가 의존 객체들을 안심하고 공유할수 있다.
또한 생성자 뿐만 아니라 정적 팩토리, 빌더 모두 똑같이 응용이 가능하다.
클래스가 하나 이상의 동작에 영향을 주는 자원에 의존한다면, 자원을 생성자 또는 정적 팩토리나 빌더에 넘겨주자
public Users(Supplier<? extends info> infomation) {
this.info = infomation.get();
}
String name = "Shin";
String name2 = "Hong";
boolean request = false;
if(name == name2 ) { request = true} // true;
String name3 = new String("Shin");
String name4 = new String("Hong");
boolean request2 = false;
if(name3 == name4 ) { request2 = true} // false;
정적 팩토리 메소드에서도 불필요한 객체 생성을 줄일수 있다. (valueof / java9 -> Deprecated)
생성 비용이 비싼 객체를 재사용하는 것도 중요하다.
자바에서는 c,c++ 처럼 직접 메모리를 관리하지 않고 GC가 알사서 사용이 끝난 객체를 회수하나 그렇다고 메모리 관리 신경을 써야 한다.
특히 자기 메모리를 직접 관리하는 클래스면 메모리 누수에 주의해야한다.
참조를 담은 변수의 유효 범위 밖으로 밀어내는 것이 가장 좋다.
캐시 또한 메모리 누수를 일으키는 주범이다.
-> WeakHashMap,LinkedHashMap. removeEldestEntity를 권장한다.
자바에서는 2가지 객체 소멸자를 제공한다. 첫번째 finalizer는 예측할수 없고 상황에 따라서 위험할수 있다.
두번째 cleaner -> Deprecated된 finalizer의 대안으로 등장하여 덜 위험하지만 여전히 예측할 수 없다.
사용해야 할때
clone 메소드를 호출하지 않는거에 대한 안전망 역할을 한다 (FileOutputStream, ThreadPollExecutor)
네이티브 자바는 가비지 컬랙터가 회수하지 못한다. 그 대안으로 사용된다. (물론 성능 저하)
그냥 사용하지 말자
//생략
BufferedReader br = new BufferedReader(new FileReader(path));
try {
return br.readLine();
} finally{
br.close();
}
//생략
//생략
try(BufferedReader br = new BufferedReader(new FileReader(path))) {
return br.readLine();
} finally{
br.close();
}
//생략
BufferedReader br = new BufferedReader(new FileReader(path));
BufferedReader br2 = new BufferedReader(new FileReader(path));
V
try(br;br2) {
return br.readLine() + br2.readLine();
} finally{
br.close();
br2.close();
}