본문 바로가기

Effective Java

(40)
2-9) try-finally 보다는 try-with-resources를 사용하라 자원 반환을 위한 try문 Java 프로그램을 만들다보면 자원을 사용하고 반환해야하는 경우가 많다. 심지어 해당 자원에 lock을 걸고 점유하며 사용한다면 반드시 사용 이후에 lock을 풀고 자원을 반환해야 한다. 이를 위해서 InputStream, OutStream의 경우 close() 메소드로 자원을 반환하도록 한다. InputStream is = new FileInputStream("temp.txt"); ... is 사용하는 코드들 ... is.close(); 위의 코드는 temp.txt 파일을 읽어들이는 InputStream을 만들고 사용한 후에 close() 메소드를 호출한다. 이렇게하면 is가 사용된 이후 자원을 반환할 수 있다. 정말일까? is 사용하는 중간 코드에서 Exception이 발생..
2-8) finalizer와 cleaner 사용을 피하라 객체 소멸자 class MyObject { // 생성자 MyObject(){ } // 소멸자 ~MyObject(){ } } // 메모리 할당 MyObject my_obj = new MyObject(); ... // 메모리 해제 > 소멸자 호출됨 delete my_obj; C++은 객체 생성시에 실행되는 생성자와 객체 소멸시에 실행되는 소멸자가 있다. delete 키워드로 객체를 소멸시키면 소멸자가 호출된다. 소멸자는 객체가 사용하던 자원을 정리하는데 쓰인다. 생성자에서 "temp.txt" 파일의 읽기/쓰기 스트림을 열었다면, 소멸자에서 스트림을 닫는 동작을 수행한다. Java에도 이런 역할을 하는 finalizer와 cleaner가 있다. finalizer와 cleaner C++에서 소멸자는 좋은 코드를..
2-7) 다 쓴 객체 참조를 해제하라 메모리 할당과 해제 int * int_array = new int[10]; c++ 에서는 new 키워드를 통해, 메모리를 할당 할 수 있다. 위의 코드에서는 길이 10의 int형 배열을 위한 메모리 공간을 new 키워드로 할당하고 그 메모리 주소를 int_array 변수에 할당하였다. int * makeIntArray(){ int * int_array = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; return int_array; } // 에러 또는 잘못된 값에 접근 int * int_array = makeIntArray(); int num1 = int_array[0]; 그렇다면 굳이 new를 사용하여 메모리를 할당해야 하는 이유는 무엇일까? 그것은 바로 new를 사용해야 프로그램의 runt..
2-6) 불필요한 객체 생성을 피하라 불필요한 객체 생성 같은 내용을 가지는 객체를 여러개 생성하는 것은 메모리상의 낭비를 가져온다. 현재는 같은 속성 값을 가지고 있지만 추후 달라질 수 있는 객체라면 필요에 따라서 객체를 중복 생성할 수 있다. 하지만 그것이 아니라면 불필요한 객체 생성을 피하고 하나의 객체를 재사용하는 것이 옳다. // 지금은 같아 보일지라도 개명할 수 있으니, 객체를 각자 생성한다. String name1 = new String("이기수"); String name2 = new String("이기수"); // 한국은 언제나 한국이다, 객채를 재사용하는것이 옳다. String born_country = new String("한국"); String cur_country = new String("한국"); // 메소드가 호출될..
2-5) 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 클래스와 의존성 일반적으로 클래스는 기능을 수행하기위해 내부적으로 다른 클래스를 사용한다. 이렇게 한 클래스가 다른 클래스를 필요로 하는 것을 의존성이 있다고 한다. 프로그램의 규모가 커질수록 이러한 의존성은 더욱 복잡해진다. 맞춤법 검사 클래스인 SpellChecker가 있다고 하면 내부적으로 맞춤법 검사를 위한 사전 클래스인 Dictionary 클래스를 가지고 있을것이다. 이 때 SpellChecker 클래스는 Dictionary 클래스에 의존성이 있다고 한다. class SpellChecker { private Dictionary dic; ... } 의존성 주입 // 유연하지 않고 테스트하기 어렵다 class SpellChecker { private Dictionary dic = new MyDict..
2-4) 인스턴스화를 막으려거든 private 생성자를 사용하라 인스턴스화를 막는 이유 정적 필드와 정적 메소드만으로 구성된 클래스를 만드는 경우가 있다. 예를 들어 java.util.Arrays의 배열을 위한 상수를 정적 필드로 가지고 있고, 배열관련 메소드를 정적 메소드로 가지고 있다. 이러한 성격의 클래스는 인스턴스화를 막는게 일반적이다. 인스턴스를 만든다는 것은 객체마다 다른 속성값을 가지고 있을 때 의미가 있다. 정적 필드와 메소드로만 구성된 클래스는 객체를 만드는것이 의미가 없다. 심지어 메모리상 낭비를 가져온다. 따라서 정적인 방식으로 만들어진 클래스는 인스턴스화를 막는것이 옳다. private 생성자 public class Arrays { ... private Arrays() {} ... } 정적 방식으로 만들어진 java.util.Arrays 클래스는..
2-3) private 생성자나 열거 타입(enum)으로 싱글톤을 보장하라 싱글톤 패턴 MyClass myClass1 = ... MyClass myClass2 = ... // true System.out.println(myClass1 == myClass2); 싱글톤 패턴은 클래스가 오로지 하나의 인스턴스를 만들 수 있도록 하는 패턴이다. 무상태 객체나 필요에 의해 시스템에 하나의 객체만 존재해야하는 경우 싱글톤 패턴을 사용한다. 싱글톤 패턴을 구현하는 방식은 크게 3가지가 존재한다. public static final 필드 방식의 싱글톤 public class Elvis { public static final Elvis INSTANCE = new Elvis(); private Elvis() { } public void leaveTheBuilding() { System.out.p..
2-1) 생성자 대신 정적 팩토리 메소드를 고려하라. 생성자(new) 대신 정적 팩토리 메소드 (Static Factory Method) 생성자(new)는 JAVA의 가장 기본적인 문법이고 클래스의 인스턴스를 만들 때 일반적으로 생성자를 사용한다. 하지만 개발자는 클래스에 별도의 정적 팩토리 메소드 (Static Factory Method)를 제공할 수 있다. 클래스의 인스턴스를 반환하는 정적 팩토리 메소드를 제공하면 생성자 대신 사용할 수 있다. public class MyClass { // 생성자를 통한 인스턴스 생성 public MyClass() {} // 정적 팩토리 메소드를 통한 인스턴스 생성 public static MyClass getInstance() { return new MyClass(); } } 간단한 예제 코드를 보면, MyClass는..