JAVA
[이팩티브 자바]아이템 8. 완벽 공략 Finalizer/ AutoCloseable
dev22
2023. 3. 7. 15:44
728x90
Finalizer 공격
import java.math. BigDecimal;
public class Account {
private String accountId;
public Account(String accountId){
this.accountId = accountId;
if(accountId.equals("푸틴")){
throw new IllegalArgumentException("푸틴은 계정을 막습니다.");
//finalizer를 통해 보낼 수 있다
}
}
public void transfer(BigDecimal amount, String to){
System.out.printf("transfer %f from %s to %s\n", amount, accountId, to);
}
}
public class BrokenAccount extends Account{
public BrokenAccount(String accountId){
super(accountId);
}
@Override
protected void finalize() throws Throwable{
this.transfer(BigDecimal.valueOf(100), "keesun");
}
}
- 테스트 코드
- 방어하는 방법
- final 클래스로 만들거나
- finalizer() 메소드를 오버라이딩 한 다음 final을 붙여서 하위 클래스에서 오버라이딩 할 수 없도록 막는다.
class AccountTest{
@Test
void 일반_계정(){
Account account = new Account("keesun");
account.transfer(BigDecimal.valueOf(10,4), "hello");
}
@Test
void 푸틴_계정() throws InterruptedException{
Account account = null;
try{
account = new BrokenAccount("푸틴");
}catch(Exception exception){
System.out.println("이러면??");
}
System.gc();
Thread.sleep(3000L);
}
}
import java.math. BigDecimal;
public final class Account { //상속을 할 필요가 없으면 final로 막을 수 있다.
private String accountId;
public Account(String accountId){
this.accountId = accountId;
if(accountId.equals("푸틴")){
throw new IllegalArgumentException("푸틴은 계정을 막습니다.");
//finalizer를 통해 보낼 수 있다
}
}
public void transfer(BigDecimal amount, String to){
System.out.printf("transfer %f from %s to %s\n", amount, accountId, to);
}
}
import java.math. BigDecimal;
public class Account { //상속을 해야 한다면 메소드에 final을 붙인다.
private String accountId;
public Account(String accountId){
this.accountId = accountId;
if(accountId.equals("푸틴")){
throw new IllegalArgumentException("푸틴은 계정을 막습니다.");
//finalizer를 통해 보낼 수 있다
}
}
public void transfer(BigDecimal amount, String to){
System.out.printf("transfer %f from %s to %s\n", amount, accountId, to);
}
@Override
protected final void finalize() throws Throwable{}
}
AutoClosable
@author josh Bloch // 교재의 지은이이다.
@since1.7
public interface AutoCloseable{
void close() throws Exception;
}
인터페이스를 쓰면 main에서 finaly 블럭을 안써도 된다.
import java.io.*;
public class AutoClosableIsGood implements AutoCloseable{
private BufferedReader reader;
public AutoClosableIsGood(String path){
try{
this.reader = new BufferedReader(new FileReader(path));
}catch(FileNotFoundException e){
throw new IllegalArgumentException(path);
}
}
@Override
public void close() throws IOException {
reader.close();
}
}
import java.io.IOException;
public class App{
public static void main(String[] args){
try(AutoCloseableIsGood good = new AutoCloseableIsGood("")){
//TODO 자원 반납 처리가 됨.
}catch(IOException e){
e.printStackTrace();
}
}
}
import java.io.*;
public class AutoClosableIsGood implements AutoCloseable{
private BufferedReader reader;
public AutoClosableIsGood(String path){
try{
this.reader = new BufferedReader(new FileReader(path));
}catch(FileNotFoundException e){
throw new IllegalArgumentException(path);
}
}
@Override
public void close() { //던지지 않고 잡으면 굳이 클라이언트 코드에서 잡을 필요가 없다.
try{
reader.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
import java.io.*;
public class AutoClosableIsGood implements AutoCloseable{
private BufferedReader reader;
public AutoClosableIsGood(String path){
try{
this.reader = new BufferedReader(new FileReader(path));
}catch(FileNotFoundException e){
throw new IllegalArgumentException(path);
}
}
@Override
public void close() { //던지지 않고 잡으면 굳이 클라이언트 코드에서 잡을 필요가 없다.
try{
reader.close();
}catch(IOException e){
throw new RuntimeException(e);
}
}
}
읽고 쓰거나 하면 Closeable을 쓰는 게 좋은 선택이 될 수도 있다. -->더 많은 규약이 있다.