본문 바로가기

Effective Java

(40)
4-3) 변경 가능성을 최소화하라 불변 클래스 불변 클래스란 인스턴스 내부 값을 수정할 수 없는 클래스를 말한다. Java에서는 String, BigInteger, BigDecimal 등 여러 클래스가 불변 클래스로 설계되었다. 불변 클래스 방식은 설계 및 구현이 쉽고 사용하기에도 쉽다. 또 오류가 생길 여지도 적어서 훨씬 안전하다. 이러한 장점을 가진 불변 클래스를 만들기 위해서는 다음 다섯가지 규칙을 따르면 된다. 1. 객체의 상태를 변경하는 메소드를 제공하지 않는다. 2. 클래스를 확장할 수 없도록 한다. 3. 모든 필드를 final로 선언한다. 4. 모든 필드를 private로 선언한다. 5. 자신 외에는 내부의 가변 컴포넌트에 접근할 수 없도록 한다. 불변 복소수 클래스 public final class Complex { pri..
4-2) public 클래스에서는 public 필드가 아닌 접근자 메소드를 사용하라 접근자 메소드 // Point 클래스의 x, y 값은 아무곳에서나 접근 가능하고 // 그 결과 x, y에 대한 관리 책임은 Point가 가지고있지 않는다. class Point { public double x; public double y; } 위 Point 클래스는 x, y 좌표를 나타내는 실수형 필드를 가지고 있다. 정말 그뿐이다. 연관된 정보를 모아둔 것 이외의 역할을 하지않는 C언어 시절의 클래스이다. OOP의 철학을 따르는 Java의 개발자라면 이런 퇴보한 클래스는 만들면 안된다. Point 클래스를 만들었다면 x, y 값에 대한 책임도 함께 가지고 있는 클래스를 만들어야 한다. // x, y의 값은 Point 클래스 내부에서만 수정하기때문에 // x, y에 대한 관리책임은 Point 클래스에 ..
4-1) 클래스와 멤버의 접근 권한을 최소화하라 캡슐화(정보 은닉) 잘 만들어진 컴포넌트의 특징 중 하나는 내부 구현 내용을 외부에 잘 숨긴다는 것이다. 외부의 사용자는 내부의 구현에 신경쓰지 않고 컴포넌트를 사용한다. 이는 OOP와 소프트웨어 설계의 기본이 캡슐화(정보 은닉)와 같은 뜻이다. 캡슐화는 내부의 상태나 정보를 외부에서 접근할수 없도록 하여 감추는 것인데, 이렇게 하면 여러 장점을 얻을 수 있다. 1. 시스템 개발 속도를 높인다 > 여러 컴포넌트를 병렬로 개발 할 수 있다. 2. 시스템 관리 비용을 낮춘다 > 디버깅 하기 쉽고, 컴포넌트 교체 부담도 적다. 3. 성능 최적화에 좋다 > 내부 컴포넌트의 코드 수정이 외부 컴포넌트에 주는 영향이 적기 때문에 성능최적화 하기에 좋다. 4. 소프트웨어 재사용성을 높인다 > 캡슐화(정보은닉)을 지킨..
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..