본문 바로가기

STUDY

(102)
3-5) Comparable을 구현할지 고려하라 Comparable 인터페이스, compareTo 메소드 public class Customer implements Comparable { private int customerId; ... @Override public int compareTo(Customer o) { return Integer.compare(this.customerId, o.customerId); } ... } // customerList가 customerId 기준으로 정렬된다. Arrays.sort(customerList); Comparable 인터페이스는 compareTo 메소드를 가지고있다. compareTo 메소드는 두 객체를 비교하고 그 결과를 반환한다. 얼핏 equals 메소드와 비슷해 보일 수 있지만, equals는 두 객..
3-4) clone 재정의는 주의해서 진행하라 clone 메소드와 Cloneable 인터페이스 public class MyClass{ ... } // 컴파일 에러, clone 메소드를 찾을 수 없다. myClass.clone(); public class MyClass{ ... public MyClass clone() throws CloneNotSupportedException { return super.clone(); } ... } // 런타임 에러, CloneNotSupportedException 발생 myClass.clone(); public class MyClass implements Cloneable{ ... public MyClass clone() throws CloneNotSupportedException { return super.clo..
3-3) toString을 재정의 하라 toString log.info("고객 객체 반환: {}", customer); toString은 무시하기 쉬우나 생각보다 자주 사용되는 공통 메소드이다. API를 호출할 때 사용자에게 보여주는 반환값을 toString을 사용하여 보여줄 수 있고, 로그를 출력할 때 toString이 사용될 수 있다. 하지만 기본 Object의 toString은 "클래스명@해시코드값"으로 되어있어서 일반적인 기대값과는 다르다. 따라서 클래스를 만들 때 기대에 맞는 toString을 재정의하고 그 포맷을 사용자가 알 수 있도록 알려주어야 한다. toString을 잘 정의한 사례 일자를 표현하는 클래스인 LocalDate가 toString을 잘 재정의한 사례이다. 먼저 일자의 핵심정보인 년/월/일이 모두 출력된다. 그리고 메..
3-2) equals를 재정의 하려면 hashCode도 재정의하라 hashCode equals 처럼 hashCode도 Object 클래스부터 정의되어있는 공통 메소드이다. hashCode는 일반적으로 객체를 비교하기 전에 간략히 비교할 대상을 걸러내는 용도로 사용된다. hashCode역시 공통 메소드로서 지켜야하는 공통 규약이 존재한다. 1. equals에 사용되는 정보가 변경되지 않는다면, hashCode의 값도 일정해야 한다. 2. equals 비교 결과 true인 두 객체는 hashCode의 값도 같아야 한다. 3. equals 비교 결과 false인 두 객체의 hashCode 값이 꼭 달라야 하는건 아니다. hashCode의 역할 public class Customer { private String customerId; public Customer(String ..
3-1) equals는 일반 규약을 지켜서 재정의하라 equals 재정의 equals는 객체의 동일성을 비교하는 공통 메소드이다. 개발자는 필요에 따라서 자신이 개발한 클래스의 equals 메소드를 재정의 할 수 있다. 하지만 equals 메소드를 재정의할 경우 예기치 못한 문제가 생길 수 있다. 그렇기 때문에 아래의 경우 중 하나라도 해당된다면 메소드 재정의를 하지 않는 것이 옳다. 1. 각 인스턴스가 본질적으로 고유하다. // Thread 인스턴스는 고유하기 때문에 thread1, thread2는 당연히 다르다. Thread thread1 = new Thread(); Thread thread2 = new Thread(); // Customer 인스터스는 고객번호가 존재하고 customer1, customer2는 논리적으로 동일하다. Customer cu..
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..