출처 : http://cusmaker.tistory.com/49

정규표현식 문법

^ : 문자열의 시작을 나타냄. 

$ : 문자열의 종료를 나타냄. 

. : 임의의 한 문자를 나타냄. (문자의 종류는 가리지 않는다)

| : or를 나타냄. 

? : 앞 문자가 없거나 하나있음을 나타냄. 

+ : 앞 문자가 하나 이상임을 나타냄. 

* : 앞 문자가 없을 수도 무한정 많을 수도 있음을 나타냄. 

[] : 문자 클래스를 지정할 때 사용한다. 문자의 집합이나 범위를 나타내며 두 문자 사이는 '-' 기호로 범위를 나타낸다. 

      []내에서 ^ 가 선행하여 나타나면 not 를 나타낸다. 

{} : 선행문자가 나타나는 횟수 또는 범위를 나타낸다. 

a{3} 인 경우 a가 3번 반복된 경우를 말하며, a{3,}이면 a가 3번 이상 반복인 경우를 말한다. 또한 a{3,5}인 경우 

a가 3번 이상 5번 이하 반복된 경우를 나타낸다. 

( ): 소괄호 ‘( )’ 특수문자는 ‘( )’ 특수문자 안의 글자들을 하나의 문자로 봅니다. 예를 들어 ‘gu(gg){2}le’ 와 같은 패턴을 작성하게 되면    

     ‘guggggle' 문자열이 문자열에 포함되어 있어야 됩니다.

|: 패턴 안에서 OR연산을 사용할 때 사용합니다. 예를 들어 'hi|hello' 는 hi 나 hello 가 포 함되어있는 문자열을 의미합니다.

\w : 알파벳이나 숫자

\W : 알파벳이나 숫자를 제외한 문자

\d : 숫자 [0-9]와 동일

\D : 숫자를 제외한 모든 문자

\: 위의 각 기능에서 벗어납니다(escape).

(?i): 앞 부분에 (?i) 라는 옵션을 넣어주면 대소문자를 구분하지 않는다 (물음표+소문자i(아이))

 

기본적인 문자열 검증 정규식

 

^[0-9]*$  :  숫자만

^[a-zA-Z]*$  :  영문자만

^[가-힣]*$  :  한글만

^[a-zA-Z0-9]*$  :  영어/숫자만

.+ : 한문자 이상의 전체문자를 표시한다.

 

정규식 표현 예제

이메일 : ^[a-zA-Z0-9]+@[a-zA-Z0-9]+$  or  ^[_0-9a-zA-Z-]+@[0-9a-zA-Z-]+(.[_0-9a-zA-Z-]+)*$ 

휴대폰 :  ^01(?:01[6-9]) - (?:\d{3}\d{4}) - \d{4}$ 

일반전화 : ^\d{2,3} - \d{3,4} - \d{4}$

주민등록번호 : \d{6} \- [1-4]\d{6}

IP 주소 : ([0-9]{1,3}) \. ([0-9]{1,3}) \. ([0-9]{1,3}) \. ([0-9]{1,3})

파일확장자: ([^\s]+(\.(?i)(jpg|png|gif|bmp))$)

 

 

클래스 사용 예.

A typical invocation sequence is thus  

Pattern p = Pattern.compile("a*b"); 

Matcher m = p.matcher("aaaaab"); 

boolean b = m.matches();

 

A matches method is defined by this class as a convenience for when a regular expression is used just once. 

This method compiles an expression and matches an input sequence against it in a single invocation. The statement  

 

boolean b = Pattern.matches("a*b", "aaaaab");

Posted by outliers
,

출처 : http://www.javaro.net/xe/tips/722

안드로이드에서 C코드와 연동할때 JNI를 써야합니다.


이때 쓰는 JNI에 대해서 세미나 할때에 썼던 발표 자료와


NDK 빌드시에 설명이 조금 부족한것 같아서


추가 설명.docx파일을 첨부하여 추가 설명 해 놓았습니다.


다음 웹 페이지는 JNI에 가이드 페이지 입니다.


http://eureka7.com.ne.kr/jdk-1_5_0-Korean-doc/docs/guide/jni/spec/jniTOC.html


다음의 블로그는 Android NDK 와 JNI에 대해 처음 시작부터

추가적으로 도움이 될만한 정보가 담겨있는 블로그 입니다.


http://blog.naver.com/jbin_k?Redirect=Log&logNo=130120653153


다음은 JNI Callback 함수 등록에 대한 블로그 입니다.


http://blog.naver.com/PostView.nhn?blogId=iflowerpot&logNo=80120899811&redirect=Dlog&widgetTypeCall=true


다음 두 블로그는 JNI에 대해 전체적으로 유용한 설명이 되어 있습니다.


http://freeair-textcube.blogspot.com/2010/02/jnijava-native-interface-1%ED%8E%B8.html

http://hellonewworld.tistory.com/162


위 블로그들의 내용을 다 이해하실 정도가 되면은 JNI에 대해서 꽤 많은 내용을 습득하게 될 것이라 생각합니다.


감사합니다.

 

Posted by outliers
,

Effect Java 제2판(Joshua Bloch / Addison Wesley) 을 공부하고 정리한 내용 입니다.

10. toString 메소드는 항상 오버라이드 하자.

  • 모든 서브 클래스들은 이 메소드를 오버라이드 할 것을 권한다. toString 메소드를 잘 구현하면 우리 클래스를 더욱 편하게 사용할 수 있다.
  • 클래스에서 toString 메소드를 잘 구현하면, 자신의 인스턴스는 물론이고 그 인스턴스들의 참조를 갖고 있는 객체들도 toString 메소드의 장점을 가질 수 있다. 가능하다면 toString 메소드에서는 객체의 모든 중요한 정보를 반환해야 한다. 하지만 객체가 너무 크거나 하면 요약된 정보만을 반환해야 할 것이다.
  • toString 메소드 반환 값의 형식을 규정 시 단점이 있다. 그 클래스가 여러 곳에서 사용될 경우, 한번 정해 놓으면 두고두고 신경 써야 한다는 것이다.
  • 표현 형식의 규정 여부와는 무관하게 아무튼 그 의도를 명쾌하게 문서화해야 한다.
  • 형식의 규정 여부와는 관계 없이, toString 메소드의 반환 값에 포함되는 모든 정보를 프로그램적으로 접근하는 방법을 제공하자.

 

 

 	/**
	 * PhoneNumber 객체(전화번호)의 문자열 표현을 반환한다.
	 * 문자열은 14자이며 형식은 "(XXX) YYY-ZZZZ" 이다.
	 * 여기서 XXX는 지역번호이고, YYY는 국번호, ZZZZ은 선번호이다.
	 * 각 영문 대문자는 한 자리의 십진수를 나타낸다.
	 * 지정된 자리수가 다 채워지지 않은 경우는 세 부분 모드 0을 앞에 붙인다.
	 * 예를 들어, 선번호의 값이 123이면, 문자열 표현 시 "0123"이 된다.
	 * 지역번호의 우 괄호 다음에는 스페이스를 하나 추가한다.
	 */
	@Override
	public String toString() {
		return String.format("(%03d) %03d-%04d", 
							areaCode, prefix, lineNumber);
	}
	
	// 만일 이 클래스의 객체를 문자열로 표현하는 형식을 규정하지 않는다면, 다음과
	// 같이 주석을 넣는게 좋을 것이다.
	
	/**
	 * 이 부분의 간략한 표현을 반환한다.
	 * 반환 문자열의 형식은 정해지지 않았으므로 변결될 수 있다.
	 * 일반적인 형태는 다음과 같다:
	 * 
	 * "[Potion #9: type=love, smell=turpentine, look=india link]"
	 */
	@Override
	public String toString() { ... }	
Posted by outliers
,

Effect Java 제2판(Joshua Bloch / Addison Wesley) 을 공부하고 정리한 내용 입니다.

9. equals메소드를 오버라이드 할 때는 hashCode 메소드도 항상 같이 오버라이드 하자.

Object.hashcode 메소드 명세서에서 가져 온 계약 사항은 다음과 같다.

  • 애플리케이션 실행 중에 같은 객체에 대해 한 번 이상 호출되더라도 hashCode 메소드는 같은 정수를 일관성 있게 반환해야 한다(equals 메소드에서 비교하는 객체의 값이 변경되지 않는다면).
    단, 이 정수 값은 애플리케이션이 매번 다시 실행될 때마다 일관되게 같을 필요는 없다.
  • equals(Object) 메소드 호출 결과 두 객체가 동일하다면, 두 객체 각각에 대해 hashCode 메소드를 호출했을 때 같은 정수 값이 나와야 한다.
  • equals(Object) 메소드 호출 결과 두 객체가 다르다고 해서 두 객체 각각에 대해 hashCode메소드를 호출했을 때 반드시 다른 정수 값이 나올 필요는 없다. 그러나 같지 않은 객체들에 대해 hashCode 메소드에서 서로 다른 정수 값을 반환하면, 이 메소드를 사용하는 해시 컬렉션들(HashMap, HashSet, Hashtable등)의 성능을 향상시킬 수 있음을 알아야 한다.

hashCode의 오버라이딩에 실패했을 때 위배되는 주요 조항은 두 번째 것으로써, 동일한 객체들은 같은 해시 코드 값을 가져야 한다는 것이다.

 
	// 최악의 hashCode 메소드 - 절대 이렇게 사용하지 말 것!
	@Override
	public int hashCode() {
		return 42;
	}

 

HashCode 를 만드는 간단한 방법

  1. 예를 들어, 17과 같이  0이 아닌 어떤 상수 값을 result라는 int 변수에 저장한다.
  2. 우리 객체의 각 주요 필드(equals 메소드에서 비교하는) f에 대해 다음을 수행한다.
    1. 각 필드에 대한 int 타입의 해시 코드 c를 다음과 같이 산출한다.
      1. 필드 f가 boolean 타입이면, (f ? 1 : 0)
      2. 필드 f가 byte, char, short, int 타입이면 (int)f
      3. 필드 f가 long 타입이면, (int)(f ^ (f >>> 32)).
      4. 필드 f가 float 타입이면 Float.floatToIntBits(f)
      5. 필드 f가 double 타입이면 Double.doubleToLongBits(f)를 실행한 후 반환된 long 타입의 값을 앞의  III 처럼 처리하여 해시 코드 값을 구한다.
      6. 필드 f가 객체 참조일 경우는, 현재(equals 메소드가 호출된) 객체의 equals 메소드에서 그 필드를 비교하기 위해 f가 참조하는 객체의 equals 메소드를 재귀적으로 호출한다. 그러면 그 객체의 필드에 대해 hashCode 메소드도 재귀적으로 자동 호출된다. 만일 더 복잡한 비교(객체의 여러 필드를 비교하거나, 필드의 복잡한 연산과 같은)가 필요하다면, 필드의 "표준 형식"을 만들어 처리하고 그 표준 형식에 대해 hashCode 메소드를 호출한다. 만일 필드 f의 값이 null이면, 0을 반환한다(또는 다른 어떤 상수 값도 가능하지만 관례적으로 0을 사용한다.)
      7. 필드 f가 배열이라면 배열의 각 요소를 별개의 필드처럼 처리한다. 즉, 위의 규칙들을 적용하여 처리를 해야 할 요소 각각의 해시 코드 값을 산출한다. 그리고 바로 밑의 2.2 수식을 적용하여 그값들의 합을 구한다. 만일 배열 필드의 모든 요소를 처리해야 한다면 자바 1.5 버전에 새로 추가되어 오버로딩 된 Arrays.hashCode 메소드들 중 하나를 사용할 수 있다.
    2. 앞의 2.1 단계에서 구한 코드 c를 result에 합계한다.
      result = 31 * result + c;
    3. result 를 반환한다.
    4. hashCode 메소드 작성이 끝나면 동일한 인스턴스들이 같은 값의 해시 코드를 갖는지 검토하자. 그리고 단위 테스트를 작성하여 잘 실행되는지 검증하자.

 

 
	// 어떤 클래스의 세 개의 중요 필드가 있고, 모두 short 타입 일 경우
	@Override
	public int hashCode() {
		int result = 17;
		result = 31 * result + areaCode;
		result = 31 * result + prefix;
		result = 31 * result + lineNumber;
		return result;
	}
Posted by outliers
,

Effect Java 제2판(Joshua Bloch / Addison Wesley) 을 공부하고 정리한 내용 입니다.

8. equals 메소드를 오버라이딩 할 때는 보편적 계약을 따르자.

다음 조건 중 어느 하나라도 만족하면 equals 오버라이드를 하지 않고 상속 받은 그대로 사용하자.

  • 클래스의 각 인스턴스가 본래부터 유일한 경우.
  • 두 인스턴스가 논리적으로 같은지 검사하지 않아도 되는 클래스의 경우
  • 수퍼 클래스에서 equals 메소드를 이미 오버라이딩 했고, 그 메소드를 그대로 사용해도 좋은 경우
  • private이나 패키지 전용(package-private) 클래스라서 이 클래스의 equals 메소드가 절대 호출되지 않아야 할 경우

 

객체 참조만으로 인스턴스의 동일 여부를 판단하는 것이 아니라, 인스턴스가 갖는 값을 비교하여 논리적으로 같은지 판단할 필요가 있는 클래스로써, 자신의 수퍼클래스에서 equals 메소드를 오버라이드 하지 않았을 때 Object.equals 를 오버라이드 하는 것이 좋다.

equals 메소드를 오버라이드 할 때는 이 메소드의 보편적 계약을 따라야 한다.
equals 메소드는 동등 관계(equivalence relation)을 구현하며, 그것은

  • 재귀적이다(Reflexive) : null이 아닌 모든 참조 값 x에 대해, x.equals(x)는 반드시 true를 반환해야 한다.
  • 대칭적이다(Symmetric) : null이 아닌 모든 참조 값 x와 y에 대해, y.equals(x)가 true를 반환한다면 x.equals(y)도 반드시 true를 반환해야 한다.
  • 이행적이다(Transitive) : null이 아닌 모든 참조 값 x, y, z에 대해, 만일 x.equals(y)가 true를 반환하고 y.equals(z)가 true를 반환한다면 x.equals(z)도 반드시 true를 반환해야 한다.
  • 일괄적이다(Consistent) : null이 아닌 모든 참조 값 x와 y에 대해, equals 메소드에서 객체 비교 시 사용하는 정보가 변경되지 않는다면, x.equals(y)를 여러 번 호출하더라도 일관성 있게 true 또는 false를 반환해야 한다.
  • null이 아닌 모든 참조 값 x에 대해, x.equals(null)은 반드시 false를 반환해야 한다.

 

좋은 equals 메소드를 만드는 방법은 다음과 같다.

  1. 객체의 값을 비교할 필요 없고 참조만으로 같은 객체인지 비교 가능하다면 == 연산자를 사용하자.
  2. instanceof 연산자를 사용해서 전달된 인자가 올바른 타입인지 확인하자.
  3. 인자 타입을 올바른 타입으로 변환한다.
  4. 클래스의 중요한(꼭 비교해야 하는) 필드 각각에 대해서는 인자로 전달된 객체의 필드와 현재 객체(equals) 메소드가 호출된)의 필드가 모두 같은지 빠뜨리지 말고 비교한다.
  5. 우리의 equals 메소드를 작성한 후에는 보편적 계약을 따르는지 확인하고 단위 테스트 코드를 작성하여 그런 속성들이 지켜지는지 검사한다.

 

유의 사항

  • equals 메소드를 오버라이드 할 때는 hashCode 메소드도 항상 오버라이드 한다.
  • 너무 똑똑한 척 하지마라. 단순히 필드 값이 같은지 검사하는 것이라면 equals 계약 준수가 어렵지 않다. 하지만 너무 지나치게 동일 여부를 비교하려 하면 문제가 생기기 쉽다.
  • equals 메소드의 인자 타입을 Object 대신 다른 타입으로 바꾸지 말자.

 

 

Posted by outliers
,

Effect Java 제2판(Joshua Bloch / Addison Wesley) 을 공부하고 정리한 내용 입니다.

7. 파이널라이저(finalizer)의 사용을 피하자.

  1. 신속하게 실행된다는 보장이 없다.
    객체가 사용할 수 없게 되는 시점부터 파이널라이저가 실행되는 시점까지는 긴 시간이 소요될 수 있다. 파이널라이저 내부에서는 실행 시간이 매우 중요한 작업을 절대 하지 말아야 한다는 것이다.

  2. 파이널라이즈를 하는 동안 catch 되지 않은 예외가 발생하면 그 예외는 무시되고 그 객체의 파이널 라이즈는 종결된다.

  3. 파이널라이저를 사용하면 엄청난 성능 저하가 발생한다.

파일이나 스레드처럼 종결 작업이 필요한 자원을 갖는 객체들의 클래스에서는 파이널라이저 대신 무었을 써야 할까?
작업이나 자원을 정상적으로 종료하는 메소드만 별도로 추가하면 된다. 그리고 더 이상 필요 없는 각 인스턴스에 대해서 그 클래스의 클라이언트가 종료 메소드를 호출하도록 하면 된다.

 

파이널라이저는 어떤 경우에 사용하면 좋을까??

  1. 생성된 객체를 갖고 있는 코드에서 그 객체의 종료 메소드 호출을 빠뜨렸을 경우에 "안전망"의 역할을 하는 것이다.
    즉, 클라이언트가 종료 메소드 호출에 실패하는 그런 경우(거의 없기를 바라지만)를 대비해서 파이널라이저를 사용한다.

  2. 네이티브 피어(native peer) 객체와 관련이 있다.
    네이티브 피어는 일반 자바 객체가 아니므로, 그것과 연관된 자바 피어 객체가 소멸되면 가비지 컬렉터가 알지 못하며 재활용 할 수도 없다. 따라서 이런 경우 파이널라이저가 적합한 수단이 된다.

"파이널라이저의 연쇄 호출(chaining)" 은 자동으로 실행되지 않는다는 것에 유의하자.

 

요약

  • 종료 메소드 호출을 빼먹은 경우를 대비한 안전망의 역할이나, 또는 중요하지 않은 네이티브 자원을 종결하는 경우 외에는 파이널라이저를 사용하지 말자.
  • 어쩔 수 없이 파이널라이저를 사용해야 하는 그런 경우에는 super.finalize()를 호출하는 것을 잊지 말자.
  • 만일 안전망의 역할로 파이널라이저를 사용한다면, 부적절한 상황(자원 사요잉 끝나지 않은 객체를 파이널라이즈하는)을 메시지로 기록해야 한다는 것을 잊지 말자.
  • public 이고 final이 아닌 클래스에 파이널라이저가 필요하다면, 파이널라이저 가디언의 사용을 고려하자. 서브 클래스의 파이널라이저에서 super.finalize 호출에 실패하더라도 파이널라이즈가 될 수 있기 때문이다.
Posted by outliers
,

Effect Java 제2판(Joshua Bloch / Addison Wesley) 을 공부하고 정리한 내용 입니다.

6. 쓸모없는 객체 참조를 제거하자.

  1. 어떤 클래스에서 자신의 메모리를 자가기 관리 한다면, 프로그래머는 항상 메모리 누출에 주의 해야 한다.
    따라서 특정 배열 요소가 자유로 사용 가능해질 때는 그 요소에 저장되었떤 객체 참조를 반드시 null 값으로 변경해야 한다.

     
    // 어디에서 "메모리 누출"이 생기는지 찾을 수 있는가?
    public 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 push(Object e) {
    		ensureCapacity();
    		elements[size++] = e;
    	}
    	
    	public Object pop() {
    		if (size == 0)
    			throw new EmptyStackException();
    		return elements[--size];
    	}
    	
    	/**
    	 * 배열 요소를 저장하는 필요한 공간을 확인하고
    	 * 배열이 커질 필요가 있을 때는 그 크기를 2배로 늘린다.
    	 */
    	private void ensureCapacity() {
    		if (elements.length == size)
    			elements = Arrays.copyOf(elements, 2 * size + 1);
    	}
    }


    객체들을 가리키는 쓸모 없는 참조를 스택에서 여전히 가지고 있다. 해결책은 쓸모 없는 참조를 null로 만드는 것이다.

     
    public Object pop() {
    	if (size == 0)
    		throw new EmptyStackException();
    	Object result = elements[--size];
    	elements[size] = null; // 쓸모 없는 참조를 제거한다.
    	return result;
    }
    


    이런 문제로 고통을 껵어 본 프로그래머들은 코드 실행이 끝나는 즉시로 너무 지나치게 모든 객체 참조를 null 값으로 바꾸려 한다. 그것은 바람직하지 않다. 프로그램 코드가 필요 이상으로 어수선해지기 때문이다. 객체 참조를 null로 변경하는 것은 꼭 필요할 때만 예외적으로 행해야 한다. 쓸모 없는 참조를 제거하는 가장 좋은 방법은, 참조 값을 갖는 변수가 유효 범위(scope) 밖에 있도록 하는 것이다. 만일 그런 변수가 최소한의 유효 범위 내에 있도록 정의 한다면 자연스레 그렇게 될 것이다.

  2. 메모리 누출이 흔히 생기는 또 다른 근원은 캐시(cache)이다.

    캐시 외부에 캐시의 키(key)에 대한 참조가 있을 동안만 캐시에 저장된 항목이 유효한 그런 캐시를 구현하는 것으로 충분하다면, WeakHashMap을 캐시로 사용하자. 그러면 키로 저장된 객체가 더 이상 참조되지 않을 때 해당 항목이 자동으로 삭제될 것이다. 캐시에 저장된 항목들의 생명주기가 각 항목의 키(값이 아닌)에 대한 외부 참조에 의해 결정되도록 할 때에만 WeakHashMap이 유용하다는 것을 기억하자.

  3. 메모리 누출의 세 번째 근원은 리스너(Listener)와 콜백(callback)이다.
    클라이언트가 콜백을 등록하되 말소는 하지 않는 API를 구현한다면 우리가 뭔가 조치를 취하지 않는 한 콜백은 계속 누적될 것이다.

    콜백이 신속하게 가비지 컬렉션 되도록 하는 가장 좋은 방법은 약한 참조(weak reference)만을 저장 유지하는 것이다. 예를 들어 WeakHashMap의 키로만 콜백을 저장한다.
Posted by outliers
,

Effect Java 제2판(Joshua Bloch / Addison Wesley) 을 공부하고 정리한 내용 입니다.

5. 불필요한 객체의 생성을 피하자.

기능적으로 동일한 객체를 필요할 때마다 매번 새로 생성하기보다는 하나의 객체를 재사용하는 것이 좋을 때가 많다. 재사용을 하면 객체 생성에 소요되는 비용(시간과 자원)이 절감되므로 실행 속도가 더 빨라지고 코드도 보기 좋게 작성할 수 있다. 불변(immutable) 객체는 항상 재사용 가능하다.

해서는 안될 극단적인 예로 다음 코드를 생각해 보자

 
// 이렇게 하지 말자
String s = new String("stringette");

// 위 문장의 개선된 버전
String s = "stringette";

여기서는 실행될 때마다 새로운 인스턴스를 생성하지 않고 하나의 String 인스턴스를 사용하며, 같은 JVM에서 실행되는 어떤 코드에서도 동일한 문자열 리터럴(literal)을 갖도록 재사용 될 것이다.

불변 클래스의 불필요한 객체 생성을 막으려면 생성자보다는 static 팩토리 메소드를 사용하는 것이 좋다. 불변 객체의 재사용에 덧붙여, 객체(의 상태)가 변경되지 않는다면 가변(mutable) 객체도 재사용 가능하다.

해서는 안될 다른 예

 
public class Person {
	private final Date birthDate;
	
	// 다른 필드와 메소드 및 생성자는 생략
	// 이렇게 하지 말자!
	public boolean isBabyBoomer() {
		// 불필요한 객체 생성
		Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
		gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
		Date boomStart = gmtCal.getTime();
		gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
		Date boomEnd = gmtCal.getTime();
		return birthDate.compareTo(boomStart) >= &&
				birthDate.compareTo(boomEnd) < 0;
	}
}

 

isBabyBoomer 메소드에서는 매번 호출될 때마다 하나의 Calendar 객체와 TimeZon 객체 및 두개의 Date 인스턴스를 불필요하게 생성한다. 아래 버전에서는 static 초기자(initializer)를 사용해서 그런 비효율적인 객체 생성을 막는다.

 
public Person {
	private final Date birthDate;
	// 다른 필드와 메소드 및 생성자는 생략
	/**
	 * 베이비 붐의 사작과 종료 일자.
	 */
	private static final Date BOOM_START;
	private static final Date BOOM_END;
	
	static {
		Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
		gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
		BOOM_START = gmtCal.getTime();
		gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
		BOOM_END = gmtCal.getTime();
	}
	
	public boolean isBabyBoomer() {
		return birthDate.compareTo(BOOM_START) >= &&
				birthDate.compareTo(BOOM_END) < 0;
	}
}

 

이 개선된 버전에서는 Person 클래스가 초기화될 때 Calendar, TimeZone, Date 인스턴스를 한번만 생성한다.
성능 향상은 물로 코드도 더 명확하다

자바 1.5 이상의 버전에서는 불필요한 객체를 생성하는 새로운 방법이 있다. 오토박싱(autoboxing)이라고 하는데, 기본형 데이터를 이에 대응되는 박스화 기본형(boxed primitive) 클래스 객체로 자동 변환해주는 기능이다. 이와는 반대로 박스화 기본형 클래스 객체를 기본형으로 자동 변환해주는 것을 오토언박싱(autounboxing)이라 한다.

 
// 무지하게 느린 프로그램! 어디서 쓸데없는 객체가 생성되는지 찾아보자.
public static void main(String[] args) {
	Long sum = 0L;
	for (long i = 0; i < Integer.MAX_VALUE; i++) {
		sum += i;
	}
	System.out.println(sum);
}

의도하지 않은 오토 박싱이 생기지 않도록 주의하자!!

그러나 객체 생성은 많은 비용이 드니 피해야 한다는 의미로만 이 항목을 오해해서는 안 된다. 도리어 생성자에서 일을 거의 하지 않는 작은 객체의 생성과 재상용은 비용이 적게 든다. 프로그램의 명확성과 단순성 및 능력을 향상시키기 위해서라면 객체를 추가로 만드는 것도 좋은 일이다. 이와는 반대로, 우리가 직접 객체 풀(object pool)을 만들고 유지하여 객체 생성을 피하려는 방법은 좋지 않다. 단, 풀에 유지할 객체들이 대단히 무거워서 생성 비용이 많이 드는 것이라면 고려해 볼만하다.(데이터베이스 연결)

Posted by outliers
,

Effect Java 제2판(Joshua Bloch / Addison Wesley) 을 공부하고 정리한 내용 입니다.

4. private 생성자를 사용해서 인스턴스 생성을 못하게 하자.

static 메소드와 static 필드만을 모아 놓은 클래스를 만들 필요가 종종 있을 것이다. 그런 유틸리티(Utility) 클래스들은 인스턴스를 생성하지 못하게 설계되었다. 인스턴스 생성이 무의미 하기 때문이다.(Math, Arrays 등) 그러나 그런 클래스일지라도 명시적으로 지정한 생성자가 없을 때는 컴파일러가 디폴트(default) 생성자를 만들어 준다.
클래스 사용자 입장에서는 이 생성자가 다른 것과 차이가 없으며, 인스턴스 생성이 가능한 클래스로 오인될 수 있다.

우리가 private 생성자를 정의하면 인스턴스 생성이 불가능한 클래스를 만들 수 있다.

 
// 인스턴스 생성이 불가능한 유틸리티 클래스
public class UtilityClass {
	// 디폴트 생성자가 자동으로 생기는 것을 방지한다.
	private UtilityClass() {
		throw new AssertionError();
	}
	... // 이하 생략
}

명시적으로 정의한 생성자가 private 이므로 이 클래스 외부에서는 생성자 호출이 불가능 하다.

Posted by outliers
,

Effect Java 제2판(Joshua Bloch / Addison Wesley) 을 공부하고 정리한 내용 입니다.

3. private 생성자나 enum 타입을 사용해서 싱글톤의 특성을 유지하자.

싱글톤(singleton)은 정확히 하나의 인스턴스만 생성되는 클래스이다.
자바 1.5 버전 이전에는 싱글톤을 구현하는 방법이 두 가지 있었으며, 두 방법 모두 생성자를 private으로 하고, 유일한 인스턴스에 접근할 수 있도록 public static 멤버를 외부에 제공한다.

1. public final 필드를 갖는 싱글톤

 
// public final 필드를 갖는 싱글톤
public class Elvis {
	public static final Elvis INSTANCE = new Elvis();
	private Elvis() { ... }
	
	public void leaveTheBuilding() { ... }
}

 

public이나 protected 생성자가 없으므로 private 생성자는 딱 한번만 호출되어 public static final 필드인 Elvis.INSTANCE를 초기화 한다. 클래스가 최초 한 번 초기화 될 때 정확히 하나의 인스턴스만 생길 것이다.

2. static 팩토리 메소드를 갖는 싱글톤

 
// static 팩토리 메소드를 갖는 싱글톤
public class Elvis {
	private static final Elvis INSTANCE = new Elvis();
	private Elvis() { ... }	
	public static Elvis getInstance() { return INSTANCE; }
	
	public void leaveTheBuilding() { ... }
}

 

1번 방법의 주된 장점은, 멤버 필드만 봐도 싱글톤 클래스인지 명쾌하게 알 수 있다는 것이다. 즉 public static 필드가 final 이므로 그 필드는 항상 같은 객체 참조를 갖는다.

2번 방법의 장점은, 클래스의 API를 변경하지 않고 클래스에서 반환하는 싱글톤 인스턴스의 형태를 바꿀 수 있는 유연성을 제공한다는 것이다. 예를 들어, 팩토리 메소드에서는 오직 하나의 인스턴스를 반환하지만, 이 메소드를 호출하는 각 스레드(thread)마다 하나씩의 인스턴스를 반환하도록 쉽게 수정할 수 있다.

1, 2번의 방법은 직렬화 하는데 불편함이 있다.

3. 자바 1.5 이후 버전에서는 싱글톤을 구현하는 다른 방법이 있다. 하나의 요소를 갖는 열거형 타입(enum)을 만들면 된다.

 
// 열거형 (Enum) 싱글톤 - 가장 좋은 방법임.
public enum Elvis {
	INSTANCE;
	public void leaveTheBuilding() { ... }
}

 

이 방법은 public 필드 방법과 기능적으로 동일하지만 더 간단하다. 그리고 복잡한 직렬화나 리플렉션(reflection) 상황에서도 직렬화가 자동으로 지원되고, 인스턴스기 여러 개 생기지 않도록 확실하게 보장해 준다. 싱글톤을 구현하는 가장 좋은 방법이다.

Posted by outliers
,