Whiteship's Note


Spring Webinar 우와..

Good Tools : 2008.10.29 23:14


실시간 세미나.... ㄷㄷㄷ..
그것도 무료로..
그것도 맥북에도 잘 돌아가는...

사용자 삽입 이미지
사용자 삽입 이미지
와.. 장난 아닙니다. 단순하게 PPT 보여주는게 아니라, 스크린캐스팅을 실시간으로 보여주고 있는거네요.

사용자 삽입 이미지
이제 강의에 집중하렵니다. +.+
top


맥OSX IRC 클라이언트 Colloquy

Good Tools : 2008.10.29 22:08


공짜에요. 좋네요. 캬캬
http://colloquy.info/

사용자 삽입 이미지
사용자 삽입 이미지

캬오... 갠춘하네요.
top


EJ2E Item 9. equals를 재정의할 땐 hashCode도 재정의하라.

Java : 2008.10.29 16:51


참조: Effective Java 2nd Edition Item 9. Always override hashCode when you override equals

equals를 재정의한 클래스는 반드시 hashCode를 재정의 해야 한다. 그렇지 않으면 Object.hashCode 일반적인 계약을 위반하게 된다. 이를 위반하면 hash 기반의 컬렉션(HashMap, HashSet, Hashtable)에서 제대로 동작하지 않을 것이다.

JavaSE6 Object 표준
  • hashCode를 여러번 호출 할 때마다 같은 integer를 반환해야 한다.
  • 두 객체가 equals(Object) 메소드로 동일할 때, hashCode도 같은 integer를 반환해야 한다.
  • 필수는 아니지만, equals(Object)로 가지 않은 두 객체는 hashCode를 호출했을 때 반드시 반드시 다른 integer를 반환해야 한다.
이 중에서 핵심은 두 번째 것.

HashMap에서 key로 사용하는 객체의 hashCode 값이 다르면 equals로 같은 객체여도 같은 key로 인식하지 않는다.

좋은 hashCode 만드는 방법
  • result 라는 int 변수에 0이 아닌 수를 넣는다.
  • 각각의 필드에 다음과 같은 계산식을 적용한다.
    • 필드가 boolean이면, (f ? 1 : 0)
    • 필드가 byte, char, short, int면, (int) f
    • 필드가 long이면, (int)(f ^ (f >>> 32))
    • 필드가 float면, Float.floatToIntBits(f)
    • double이면, Double.doubleToLongBits(f)를 한 다음에 long 타입 다루듯이 한 번 더 계산
    • 레퍼런스 타입이면 hashCode 호출하여 그 결과값 반환. null이면 0 반환
  • result = 31 * result + 위에서 계산한 값
  • result를 반환한다.
  • 작성후 equals로 같은 객체가 같은 hashCode를 반환하는지 단위 테스트로 검증.
equals에서 사용하지 않는 필드는 hashCode에서도 사용하면 안 된다.

example

@Override public int hashCode() {
  int result = 17;
  result = 31 * result + areaCode;
  result = 31 * result + prefix;
  result = 31 * result + lineNumber;
  return result;
}



top


EJ2E Item 8. equals를 재정의 할 떄는 일반적인 계약을 따르라.

Java : 2008.10.29 12:18


참조: Effective Java 2nd Edition Item 8. Obey the general contract when overriding equals

equals 메소드 재정의은 간단해 보이지만 잘못 될 여지가 많다.

equals 메소드 재정의가 필요 없는 경우
  • 클래스 특성상 각각의 객체가 유일할 때. ex) Thread
  • "논리적인 일치" 확인 기능을 제공하는지 관심 없을 때. ex) Random
  • 이미 상위 클래스에서 재정의한 equals를 재공하며, 그 로직이 현재 클래스서도 적당할 때. ex) AbstractSet, AbstractList, AbstractMap
  • 클래스가 private 또는 package-private인 경우 equals가 절대로 호출되지 않을거라는 확신이 있을 때.
equals 메소드 재정의가 필요한 경우
  • logical equality 개념이 있는 클래스
  • 보통 value class(예외, 싱글톤, Enum 타입 - Object의 equals가 곧 logical equality)
  • ex) Integer, Date
equals를 재정의할 때 따라야 하는 일반적인 계약(JavaSE6 Object 스펙)
  • 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에 대해, x.equals(y)를 몇 번 호출하든지 계속해서 일관적으로 true를 반환하거나 false를 반환해야 한다.
  • null이 아닌 레퍼런스 값 x에 대해, x.equals(null)은 반드시 false를 반환한다
규칙을 어기면 다른 객체가 어떻게 동작할지 예측하기 힘들다.

고품질 equals 메소드 레서피
  • 같은 객체를 참조하는 레퍼런스가 아닌지 확인. == 사용.
  • 정당한 타입인지 확인할 떄는 instanceof 연산자를 사용,
  • 적당한 타입으로 캐스팅
  • 각각의 필드가 같은지 확인. primitive 타입은 == 사용, 레퍼런스 타입은 equals 사용
  • 메소드 작성을 마친 뒤에, symmetric, transitive, comsistent 한지 단위 테스트를 작성한다.
example

@Override public boolean equals(Object o) {
  if (o == this)
    return true;
  if (!(o instanceof PhoneNumber))
    return false;
  PhoneNumber pn = (PhoneNumber)o;
    return pn.lineNumber == lineNumber
      && pn.prefix  == prefix
      && pn.areaCode  == areaCode;
}

top


연변 말투 == 보이스피싱

모하니?/Thinking : 2008.10.29 11:56


방금 전 사무실로 보이스피싱 전화 한 통이 걸려왔습니다. 보이스피싱 인지 아닌지는 대충 몇 마디만 대화를 나누면 확신이 서고 전화를 끊게 만듭니다.

"여보세요 에스엘티입니다."

"..."

"어디세요?"

"식약청인데요."  // 일단 말투가 연변 말투인데다가, 주춤 거리는걸 보고 50% 확신

"네? 식약청이요? 왜요?"

"누가 연락을 주셨는데요." // 그럴 사람이 회사 내에 없음으로. 80% 확신.

"누가 무슨 연락을 주셨는데요?"

"아.. 그럼 핸드폰 번호를.." // 전혀 어이없는 플로우로 개인 정보 요구. 99% 확신

'찰칵' // 이쯤되면 끊어도 이상하지 않습니다.

끊어 버린뒤 현재 5분 정도 경과 됐는데 연락이 안 오는거 보면 100% 보이스피싱.

말투에서 일단 50% 먹고 들어가는 연변 알바야. 제발 다른 일 좀 하면 안 되겠니?
top


EJ2E Item 7. finalizer 사용 자제하기

Java : 2008.10.29 11:06


참조: Effective Java 2nd Edition Item 7. Avoid finalizers

Finalizer는 예측 불가능하고, 위험하며, 별로 필요없다. 자바에서 자원 반납은 try-finally 블럭에서 처리하는게 보통.

finalizer의 단점은 바로 실행한다는 보장이 없다는 것이다. 객체를 참조하는 모든 레퍼런스가 없어지는 시점과 실제 finalizer를 실행하는 사이의 텀이 불규칙적이다. 따라서 호출 시기를 고려한 어떤 작업도 finalizer에서 하면 안 된다. ex) 파일 닫기.

더딘 finalization으로 인해 심각한 문제가 발생할 수도 있다. 객체 자원 반환을 지연 시키는 경우도 인해 OutOfMemoryError가 발생할 수도 있다. (finalizer thread 우선 순위가 낮아서 계속 처리가 밀리는 듯...)

finalizer 실행 자체를 안하고 프로그램이 종료 될 수도 있다. 중요 영속 상태를 갱신하는 일을 절대로 finalizer에서 하지 말아라. 만약 DB에서 공유 자원에 대한 락 해제를 finalizer에서 했다간 전체 시스템이 정지하는 사태가 벌어질 수도 있다.

System.gc는 finalizer 실행할 가능성을 높여주긴 해도 보장하진 못한다. 그리고 finalier 실행을 보장하는 System.runFinalizersOnExit와 Runtime.runFinalizerOnExitr는 치명적인 결함이 있는데다가 deprecated돼다.

finalizer를 사용하면 심각한 성능 문제도 있다. 저자의 로컬 컴터에서 430배 정도의 성능 차이가 발생했다.

finalizer를 대신해서 명시적인 종료 메소드(explicit termination method)를 제공하라. ex) InputStream의 close 같은 메소드. 이 메소드 내부에서는 해당 객체를 더이상 사용할 수 없다는 flag를 설정하고, 다른 메소드들은 해당 flag를 참조하여 경우에 따라 IllegalStateException을 던진다.

보통 명시적인 종료 메소드는 try-fianlly 블럭으로 감싸서 예외가 발생해도 실행하도록 한다.

finalizer는 언제 사용하면 좋은가?

하나는 "safety net"으로 사용자가 명시적인 종료 메소드 실행을 깜빡한 경우에 대한 대비책이다. 비록 호출될지 안될지도 모르지만 그래도 아예 안하는 것 보단 낫다. 이런 경우 로그 메시지를 뿌려서 해당 자원이 정상적으로 종료되지 않았다는 걸 알려주면 버그를 수정할 여지를 주게된다. ex) FileInputStream, FileOutputStream, Timer, Connection 얘네가 safety net으로 finalizer를 사용하고 있다.

두 번째는 native peers다. native peers는 native 객체들은 일반 객체가 아니라서 GC 대상이 아니다. 만약 이런 native 객체들이 반드시 종료해야 하는 리소스를 가지고 있다면, 위에서 살펴본 명시적인 종료 메소드를 제공하는게 좋겠다.

"finalizer zhaining"은 자동으로 이뤄지지 않는다. 어떤 클래스가 finalizer를 가지고 있고 그 하위 클래스가 그걸 재정의 했다면 그 상위의 finalizer를 반드시 명시적으로 호출해야 한다.

// Manual finalizer chaining
@Override protected void finalize() throws Throwable {
  try {
    ... // Finalize subclass state
  } finally {
    super.finalize();
  }
}

이렇게 try-finally로 감싸야 현재 finalizer에서 예외가 발생해도 상위 클래스의 finalizer를 실행할 수 있다. 상위 클래스의 finalizer 호출을 깜빡할 수도 있는 것에 대비해서 finalizer guardian이라는 걸 사용할 수도 있는데;;;;

finalizer guardian 이건 생략; -_-;;
top