전체 글 194

[Effective Java] Item 17. 변경 가능성을 최소화하라

[Effective Java] Item 17. 변경 가능성을 최소화하라 불변 클래스 인스턴스의 내부 값을 수정할 수 없는 클래스 불변 인스턴스에 간직된 정보는 고정되어 객체가 파괴되는 순간까지 절대 달라지지 않는다. 불변 클래스는 가변 클래스보다 설계하고 구현하고 사용하기 쉬우며, 오류가 생길 여지도 적고 훨씬 안전하다. 예) String, 기본 타입의 박싱된 클래스들, BigInteger, BigDecimal 불변 클래스로 만들기 위한 다섯 가지 규칙 객체의 상태를 변경하는 메서드(변경자)를 제공하지 않는다. 클래스를 확장할 수 없도록 한다. 하위 클래스에서 부주의하게 혹은 나쁜 의도로 객체의 상태를 변하게 만드는 사태를 막아준다. 상속을 막는 대표적인 방법은 클래스를 final로 선언하는 것이지만, ..

[Effective Java] Item 16. public 클래스에서는 public 필드가 아닌 접근자 메서드를 사용하라

[Effective Java] Item 16. public 클래스에서는 public 필드가 아닌 접근자 메서드를 사용하라 이따금 인스턴스 필드들을 모아놓는 일 외에는 아무 목적도 없는 퇴보한 클래스를 작성하려 할 때가 있다. 이처럼 퇴보한 클래스는 public 이어서는 안된다! public double x; public double y; 이런 클래스는 데이터 필드에 직접 접근할 수 있으니 캡슐화의 이점을 제공하지 못한다. API 수정하지 않고는 내부 표현을 바꿀 수 없고, 불변식을 보장할 수 없으며, 외부에서 필드에 접근할 때 부수 작업을 수행할 수도 없다. 철저한 객체 지향 프로그래머는 이런 클래스를 상당히 싫어해서 필드를 모두 private으로 바꾸고 public 접근자 (getter)를 추가한다. ..

[Effective Java] Item 15. 클래스와 멤버의 접근 권한을 최소화하라

[Effective Java] Item 15. 클래스와 멤버의 접근 권한을 최소화하라 어설프게 설계된 컴포넌트와 잘 설계된 컴포넌트의 가장 큰 차이는 바로 클래스 내부 데이터와 내부 구현 정보를 외부 컴포넌트로부터 얼마나 잘 숨겼느냐다. 잘 설계된 컴포넌트는 모든 내부 구현을 완벽히 숨겨, 구현과 API를 깔끔히 분리한다. 오직 API를 통해서만 다른 컴포넌트와 소통하며 서로의 내부 동작 방식에는 전혀 개의치 않는다. 정보 은닉, 혹은 캡슐화라고 하는 이 개념은 소프트웨어 설계의 근간이 되는 원리다. 정보 은닉의 장점은 많다. 그중 대부부는 시스템을 구성하는 컴포넌트들을 서로 독립시켜서 개발, 테스트, 최적화, 적용, 분석, 수정을 개별적으로 할 수 있게 해주는 것과 연관이 있다. 정보 은닉의 장점을 구..

[Effective Java] Item 14. Comparable을 구현할지 고려하라

[Effective Java] Item 14. Comparable을 구현할지 고려하라 이번에는 Comparable 인터페이스의 유일무이 한 메서드인 comapreTo를 알아보자. 그렇다! 이번 장에서 다룬 다른 메서드들과 달리 compareTo는 Object의 메서드가 아니다. 성격은 두 가지만 빼면 Object의 equals와 같다. 그렇다면 무엇이 다른가? compareTo는 단순 동치성 비교에 더해 순서까지 비교할 수 있으며, 제네릭하다. Comparable을 구현했다는 것은 그 클래스의 인스턴스들에게는 자연적인 순서(natual order)가 있음을 뜻한다. 그래서 Compareble을 구현한 객체들의 배열은 다음처럼 손쉽게 정렬할 수 있다. Arrays.sort(a); 검색, 극단값 계산, 자동..

[Effective Java] Item 13. clone 재정의는 주의해서 진행하라

[Effective Java] Item 13. clone 재정의는 주의해서 진행하라 Cloneable은 복제해도 되는 클래스임을 명시하는 용도의 믹스인 인터페이스(아이템 20)지만, 아쉽게도 의도한 목적을 제대로 이루지 못했다. 믹스인 인터페이스: 객체 지향 프로그래밍 언어에서 믹스인(mixin 또는 mix-in)은 다른 클래스의 부모 클래스가 되지 않으면서 다른 클래스에서 사용할 수 있는 메서드를 포함하는 클래스 가장 큰 문제는 clone 메서드가 선언된 곳이 Cloneable이 아닌 Object이고, 이마저도 protected라는 데 있다. 그래서 Cloneable을 구현하는 것만으로는 외부 객체에서 clone 메서드를 호출할 수 없다. 리플렉션(아이템 65)을 사용하면 가능하지만, 100% 성공하는..

[Effective Java] Item 12. toString을 항상 재정의하라

[Effective Java] Item 12. toString을 항상 재정의하라 Object의 기본 toString 메서드가 우리가 작성한 클래스에 적합한 문자열을 반환하는 경우는 거의 없다. 이 메서드는 PhoneNumber@adbbd처럼 단순히 클래스_이름@16진수로_표현한_해시코드를 반환할 뿐이다. toString의 일반 규약에 따르면 '간결하면서 사람이 읽기 쉬운 형태의 유익한 정보'를 반환해야 한다. PhoneNumber@adbbd는 간결하고 읽기 쉽다고 볼 수도 있지만, 707-867-5309처럼 전화번호를 직접 알려주는 형태가 훨씬 유익한 정보를 담고 있다. 또한 toString의 규약은 "모든 하위 클래스에서 이 메서드를 재정의하라"고 한다. 정말 새겨들어야 할 조언이다! e..

[Effective Java] Item 11. equals를 재정의하려거든 hashCode도 재정의하라.

[Effective Java] Item 11. equals를 재정의하려거든 hashCode도 재정의하라. equals를 재정의한 클래스 모두에서 hashCode도 재정의해야 한다. 그렇지 않으면 hashCode 일반 규약을 어기게 되어 해당 클래스의 인스턴스를 HashMap이나 HashSet 같은 컬렉션의 원소로 사용할 때 문제를 일으킬 것이다. 다음은 Object 명세에서 발췌한 규약이다. equals 비교에 사용되는 정보가 변경되지 않았다면, 애플리케이션이 실행되는 동안 그 객체의 hashCode 메서드를 몇 번을 호출해도 일관되게 항상 같은 값을 반환해야 한다. 단, 어플리케이션을 다시 시작한다면 이 값이 달라져도 상관없다. equals(Object)가 두 객체를 같다고 판단했다면, 두 객체의 ha..

[Effective Java] Item 10. equals는 일반 규약을 지켜 재정의하라

[Effective Java] Item 10. equals는 일반 규약을 지켜 재정의하라 equals 메서드는 재정의하기 쉬워 보이지만 곳곳에 함정이 도사리고 있어서 자칫하면 끔찍한 결과를 초래한다. 문제를 회피하는 가장 쉬운 길은 아예 재정의하지 않는 것이다. 그냥 두면 그 클래스의 인스턴스는 오직 자기 자신과만 같게 된다. 그러니 다음에서 열거한 상황 중 하나에 해당한다면 재정의하지 않는 것이 최선이다. equals를 재정의 하지 않아야 하는 경우 각 인스턴스가 본질적이고 고유하다. 값을 표현하는 게 아니라 동작하는 개체를 표현하는 클래스가 여기 해당한다. Thread가 좋은 예로, Object의 equals 메서드는 이러한 클래스에 딱 맞게 구현되었다. 인스턴스의 '논리적 동치성(logical eq..

[Effective Java] Item 9. try-finally보다는 try-with-resources를 사용하라

[Effective Java] Item 9. try-finally보다는 try-with-resources를 사용하라 자바 라이브러리에는 close 메서드를 호출해 직접 닫아줘야 하는 자원이 많다. InputStream, OutputStream, java.sql.Connection 등이 좋은 예다. 자원 닫기는 클라이언트가 놓치기 쉬워서 예측할 수 없는 성능 문제로 이어지기도 한다. 이런 자원 중 상당수가 안전망으로 finalizer를 사용하고 있지만 finalizer는 그리 믿을만하지 못하다. 전통적으로 자원이 제대로 닫힘을 보장하는 수단으로 try-finally가 쓰였다. 예외가 발생하거나 메서드에서 반환되는 경우를 포함해서 말이다. try-finally (더 이상 자원을 회수하는 최선의 방책이 아님)..

[Effective Java] Item 8. finalizer와 cleaner 사용을 피하라

[Effective Java] Item 8. finalizer와 cleaner 사용을 피하라 자바의 두 가지 객체 소멸자 finalizer 예측할 수 없고 상황에 따라 위험할 수 있어서 일반적으로 불필요함. 오작동, 낮은 성능, 이식성 문제의 원인이 되기도 함. Java 9부터 deprecated API로 지정되어 cleaner를 대안으로 사용. cleaner finalized 보다는 덜 위험하지만 여전히 예측할 수 없고, 느리고, 일반적으로 불필요함 finalizer 사용 예시 (Java 8 ThreadPoolExecutor) public class ThreadPoolExecutor extends AbstractExecutorService { ... /** * Invokes {@code shutdown..