Java7부터 제공되는 API로 int 형 비교때는 이걸 사용하자..


Integer.compare(int x, int y)


x - y로 계산 할 경우 오버플로우 가능성이 존재함.

저작자 표시 비영리 변경 금지
신고
Posted by 용식
저작자 표시 비영리 변경 금지
신고
Posted by 용식
TAG java, map

[Java] Map.Entry

Java 2013.11.28 14:01

for(ClassA key : myMap.keySet()) {

    System.out.println(key);

    System.out.println(myMap.get(key);

}


보다는..


for(Map.Entry<ClassA, ClassB> entrie : myMap.entrySet()) {
    System.out.println(entrie.getKey());
    System.out.println(entrie.getValue());
}

저작자 표시 비영리 변경 금지
신고
Posted by 용식
TAG java, map

마찬가지로 "테스트 주도 개발로 배우는 객체 지향 설계와 실천"의 4부에 나오는 예제입니다.

전체적인 책의 내용은 Swing 소스라서 눈에 잘 안들어와서 읽기가 힘들었는데.. 4부는 일반적인 상황에 대한 이야기라서 잘 읽히네요..;; 편식도 아니고..편독을...


아무튼.. 테스트 케이스 가독성 높이기에 대한 예제 코드 2개입니다.




1. 첫번째 코드는 테스트 케이스의 메서드명을 테스트 대상 객체의 메서드명을 그대로 쓰거나, 의미없는 메서드명을 사용하지 말고, 기능을 설명하는 형태로 메서드명을 작성하라는 것입니다. TO-BE 코드를 보시면 메서드명이 상당히 길게 작성이 되어있는데요, 이 책에서는 어차피 이 메서드를 누군가 직접 쳐서 사용할 일이 없으므로 아무리 길어도 상관없다라고 하고 있네요.  그리고 채수원님께서 쓰신 책 TDD 관련 책에도 있는것처럼 한글등으로 메서드명을 작성하면 Junit 테스트 결과가 그대로 훌륭한 보고서가 될 수 있습니다.

2. 설명을 하는 Assert 구문인데요, 단순히 assert를 사용해서 expected, but was 만 나오게 할것이 아니라 앞에 간단한 설명 구문을 붙여주면 테스트 결과 자체가 훨씩 읽기 좋아질것이라는 예제입니다.



또한 String 메시지로 단정문을 작성해야 할 때 간혹 공백문자등으로 Fail이 나는 경우가 있습니다.

이런 경우에도 문자 자체가 중요하다고 하면, indexOf와 같이 문자열이 들어있는지를 파악할수 있는 메서드등을 사용하는 것도 방법이 될 수 있습니다.

저작자 표시 비영리 변경 금지
신고
Posted by 용식

먼저 "테스트 주도 개발로 배우는 객체 지향 설계와 실천" 책의 22장에 나오는 예제 코드임을 밝힙니다.


책을 읽던 중 평소에 테스트케이스를 작성하면서 가장 귀찮았고 보기 안 좋았던 부분에 대한 해결방법이 나와서

gist에 정리 후 블로그를 이용하여 포스트해봅니다.




1. Sample1.java
테스트를 위한 객체가 필요한데 이 객체를 생성하기위해 위와 같이 다수의 객체 혹은 String등을 입력해줘야 할때 사용 할 수 있는 방법입니다. Builder 클래스를 작성하는 것..

2. Sample2.java
비슷한 객체를 다수 생성해야 할때가 있습니다. 특정 필드의 값만 다른... 그럴때 사용하는 방법입니다.

3. Sample3.java
2의 예를 사용해서 테스트 데이터를 생성하다보면, 비슷한 이름의 필드에 대해서 값을 설정할때 문제가 발생 할 수 있습니다. 위 코드에서는 orderWithGiftVoucher의 discount 필드가 0.10으로 셋팅이 된 상태이죠. 하지만 코드상으로 이 부분이 명확하게 드러나지 않습니다. 그럴 때 Builder를 넘겨주거나 혹은 현재 상태를 지닌 Builder의 사본을 반환하는 팩터리 메서드(but())를 추가하는등의 방법입니다.

4.Sample4.java
Builder의 조합의 경우 build() 메서드의 다수 출현으로 코드가 산만해집니다. 이럴때 사용하는 방법이며, 팩터리 메서드를 이용해서 도메인 모델을 강조하는 방법도 나와있습니다.


gist가 파일마다 링크가 생성되면 좋은데.. 그렇게는 안되네요... :)

저작자 표시 비영리 변경 금지
신고
Posted by 용식

crescent에서 색인 설정 파일을 xml로 정의하고 있습니다.

collections.xml인데요... 본래 이걸 그냥 dom4j를 사용해서 읽어서 Map과 기타 필요한 오브젝트를 생성하는

형태로 만들어서 사용하고 있었습니다.


그러다보니.. webpage에서 이 collections.xml설정을 변경하는 기능을 추가하려보니..

저런 형태로는 다루기가 어려울 것 같아서 XML과 POJO의 변환에 관련된 라이브러리를 찾아보다가

XStream을 알게되어 처음 사용해보았습니다.


꽤 오래전부터 많이 사용되던 것 같은데..

왜 몰랐을까요 -_-;


http://xstream.codehaus.org


예제도 잘 나와있습니다.


이걸 사용해서 collections.xml을 변환해본 예제입니다. xml 자체가 그리 복잡하지 않아서..

특별히 어려운 내용은 없습니다.


XStream 사용하시는 분들께서 예제로 보시면 좋을 것 같아서 올려봅니다.


현재 사용되고 있는 xml인데요.. XStream을 사용하기 위해서 각 엘리먼트들을 전부 클래스로 만들었습니다.

여기서는 최상위 Root를 나타내는 CrescentCollections 와 그 하위인 CrescentCollection

그리고 CrescentCollection 하위로 들어가는 CrescentCollectionField, CrescentDefaultSearchField, CrescentSortField가 만들어졌습니다.


indexingDirectory와 analyzer 부분은 CrescentCollection의 field로 들어갑니다.



CrescentCollections.java

XStream의 annotation을 사용하였고요..

@XStreamAlias로 지정된 name 값이 엘리먼트명이 되고..

@XStreamOmitField로 지정된 field는 XML의 변환에서 제외됩니다.


@XStreamImplicit(itemFieldName="collection")
	private List crescentCollections = null;

이 부분은.. <collections></collections>가 하위에 <collection></collection>을 2개 가지고 있는데 그것을 나타내기 위한 설정입니다. 추후 실제 XML로 변환하는 코드에서 추가로 말씀을 드리겠습니다.


getter, setter 메서드는 코드에서는 생략했습니다.

CrescentCollection.java

<collection></collection>이 가지고 있는 항목들을 표한하기 위한 설정들이 들어가있습니다.

@XStreamAsAttribute 이 설정을 가지고 있는 field는 xml에서 속성으로 표현됩니다.

<collection name="sample"> 과 같은 형태로요...




CrescentCollectionField.java

<field></field>는 전부 속성으로 되어있기 때문에 특별한 설정은 없고.. 다만 위 xml예에서는 각 속성이 <field></field>로 조금씩 다른데.. 위와 같이 사용하기 위해서는 필드가 전부 동일해야 하겠죠... 




CrescentDefaultSearchField.java


<defaultSearchField/>나 <sortField/>는 거의 비슷하기 때문에 하나만...

이제 이 XML을 POJO로 변환하는 코드입니다.




Test

위와같이 해주시면 되는데...

processAnnotation은 최상위 클래스만 걸어주시면 됩니다.



저작자 표시 비영리 변경 금지
신고
Posted by 용식
TAG java, Xstream

며칠전부터 영 디버깅이 안되는 부분이 있었다..


파일에서 읽어오는 "nbsp"라는 String과

사용자가 입력한 "nbsp"라는 String이 equals를 하면 false가 나오는 것이었다.


공백이 있나? 로직이 잘못되었나?


해서 이래저래 막 디버깅해보고 바꿔보고 해봐도..

도무지 모르겠었다.


그래서 혹시나해서 파일에 직접 "nbsp"라고 한줄을 더 넣었다.


그랬더니, Map의 키에 nbsp가 두개가 생겼다.!

뭐여 이게..??




혹시나해서 원래있던 nbsp를 지우고 새로 입력해 넣었더니

정상작동을 한다. 뭔 상황인지도 모르고 상황이 해결되어버려서 그냥 놔둘까하다가..

문득, 혹시..? 해서 각 char의 유니코드 값을 찍어보았다.


                        D : 65279  <- ??? 응????

F : 110

D : 110

F : 98

D : 98

F : 115

D : 115

F : 112

D : 112


맨 앞에 110이 아니라 뭔가 큰 값이 나왔다.!


뭔가해서 찾아보니..

ZERO WIDTH NO-BREAK SPACE

란다..


단어도 처음들어본다..--; 암튼 이거 덕분에 며칠을 삽질했는데..

그래도 원인을 찾아서 다행이지 싶다... 아오..ㅠㅠ

저작자 표시 비영리 변경 금지
신고
Posted by 용식

DB에서 데이터를 읽어와서 네트워크를 통해 뭔가 작업을 한 후

다시 DB에 넣는 작업을 해야하는데 이 데이터의 건수가 많고 네트워크를 통한 작업에 시간이 좀 걸려서

이 부분을 스레드로 돌렸다.


기존에 알고 있는



Executor exec = Executors.newFixedThreadPool(10);


을 사용해서 실행을 했더니 DB에서 데이터 읽어오는 속도가 훨씬 빠른탓에

OOM 에러가 발생하기 시작... 처음에 도무지 왜 에러가 나는지 몰랐는데 확인해보니..

내부에서 스레드들이 처리하지 못 한 JOB을 Queue에 저장해 두는데 이게 너무 쌓이다보니

문제가 되었던듯 하여... 


자바병렬처리 프로그래밍 책을 다시 집어들었다.


미리 준비된 ExecutorService중 스레드가 추가 작업을 하지 못 할 때 

wait을 하는 API는 없다고 하여... 책을 더 뒤적거리고... ..

결국 세마포어를 활용한 BoundedExecutor라는 것이 있어서 이걸 살짝 고쳐서 사용.




다만...

semaphore의 release를 catch에서만 해주고 있어서

Runnable command에서 작업 종료 후 release 해주지 않으면 lock이 발생한다.


책에서는 Semaphore를 생성자에서 생성하도록 되어있는데

이런 경우 어떻게 Runnable command에서 작업 종로 후에 semaphore를 release 해줄 수 있는지

잘 모르겠어서... Semaphore를 외부에서 생성하고 Executor와 Runnable command에게 넘겨주는 방식으로

수정하였다.


저작자 표시 비영리 변경 금지
신고
Posted by 용식

http://ir.bagesoft.com/640


저작자 표시 비영리 변경 금지
신고
Posted by 용식
요즘 회사에서 RabbitMQ를 사용하여
메시지 처리 프로그래밍을 하고 있습니다. 다른 개발자분과 함께 개발 중인데
저는 Consumer 역할을 하는 데몬을 구현중이네요.

생산자-소비자라는 것이 상대적인 부분이 있어서
MQ를 중심으로 제가 개발 중인 데몬은 소비자가 되지만...
제 데몬을 중심으로는 이 소비자가 다시 생산자가 되는 그런 개념이 됩니다.

아무튼 MQ로부터 메시지를 가져오고
그것을 내부 Queue에 저장하여 이런저런 할 일들을 구현을 해야하다보니
데몬안에서도 또 다시 생산자-소비자 패턴의 모델이 되어버렸습니다.

이를위해 Java에서 제공되는 BlockingQueue를 사용하였습니다.

"자바 병렬처리 프로그래밍"이란 책에서는 이 Queue가 생산자-소비자 패턴을 구현하는데
아주 좋은 Queue라고 소개가 되어있습니다.

그래서 기본적인 사용법을 작성해보려고 합니다.

 Producer.java

위 소스가 생산자 역할을 하는 소스입니다. queue를 가지고 있고
이 queue에 900ms에 한번씩 msg를 생성하여 집어 넣습니다.


Consumer.java

Starter.java
실행소스입니다.
두 스레드가 사용 할 queue를 생성 후 스레드를 실행합니다.

각 스레드의 loop 간격을 조절해가면서 이런저런 테스트를 해보시면
좋을 것 같습니다.

몇가지 특징을 소개해드리면...

1. BlockingQueue를 생성 할 때 인자로 들어가는 int 파라메터는 fixed capacity를 뜻 합니다.
producer가 queue에 msg를 넣는 속도가 너무 빠르거나 해서 저 한계를 넘어가버리면 exception이 발생합니다.
다만, BlockingQueue의 다른 구현 클래스인 LinkedBlockingQueue()를 사용하시면 capacity와 상관없이
계속 queue를 채울 수 있지만.. 무한대로 queue가 쌓이는 것은 피하는 것이 좋겠죠..

####### 3월 2일 내용추가 #########
커멘트로 풍주형님께서 지적해주신 내용입니다.

api 문서에서는 아래와 같이..

BlockingQueue.add 
Inserts the specified element into this queue if it is possible to do so immediately without violating capacity restrictions,
returning true upon success and throwing an IllegalStateException if no space is currently available.

BlockingQueue.put
Inserts the specified element into this queue, waiting if necessary for space to become available.



add와 put의 동작 방식이 다르게 설명이 되어있습니다. 위 예제에서도 Linked... 를 사용하시는 대신
put 메서드를 사용하시게 되면 queue에 자리가 생길때까지 기다리게 된다고 하네요.


2. Consumer에서 사용하는 take() 메서드는 queue가 비어있으면 기다립니다.
그리고, queue가 채워지면 실행이 되는 구조 입니다. Socket의 accept를 생각하시면 되겠네요..


저작자 표시 비영리 변경 금지
신고
Posted by 용식