월별 글 목록: 2008년 2월월

LinkedHashMap 기반으로 LRU(least-recently-used) 캐시하기

java 1.4 Collections API에 새롭게 첨가된 java.util.LinkedHashMap 클래스는 HashMap처럼 해쉬테이블에 기반을 둔 Map 클래스 입니다. LinkedHashMap이 다른 점은 맵 엔트리에서 실행되는 링크된 리스트를 관리할 수 있고 또한 그 엔트리에 대해서 예측할 수 있는 반복 작업을 수행할 수 있다는 것이다. 대부분 이 순서는 맵에 엔트리가 추가된 순서대로 되고 가끔씩 아주 유용한 특징으로 사용할 수 있는 상황도 있습니다. 

LinkedHashMap은 생성자의 세 번째 인자로 true 값을 넘겨줌으로써 가장 최근에 접근(즉 조회되거나 설정된) 순서에서 가장 오래 전에 접근된 순서로 엔트리 순서를 설정할 수 있다.

그리고, LinkedHashMap의 removeEldestEntry()를 새로운 Entry가 추가될 때 마다 호출을 하게되면, 이 메소드가 true를 반환하면 맵에서 ‘가장 오래된’ Entry, 즉 가장 오래 전에 입력되거나 사용된 것은 자동적으로 삭제된다. removeEldestEntry()의 기본값으로 항상 false를 반환하지만 맵이 정해진 어떤 최고 크기에 다다르면 true 값을 반환하도록 오버라이드 할 수 있다. 이와 같이 하면 LRU(least-recently-used) 캐시를 만들 수 있는 것입니다.

public class LRUCache extends java.util.LinkedHashMap {
    public LRUCache(int maxsize) {
        super(maxsize*4/3 + 1, 0.75f, true);
        this.maxsize = maxsize;
    }
    protected int maxsize;
    protected boolean removeEldestEntry() {
        return size() > maxsize;
    }
}

Iterator보다 빠르게 Collection의 오브젝트 처리

Collection에 들어있는 오브젝트를 가져오기 위해서 일반적으로 Iterator 패턴을 구현한 Iterator 클래스를 많이 사용합니다. 하지만, Iterator클래스의 next()를 통해서 오브젝트를 가져오고, hasNext()를 통해서 오브젝트의 마지막을 체크하기 때문에, List 타입의 Collection에서는 get()를 사용하는 것이 더 빠르게 동작을 합니다.


ex) Iterator 클래스 사용예


Iterator iterator = array.iterator();
while (iterator.hasNext()) {
 Object object = iterator.next();
}

ex) List 타입의 get() 사용 예


int size = array.size();
for (int i=0; i<size ; i++) {
 Object object = array.get(i);
}

정규 표현식을 사용하여 HTML 태그 제거하기

먼저 HTML 태그는 < 로 시작해서 > 로 끝나고, 종료 태그의 경우는 </ 로 시작하거나 또는 />로 끝난다.
따라서, 다음과 같은 정규 표현식은 HTML 태그를 모두 포함하게 된다.
<(/)?([a-zA-Z]*)(\\s[a-zA-Z]*=[^>]*)?(\\s)*(/)?>

자바 1.4부터 String.repalceAll(String regex, String replacemenet) 메소드를 제공하는데, 이 메소드는 문자열에서 regex의 정규 표현식에 일치하는 부분을 replacement로 바꿔주는 기능을 제공한다.

따라서, 특정 문자열에 HTML 태그를 제거하려면 위의 정규 표현식을 다음과 같이 적용하면 된다.

String text = “……”;
String textWithoutTag = text.replaceAll(“<(/)?([a-zA-Z]*)(\\s[a-zA-Z]*=[^>]*)?(\\s)*(/)?>”, “”);  

import java.util.*;
public class Test
{
  public static void main(String[] args)
  {
    String data = ” <a href=”aaa.gif”>”;
    data += “Afdskjhasdkljhaskld” + “</a>”;
    System.out.println( data.replaceAll(“(?:<!–.*?(?:–.*?–\\s*)*.*?–>)|(?:<(?:[^>’\”]*|\”.*?\”|’.*?’)+>)”,””) );
  }
}

String 인코딩 변경

String data = “데이타”; 
String utf8 = new String(data.getBytes(“UTF-16“), “UTF-8“);
String utf16 = new String(data.getBytes(“UTF-8“), “UTF-16“);

표준 캐릭터셋


Java 플랫폼의 구현은 모두 다음의 표준 캐릭터셋를 지원 할 필요가 있습니다. 지원 되고 있는 그 외의 캐릭터셋에 대해서는 구현의 릴리스 노트를 참조하십시오. 그러한 옵션의 캐릭터셋의 동작은 구현 마다 다를 가능성이 있습니다.

























캐릭터셋


설명

US-ASCII 7 비트 ASCII (ISO646-US/Unicode 캐릭터셋의 Basic Latin 블록)
ISO-8859-1   ISO Latin Alphabet No. 1 (ISO-LATIN-1)
UTF-8 8 비트 UCS 변환 형식
UTF-16BE 16 비트 UCS 변환 형식, 빅 endian 바이트순서
UTF-16BE 16 비트 UCS 변환 형식, little endian 바이트순서
UTF-16 16 비트 UCS 변환 형식, 옵션의 바이트순서 마크로 식별되는 바이트순서

Boxing과 UnBoxing

다음을 살펴보자

int i = 42;
object o = i;

위 예제는 i값에는 42가 stack 영역에 있다.
이를 다시 대입해야 하는 o는 stack 영역의 것을 가지고 올 수 있을까?
안타깝게도 object는 heap영역에 메모리를 생성하고 그를 참조하므로… 바로 stack영역의 값을 참조 할 수 없다.
따라서 위 예제를 에러 없이 실행하려면..스택 영역의 42를 힙영역으로 복사하고 그것을 참조해야 한다.

실제로 이런 복사과정은 자동으로 일어나게 되며 이를 Boxing 이라고 한다.

반대의 경우를 생각해보자

object o = 43;
int i = o;

object 형의 값은 힙영역에 있다고 했다.
따라서 스택에 값을 가져야 하는 int i 는 o를 참조 하지 못한다.
에러가 난다.
이를 막으려면 object의 값을 형태변환을 하면 된다.

object o = 43;
int i = (int) o;

이렇게 heap 영역의 것을 스택영역으로 가져오는 것을 UnBoxing이라고 한다.