목요일, 3월 28
Shadow

JAVA

자바의 설명

#013 예외(Exceptions)

JAVA
이 장에서는 효과적으로 예외를 사용하는 지침을 제공한다. 예외 상황에서만 예외를 사용하자 / 예외의 터무니 없는 사용. 절대 이렇게 하지 말자! try { int i = 0; while(true) range[i++].climb(); } catch(ArrayIndexOutOfBoundsException e) { } 위의 코드는 예외를 이용하여 while 루프문을 종료시키고 있다. 배열의 범위를 벗어나는 최초의 배열 요소를 사용하려는 순간, ArrayIndexOutOfBoundsException 예외가 발생하고(throw), 검출되고(catch), 무시되면서 이 무한 루프는 종료된다. 이런 식의 코드는 본래의 목적을 혼란스럽게 하고 성능을 저하시키며, 코드가 제대로 동작하는 것을 보장하지 못한다. 코드의 취지와 무관한 버그가 생겨 우리도 모르는 사이에 루프 실행이 실패하고 버그를 감추게 되어 디버깅이 무척 복잡해진다. 예외는 예외적인 상황에서 사용하기 위해 설계된 것이니, 정상적인 흐름 제어에 예외를 사용하지 말자. 복구 가능 상황에는 checked 예외를 사용하고 런타임 예외는 프로그램 에러에 사용하자 자바에서는 던질 수 있는(throwable) 세 종류의 예외를 제공한다. 1. checked 예외 명시적으로 try-catch-finally 예외 처리를 해야하는 것 2. runtime 예외 JVM이 정상적으로 작동하는 동안에 발생하는 예외 3. error 프로그램이 catch 해서는 안되는 심각한 문...

#012 메소드(method)

JAVA
이 장에서는 매개 변수와 return 값을 처리하는 방법, 메소드 시그니처(signature)를 설계하는 방법, 메소드를 문서화하는 방법에 대해서 설명한다. 매개 변수가 유효한지 검사하자 대부분의 메소드와 생성자는 자신들의 매개변수로 전달될 수 있는 값에 제한을 둔다. 예를 들면, 배열의 인덱스는 음수가 아니어야 하고 객체 참조는 null이 아니어야 한다는 것들이다. 이런 모든 제약은 명확하게 문서화해야 하며, 메소드 몸체 코드의 맨 앞에서 검사하도록 해야한다. public 메소드의 경우는 Javadoc의 @throws 태그를 사용해서 매개 변수의 값의 제약을 위반했을 때 발생되는 예외를 문서화 한다(항목 62). 일반적으로 IllegalArgumentException, IndexOutOfBoundsException, NullPointerException 예외가 될 것이다 (항목 60). // BigInteger.java 일부 발췌 /** * 그 값이 (this mod m)인 BigInteger를 반환한다. * 이 메소드는 항상 양수의 BigInteger를 반환하는 * BigInteger의 remainder 메소드와는 다르다. * * @param m은 계수(modulus)로서, 반드시 양수여야 한다. * @return this mod m * @throws ArithmeticException 만일 m이 0보다 작거나 같으면 */ public BigInteger mod(Bi...

#011 열거형(Enum)과 주석(Annotation) 두번째

JAVA
작명 패턴보다는 주석(annotation)을 사용하자 What is the Annotation? 어노테이션은 일종의 메타 정보를 컴파일러에게 제공할 수 있는 문법이다. // 나 /**/ 등으로 적는 문법은 컴파일러는 알아먹을 수 없고 사람, 정확히는 프로그래머에게 이 코드는 이러저러한 코드다…라고 정보를 주는 문법이지만 어노테이션은 컴파일러에게 메타 정보를 주는 문법이다. 물론 잘 쓴 어노테이션은 프로그래머에게도 정보를 줄 수 있다. 참고 ## 메타 정보 메타데이터 (metadata)란 데이터(data)를 위한 데이터다. 어떤 데이터 즉 구조화된 정보를 분석, 분류하고 부가적 정보를 추가하기 위해 그 데이터 뒤에 함께 따라가는 정보를 말한다. 이를테면, 디지털 카메라에서는 사진을 찍어 기록할 때마다 카메라 자체의 정보와 촬영 당시의 시간, 노출, 플래시 사용 여부, 해상도, 사진 크기 등의 사진 정보를 화상 데이터와 같이 저장하게 되어 있다. 이러한 데이터를 분석하여 이용하면 그 뒤에 사진을 적절하게 정리하거나 다시 가공할 때에 아주 유용하게 쓸 수 있는 정보가 된다. 어노테이션 문법 아마 일반적으로 제일 많이 볼 수 있는 어노테이션은 @Override 일것이다. @Override public void xxx() { ... } 어노테이션의 선언 방법부터 살펴보자. 어노테이션은 @interface 타입으로 선언하며 뒤에 이름이 온다. 만일 TODO 라는 작업이라는 메타 정보를 제공하는 어노테이션을 선언한다면, 이러한 문법이 된다. public @...

#010 열거형(Enum)과 주석(Annotation)

JAVA
자바 1.5 배포판에는 enum 타입이라는 새로운 클래스와 annotation이라는 새로운 인터페이스가 추가되었다. 이 장에서는 새로운 타입들을 잘 사용할 수 있는 방법을 설명한다. int 상수 대신 enum을 사용하자 int 상수에 비해 enum 타입은 훨씬 더 가독성이 좋고, 안전하며, 강력하다. // int enum 패턴 - 너무 빈약하다! public static final int APPLE_FUJI = 0; public static final int APPLE_PIPPIN = 1; public static final int APPLE_GRANNY_SMITH = 2; public static final int ORANGE_NAVEL = 0; public static final int ORANGE_TEMPLE = 1; public static final int ORANGE_BLOOD = 2; int enum 패턴의 단점 – 타입 안전을 보장하는 방법이나 편리하게 사용할 수 있는 방법을 제공하지 않는다. (예. 오렌지를 인자로 받는 메소드에 사과를 전달하고 오렌지와 사과를 == 연산자로 비교해도 컴파일 에러가 나지 않는다) – int enum 상수와 연관된 int 값이 변경되면 클라이언트 코드를 다시 컴파일 해야 한다. – int enum 상수를 출력 가능한 문자열로 쉽게 바꾸는 방법도 없다. public enum Apple {FUJI, PIPPIN, GRANNY_SMITH} public enum Orange {NAVEL, TEMPLE, BL...

#009 제네릭 두번째

JAVA
제네릭 메소드를 애용하자 // 원천 타입을 사용 - 바람직하지 않다! (항목 23) public static Set union(Set s1, Set s2) { // 경고 - Set is a raw type. References to generic type Set should be parameterized Set result = new HashSet(s1); // 경고 - HashSet is a raw type. References to generic type HashSet should be parameterized result.addAll(s2); // 경고 - Type safety: The method addAll(Collection) belongs to the raw type Set. References to generic type Set should be parameterized return result; } 위의 코드는 컴파일은 되지만 경고 메시지가 나온다. 이 경고 메세지를 없애고 메소드가 타입 안전하게 만들려면, 아래와 같이 코딩한다. import java.util.*; public class Union { // 제네릭 메소드 public static Set union(Set s1, Set s2) { Set result = new HashSet(s1); result.addAll(s2); return result; } // 제네릭 메소드를 사용하는 간단한 프로그램 ...

#007 클래스와 인터페이스 세번째

JAVA
자바에서는 클래스와 인터페이스를 설계하는데 사용할 수 있는 강력한 요소들을 제공한다. 이 장에서는 우리가 만드는 클래스와 인터페이스가 쓸모있고 강력하며 유연성이 있도록 하기 위해 도움을 주는 지침을 설명한다. 태그 (tagged) 클래스보다는 클래스 계층을 사용하자 태그(tagged) 클래스란 인스턴스들이 두 개 이상의 특성으로 분류되고 그런 특성을 나타내는 태그(tag) 필드를 갖는 클래스를 말한다. // Tagged class - 클래스 계층보다 매우 조악하다! class Figure { enum Shape { RECTANGLE, CIRCLE }; // Tag field - 이 도형의 형태 final Shape shape; // 이 필드는 shape가 RECTANGLE일 때만 사용된다. double length; double width; // 이 필드는 shape가 CIRCLE일 때만 사용된다. double radius; // circle 생성자 Figure(double radius) { shape = Shape.CIRCLE; this.radius = radius; } // rectangle 생성자 Figure(double length, double width) { shape = Shape.RECTANGLE; this.length = length; this.width = w...

#006 클래스와 인터페이스 두번째

JAVA
자바에서는 클래스와 인터페이스를 설계하는데 사용할 수 있는 강력한 요소들을 제공한다. 이 장에서는 우리가 만드는 클래스와 인터페이스가 쓸모있고 강력하며 유연성이 있도록 하기 위해 도움을 주는 지침을 설명한다. 가급적 상속(inheritance)보다는 컴포지션(composition)을 사용하자 상속의 문제점 동일한 프로그래머가 서브클래스와 수퍼 클래스의 구현을 관장하는 같은 패키지 내에서 상속을 사용하는 것은 안전하다. 또한 상속을 위해 특별히 설계되고 문서화된 클래스를 확정하기 위해 상속을 사용하는 것도 안전하다. 그러나 다른 패키지에 걸쳐 일반적인 실체 클래스로부터 상속을 받는 것은 위험하다. 메소드 호출과는 달리 상속은 캡슐화를 위배한다. // 상속을 잘못 사용한 예! import java.util.*; public class InstrumentedHashSet extends HashSet { // 요소를 추가한 횟수 private int addCount = 0; public InstrumentedHashSet() { } public InstrumentedHashSet(int initCap, float loadFactor) { super(initCap, loadFactor); } @Override public boolean add(E e) { addCount++; return super.add(e); } @Override p...

#005 클래스와 인터페이스

JAVA
자바에서는 클래스와 인터페이스를 설계하는데 사용할 수 있는 강력한 요소들을 제공한다. 이 장에서는 우리가 만드는 클래스와 인터페이스가 쓸모있고 강력하며 유연성이 있도록 하기 위해 도움을 주는 지침을 설명한다. 클래스와 그 멤버의 접근성을 최소화하자 잘 설계된 모듈은 외부 API 부분과 내부 구현 부분을 명쾌하게 분리하며 내부의 상세한 구현 부분 모두를 감춘다. 이 개념은 소프트웨어 설계 기본 원리 중 하나로, 정보 은닉(information hiding) 또는 캡슐화(encapsulation)라고 한다. 정보 은닉이 중요한 이유 시스템을 구성하는 모듈들 간의 결합도를 낮추어 모듈별로 개발, 테스트, 최적화, 사용 및 수정이 가능하도록 한다. 각 모듈별로 병행 개발할 수 있으므로 시스템 개발이 빨라진다. 모듈을 더 빨리 파악할 수 있다. 다른 모듈에 영향을 주지 않고 수정이 가능하므로, 유지 보수의 부담을 덜 수 있다. 정보 은닉 자체만으로 성능을 좋게 할 수 없지만 효과적인 성능 튜닝이 가능하다. (프로파일링을 통해 어떤 모듈이 문제를 유발하는지 결정되면, 다른 모듈에 영향을 주지 않고 최적화할 수 있다.) 모듈간의 결합도가 높지 않으므로 소프트웨어의 재사용성을 증가시킨다. 시스템 전체가 덜 개발 되었더라도 각 모듈별 성공 여부를 입증할 수 있으므로, 큰 시스템 개발 시 위험 부담이 줄어든다. public 클래스에서는 public 필드가 아닌 접근자(accessor) 메소드를 사용한다 // 이와 같은 클래스는 public으로 사용하면 안된다! class...

#004 모든 객체에 공통적인 메소드 두번째

JAVA
12 Comparable 인터페이스의 구현을 고려하자 compareTo 메소드는 Object 클래스에 정의되어 있지 않으며(자바 1.2에 추가됨), 대신에 Comparable 인터페이스에 유일하게 존재하는 메소드이다. 이 메소드는 Object.equals 메소드와 유사한 특성을 가지는데, 차이점이라면 두 객체가 동일한지 비교하는 것과 더불어 순서까지 비교할 수 있으며, 제네릭 타입을 지원한다. 클래스에서 Comparable 인터페이스를 구현하면, 이 인터페이스에 의존하는 수많은 알고리즘 및 컬렉션 클래스들과 상호연동이 가능하다. 실제로 자바 라이브러리의 모든 값은 Comparable 인터페이스를 구현하므로, 만일 알파벳 순, 숫자 순, 날짜 순과 같은 자연율을 갖는 값 클래스를 작성한다면 반드시 Comparable 인터페이스를 구현해야 한다. compareTo 메소드의 보편적 계약 순서 판단을 위해 현재 객체(compareTo 메소드가 호출된)와 지정 객체(compareTo 메소드의 인자로 전달된)를 비교한다. 현재 객체의 값이 지정 객체보다 작으면 음수 정수값을, 같으면 0을, 크면 양수 정수값을 반환한다. 만일 지정 객체 타입이 현재 객체와 비교할 수 없는 타입이면 ClassCastException 예외를 발생시킨다. 다음 설명에서 sgn(표현식)은 signum 수학 함수를 나타내며, 표현식의 값이 음수면 -1을, 0이면 0을, 양수면 1을 반환한다. 대칭적: 모든 x, y에 대하여 sgn(x.compareTo(y)) == – sgn(y.compareTo(x))가 되도록 해...

#003 모든 객체에 공통적인 메소드

JAVA
Object는 실체 클래스(concrete class)지만 원래 상속을 목적으로 설계되었다. 이 장에서는 final이 아닌 Object의 메소드(equals, hashcode, toString, clone, finalize)들을 언제 어떻게 오버라이드하는지 알려준다. 실체 클래스란? 추상 클래스와 상반되는 것으로서, 자신의 인스턴스를 생성할 수 있는 일반적인 클래스를 말한다. 8. equals 메소드를 오버라이딩 할 때는 보편적 계약을 따르자 인스턴스의 동일여부를 판정하는 euqals 메소드의 오버라이딩은 간단한 것 같지만, 잘못 구현하는 경우가 많아서 참담한 결과를 초래할 수 있다. 그런 문제를 피하는 제일 쉬운 방법은 equals 메소드를 오버라이드하지 않고 상속받은 그대로 사용하는 것이다. (여기서 equals 메소드는 Object.equals이거나, 다른 수퍼 클래스에서 Object의 equals를 이미 오버라이딩 한 것을 말한다.) equals 메소드를 오버라이드하지 않고 상속받은 그대로 사용하는 경우 1. 클래스의 각 인스턴스가 본래부터 유일한 경우 인스턴스가 갖는 값보다는 활동하는 개체임을 나타내는 것이 더 중요한 Thread와 같은 클래스가 여기에 해당된다. 그런 클래스들은 인스턴스가 갖는 값의 논리적인 비교는 의미가 없으며, 객체 참조가 같으면 동일한 것임을 알 수 있으므로 Object의 equals(== 연산자 사용)를 그냥 사용하면 된다. 2. 두 인스턴스가 논리적으로 같은지 검사하지 않아도 되는 클래스의 경우 클래스를 설계할 때, 인스턴스가 갖...