개발이야기/Effective Java 15

[Effective Java]가능하면 제네릭 자료형으로 만들 것

컬렉션 객체 선언을 제네릭화 하거나, JDK가 제공하는 제네릭 자료형과 메서드를 사용하는 것은 일반적으로 어렵지 않다. 그러나 제네릭 자료형을 직접만드는 것은 어렵지만 그래도 배워둘만한 가치가 있다. 1. 제네릭을 사용하지 않고 Object class를 활용하여 만든 Stack class12345678910111213141516171819public class Stack { private Object[] elements; private int size = 0; private static final int DEFAULT_INITIAL_CAPACITY = 16; public Stack() { elements = new Object[DEFAULT_INITIAL_CAPACITY]; } public void pu..

[Effective Java]무점검 경고(unchecked warning)를 제거하라

제네릭으로 프로그램하다보면 많은 컴파일러 경고메시지를 보게 된다. 아래가 그러한 경고이다. 무점검 형변환 경고(unchecked cast warning)무점검 메서드 호출 경고(unchecked method invocation warning)무점검 제네릭 배열 생성 경고(unchecked generic array creation warning)무점검 변환 경고(unchecked conversion warning)etc...제네릭에 대한 경험이 많고 코드에 대한 경험이 많다면 경고메시지가 줄어들지만 아직도 많은 제네릭 코드들이 경고메시지를 날리고 있다. 이러한 경고메시지를 제거하기 위해서 @SupressWarnings("unchecked") 어노테이션(annotation)을 사용해 억제한다. 하지만 @Su..

[Effective Java]자료형을 정의할 때 표식 인터페이스를 사용하라

마커 인터페이스 혹은 표식 인터페이스(marker interface)는 아무 메서드도 선언하지 않는 인터페이스이다.(자세한 내용 참조 블로그) (Ex. Cloneable, serializable,Eventlistener,Remote,RandomAccess,EnterpriseBean 등) 표식 어노테이션 vs 표식 인터페이스표식 인터페이스는 표식이 붙은 클래스가 만드는 객체들이 구현하는 자료형이라는점, 표식 어노테이션은 자료형이 아니다.표식 인터페이스는 적용 범위를 좀더 세밀하게 지정할 수 있기 때문에 표식 어노테이션보다 낫다. 그럼 어떤 상황에서 표식 어노테이션과 표식 인터페이스를 선택해서 사용해야 하나?클래스나 인터페이스 이외의 프로그램 요소에 적용되어야 하는 표식은 어노테이션으로 만들어야 한다.표식을..

[Effective Java]Override 어노테이션은 일관되게 사용하라

어노테이션을 일관되게 사용하면 끔찍한 human error로 인한 버그들을 방지 할 수 있다. 123456789101112131415161718192021222324252627public class Bigram { private final char first; private final char second; public Bigram(char first, char second){ this.first = first; this.second = second; } public boolean equals(Bigram b){ return b.first == first && b.second == second; } public int hashCode(){ return 31 * first + second; } public..

[Effective Java]작명 패턴 대신 어노테이션을 사용하라

Java 1.5 이전에는 annotation이 존재하지 않았다. 그래서 이전에는 도구 or 프레임워크를 특별 취급하기 위해서 Java 1.5 이전에는 작명 패턴을 사용(ex. JUnit 테스트 이름을 test로 시작하는 것)했다. 그러나 이 방법을 사용하면 이름을 잘못 입력하면 문제가 발생하거나 무시해버리는 오류가 생기며, parameter을 전달할 방법이 없었음. 이를 해결하기 위해 Java 1.5에서는 annotation이 등장 했다.JAVA API Annotation 자료형 보러가기(클릭) Annotation 종류@Override - 해당 메소드가 부모 클래스에 있는 메소드를 오버라이드 했다는 것을 명시적으로 선언@Deprecated - 더이상 사용되지 않은 클래스나 메소드 앞에 추가@Suppres..

[Effective Java]int 상수 대신 enum을 사용하라

JAVA API Enum 자료형 보러가기(클릭) Java enum의 특징 1. enum은 가독성이 좋고 안전하며 강력함2. enum안에 데이터 또는 그 데이터에 관계된 메서드를 추가해 기능을 향상시킨 enum으로 만들 수 있음 3. C/C++/C# 언어의 enum(단순 int 값)과는 다르게 Java에서는 참조 자료형으로 사용한4. toString 메서드를 호출하여 문자열로 쉽게 변경 가능5. Object 메서드 사용가능6. Comparable, Serializable 인터페이스가 구현되어 있음 End of Document

[Effective Java]예외를 무시하지 마라

어떤 메서드에 대해 예외가 발생할 수 있다고 선언했다면, 그것은 API를 이용할 프로그래머에게 무언가를 알리려는 것이다. 무시하면 안된다. 아래와 같은 코드로 손쉽게 무시 할 수도 있다. 위와 같은 코드처럼 무시할 수도 있지만 매우 의심스럽고 가독성도 떨어지고 이유를 알기가 어렵다. catch블록안에 적절한 코드가 없다면 적어도 catch 블록 안에는 예외를 무시해도 괜찮은 이유라도 주석으로 남겨두기라도 해야만 한다. End of Document.

[Effective Java]실패 원자성 달성을 위해 노력하라

예외를 던지고 난 뒤에도 객체는 상태가 이전 상태와 동일하며 사용가능한 형태로 남아있어야 한다. 특히 checked exception의 경우 그렇다. 위와 같은 코드 처럼 빈 스택에서 뭔가 뽑아내려고 할때 먼저 상황을 체크하고 exception을 throw하여 실패 원자성(failure atomicity)을 갖춘 코드라 볼수 있다. 방법은 크게 두가지가 있다. 1. exception이 났을 때 roll back될수 있도록 코드를 구성한다.2. 실패할 가능성이 있는 코드를 전부 객체 상태를 바꾸는 코드앞에 배치한다. 이러한 실패 원자성은 권장하지만 가은 객체를 여러 스레드가 동기화 없이 접근하는 것과 같은 특수한 경우에는 객체 상태의 일관성이 깨질 가능성이 있다. 또한 실패 원자성을 달성하기 위해 코드의 ..

[Effective Java]어떤 오류인지를 드러내는 정보를 상세한 메시지에 담으라

런타임에서 catch하는 unchecked exception에서 프로그램이 죽으면 시스템은 자동으로 해당 예외의 스택 추적 정보(stack trace)를 출력한다. 스택 추적정보는 예외 객체의 클래스명 뒤에 상세 메시지가 오는 형태로 구성되어 있다. 그러므로 오류 정보를 쉽고 빠르게 포착해 내기 위해서는, 오류의 상세메시지에 "예외에 관계된" 모든 인자와 필드의 값을 포함시켜서 stack trace에서 볼 수 있도록 한다. 위와 같은 상세 메시지를 사용하게 되면 최종 사용자(프로그래머, 서비스 담당자)가 오류 원인을 분석하여 이해 할 수 있게 된다. 최종 사용자가 오류 원인을 분석하기 위해서는 가독성보다 내용이 훨씬 중요하기 때문일 것이다. End of Document

[Effective Java]메서드에서 던져지는 모든 예외에 대해 문서를 남겨라

메서드를 올바르게 사용하려면, 메서드에서 던져지는 예외에 대한 설명이 문서에 있어야 한다. 따라서 문서화는 아주 중요하다.(당연한 이야기) 1. Javadoc @throws 태그를 사용해서 정확하게 밝히기2. 같은 이유로 동일한 예외를 던지는 메서드가 많으면 메서드마다 문서를 만들지말고, 예외에 대한 문서를 클래스의 문서화 주석(documentation comment)에 남기자. 단순하지만 명확한 결론 결론 : 메서드가 던질 가능성이 있는 모든 예외를 문서로 남기자

[Effective Java]표준 예외를 사용하라

자바 플랫폼 라이블러리에는 대부분의 API가 필요로 하는 기본적인 unchecked exception들이 갖추어져 있다. 이미 있는 예외들은 재사용하면 아래와 같은 좋은 점이 있다. 1. 배우기 쉽고 사용하기 편리한 API를 만들 수 있다.2. 표준 예외를 사용한 API는 가독성이 높다.3. 예외 클래스 개수를 줄이면 프로그램의 메모리 요구량이 줄어들고, 클래스를 로딩하는 시간도 줄어든다.(확인 불가..) 아래는 가장 널리 재사용 되는 예외를 정리한 표이다. 예외 사용법 IllegalArgumentException null이 아닌 인자의 값이 잘못되었을 때 IllegalStateException 객체 상태가 메서드 호출을 처리하기에 적절치 않을 때 NullPointException null 값을 받으면 ..

[Effective Java]불필요한 점검지정 예외 사용은 피하라

자바에는 exception이라는 훌륭한 기능을 제공한다. 그중 두가지 exception 종류는 아래와 같은 표로 정리 할 수 있다. checked exception unchecked exception 처리여부 반드시 처리 명시적으로 처리 안해도 됨 확인시점 컴파일 런타임 대표예외 exception의 상속받는 하위 클래스 중 Runtime exception을 제외한 모든 예외 runtime exception 하위 예외 이 중 checked exception을 너무 많이 남발하게 되면 불편하므로 checked exception을 던지지 않는 소스로 리펙토링 하는 것도 좋은 방법이다. 위와 같이 file input output 소스가 있다고 한다면 아래와 같이도 바꿀 수 있을 것이다. 항상 이렇게 리펙토링 가..

[Effective Java]예외는 예외적 상황에만 사용하라

아래와 같은 코드를 써서 반복구문(loop)를 돌리는 개발자는 없다.(없어야만 한다) 문제점이 뭐냐? 크게 3가지로 볼 수 있다.(라고 책에 나와있다.) 1. 예외는 예외적 상황을 위해 설계된 것이므로 JVM수준에서 보면 빠르게 만들 필요가 없다.2. try-catch 블록안의 코드는 최신JVM의 최적화 기법 중 일부분이 적용되지 않는다.3. array 내부의 중복 검사가 이루어지지 않는다. 그런데 위 내용에서 추가적으로 책에서 설명한 부분이 있다. "사실 최신 JVM에서 돌려보면 예외를 통해 구현한 순환문이 표준적 순환문 보다 훨씬 느리다. 필자의 컴퓨터에서는, 100개 원소를 갖는 배열일 때 두 배 이상 느렸다." 라는 글을 보고 직접 실험해보기로 하였다. 1. for loop 2. try-catch..

[Effective Java]생성자 인자가 많을 때는 Builder 패턴 적용을 고려하라.

규칙 2 생성자 인자가 많을 때는 Builder 패턴 적용을 고려하라. Builder pattern은 객체에서 생성자에 들어갈 파라미터가 많든 적든 차례차례 파라미터를 받아들이고 모든 파라미터를 받은 뒤에 이 변수들을 통합해서 한번에 사용을 할 수 있다. 사진. 고도화된 빌더패턴 안드로이드에서도 이 패턴을 유용하게 많이 사용했는데, 이게 어떻게 이루어지고 사용을 했는지 몰랐다. AlertDialog가 그 예이다. 아래는 AlertDialog의 예시이다. 안드로이드를 하다보면 이 패턴을 자주보게 된다. AlertDialog 뿐만아니라 Uri, Geofence 등등 해당 패턴을 많이 사용하고 있다는 것을 알 수 있었다. 기존에는 오버로딩(Overloading)을 활용하여 객체를 생성했으나 이는 어떤 파라미터..