Spring Framework 4.0 안내

스프링 프레임워크가 3.0이 출시되고 4.0으로 버전업 하기까지 4년 가까운 시간이 흘렀습니다. 스프링 프레임워크의 프로젝트 리더인 Juergen Hoeller는 그의 블로그를 통해 첫번째 마일스톤이 완성되었음을 알렸습니다.
첫번째 마일스톤의 결과물의 다운로드 링크는 아직 제공하지 않았습니다. 
스프링 4.0의 테마는 Java SE8(아마도 Open JDK 8 build 88 이후 버전을 base로 작업하고 있는듯) 과 Java EE 7의 지원과 몇가지 사용성 기능 추가로 보입니다.

Juergen는 JAVA SE 8에 대한 지원이 개발되고 있으며 JDK 8 developer preview의 출시에 맞춰 2013년 9월경에는 release candidate 출시를 예상하고있습니다. 올 9월에있을 SpringOne에서 소개할 예정입니다.

다음과 같은 Java se 8의 기능이 지원됩니다
JSR-335(새 창으로 열기) Lambda expressions.
JSR-310(새 창으로 열기) Date-Time value types for Spring data binding and formatting.
Support for the new 1.8 byte code format (람다 표현식 지원을 위해 필요).

다음 JEE 7 기능 지원도 포함됩니다.
JSR-343(새 창으로 열기) JMS 2.0.
JSR-338(새 창으로 열기) JPA 2.1.
JSR-349(새 창으로 열기) Bean Validation 1.1.
JSR-236(새 창으로 열기) Java EE 7 Enterprise Concurrency support.
JSR-356(새 창으로 열기) Spring's WebSocket endpoint mode.


http://www.infoq.com/news/2013/06/Spring_Framework_4.0_Announced(새 창으로 열기)

2013/07/08 13:03 2013/07/08 13:03
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

Hibernate의 generated query와 MSSQL의 nolock 힌트에 대한 고찰

하이버네이트와 같은 OR매핑 도구를 이용하게되면 개발자가 SQL 를 작성할 필요가 없어지고 ( 물론, createSQLQuery() 메소드를 통해 native query를 작성할 수 있지만 이번글의 주제와는 조금 다른 이야기이니 제쳐두자. ) OR매퍼에서 생성된 쿼리가 실행되는데 MSSQL과 hibernate를 이용할때는 한 가지 특수한 상황에 맞딱드리게 된다.

바로 select lock.
MSSQL, Sybase, DB2는 여타 DBMS와는 달리 select 쿼리에도 row level lock ( 트랜젝션이 몰리면 이 lock도 에스컬레이션해서 row -> page -> table lock으로 범위가 확대 )을 거는데 일반적인 web application을 개발하는데 select lolock은 DB성능을 떨어트리는 원인이되기때문에 대게 select 쿼리에 각 테이블에 with(nolock) 힌트를 줘서 락을 걸지 않도록 처리한다.

이제 Hibernate로 돌아와서, hibernate에 의해  generate된 쿼리에는 with(nolock) 옵션이 기본 적용이 되지 않는다.  MSSQL에서 그냥 이용해도 하이버네이트 캐시시스템의 덕으로 문제가 발생하지 않을 수도 있지만 쿼리 실행 시 부하를 줄일 수 있는 방안이 있다면 적용하지 않을 이유가 없다.

이와 같은 내용은 검색 엔진에 hibernate mssql nolock 등의 키워드로 찾아보면 많은 결과를 확인할 수 있다. 그 중에 https://forum.hibernate.org/viewtopic.php?f=1&t=934158 의 쓰레드를 통해 확인한 방법은 다음과 같다.

session.connection().setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);


물론, MSSQL의 READ COMMITTED 격리수준 등 더 깊이있는 주제들도 있지만 내가 DB Geek도 아니고... 프로그래머 입장에서 요 정도까지만..
2012/06/12 18:27 2012/06/12 18:27
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

제임스 고슬링 구글로 이적

자바의 아버지 제임스 고슬링 아저씨가 구글로 그 자리를 옮겼다고 합니다. 뭐 썬이 오라클로 넘어가면서 자연스레 오라클 소속이 되었다가 작년에 그만두었죠(http://kldp.org/node/114063(새 창으로 열기)). 일년의 공백 후 구글로 입사한 거니 딱히 자리를 옮겼다고 표현하기에도 뭐하지만요. 오라클의 자바 및 오픈소스 지원정책에 불만이 있었기에 오라클을 그만둔 그의 다음 포지션을 많은 이가 궁금해 했을 겁니다. IBM 정도가 아닐까 예상했는데.. 구글로 가는군요. 구글의 비공개 직위로 간다는데 이게.. 오라클과의 특허 분쟁 방어용으로 가는건지 혹은, 자바나 또다른 언어를 위한 것인지는 아직 알려진 바는 없습니다. 그의 강연이나 이전까지 보여준 독설이나 자바 옹호 행위에서 느낀 것은 고슬링아저씨가 위대한 사람이긴 해도 성인군자 스타일은 아니란 거죠. 오라클을 엿먹이기 위해 구글과 손잡았을 가능성도 전혀 배제하진 못하겠네요. 그 정도 창의력이 있는 사람이라면 앞으로도 혁신적인 일로 인류에 공헌하면 좋겠어요.
2011/03/29 12:26 2011/03/29 12:26
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

InputStream.read()

제가 만든 서버에서 보낸 데이터가 xml 형식으로 바이트 스트림으로 해서 받는데 in.read로 받았더니 byte 버퍼에 태그단위로 하나씩 들어가는데다가 디버그해봤더니 in.read라는 문장은 받은 xml 태그 수만큼 반복해서 실행되고 전체 xml을 받아서 파싱하려고 Stringbuffer를 이용해서 append 하려고 했더니 이것도 안되네요..

안녕하세요 질문자님.
질문 내용을 제가 정확히 이해한 건진 모르겠습니다만 제가 이해한 내용은
보내는 서버 측에서는 예를 들어, "<tag>내용</tag>" 스타일의 문자열을  byte[]로 변환하여
outputStream.write( byte[] );
하고 있고 클라이언트 측에서는

while ((readLength = inputStream.read(input, 0, input.length)) != -1) {
    stringBuffer.append(  new String( input )  );
}

과 같은 동작을 하고 있다고 생각이 됩니다.

질문 내용 중 ' in.read라는 문장은 받은 xml 태그 수만큼 반복해서 실행되고' 라고 하신 걸로 미루어보아 데이터는 정상적으로 들어오고 있다고 판단됩니다. 받은 데이터를 가공하는데 어려움을 느끼고 계신 건 아닌가 하는 생각이 드네요.

우선 작성하신 클라이언트 쪽이 서버에서 보내주는 xml을 다 받으면 while 문을 빠져 나오는지 확인해 보시고요. 정상적으로 while문을 빠져 나온다면 유입된 Data를 가공하는 문제가 될 거고 그렇지 않다면 서버 측의 outputStream 에 write() 하는 부분을 확인하셔서 stream을 확실히 끝내고 있는지 확인하셔야 할 것 같습니다.

참고로 제가 작성한 소스를 첨부합니다.
첨부한 소스는 xml 형식의 문서를 읽어들여 byte 형식으로 전송하여 수신부에서 file과 문자열로 복원하는 코드가 작성되어 있습니다. Server.java 와 Client.java 는 일반적인 자바 bolocked Socket 프로그래밍 방식을 취하고 있습니다. 실제로 확인해야 하는 부분은 ByteArrayTransporter 클래스에서 클라이언트에 Data를 전송하는 부분과 Client 클래스에서 java.nio.ByteBuffer 를 이용하여 입력 데이터를 처리하는 부분 정도가 될 거 같습니다.


ByteArrayTransporter.java
   byte[] byteArray = new byte[1024];
   int readLength = 0 ;
   while ( (readLength = fileInStream.read(byteArray, 0, byteArray.length) ) != -1 ){
     out.write(byteArray, 0, readLength);
   }
   out.flush();
   out.close();  //<-- 스트림 끝내기


Client.java
   ByteBuffer bBuffer = ByteBuffer.allocate(102400);
   while ((readLength = bin.read(input, 0, input.length)) != -1) {   //byteBuffer에 byte[] 쓰기
      bBuffer.put(input, 0 ,readLength );
   }   //ByteBuffer 에 담긴 문자열 확인 
   System.out.println( new String(bBuffer.array() , "UTF-8" ) );

2010/07/20 19:54 2010/07/20 19:54
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다
  1. 다른 문제로 구글링하다가 들리게 되었는데, 좋은 글 잘 읽었습니다.

    이 페이지에 어울리지 않을지는 모르나 도움을 주실 수 있을 듯하여 한 가지 질문 드리겠습니다.

    <질문> 삼성 갤럭시폰에서 파일도 존재하고 파일크기도 0이 아닌데 FileNotFoundException 에러 나타나는 문제

    구글링해도 제 힘으로 답을 구하지 못해 도움을 청합니다.

    도와주시면 정말로 감사하겠습니다.

    1. 테스트 환경 : 폰(삼성 갤럭시S3/갤럭시S5), 파일(MMS에 첨부된 .vcf 주소록파일), 안드로이드 스튜디오 2.3, 윈7(64비트)

    아래 코드의 실행 결과 : "파일 OK/2025bytes/주소록 내용을 읽을 수 없습니다."

    즉 exists 메소드로 검사하면 파일도 존재하고, length 메소드로 검사하면 파일크기도 0이 아니므로 분명 존재하는 파일입니다.

    그런데 BufferedReader/readLine으로 파일을 읽으면 FileNotFoundException 에러를 내고 파일 내용을 읽지 못합니다.

    다른 테스트 폰 엘지 G2에서는 정상으로 읽힙니다.

    // 주소록 보이기
    public void viewVcf(final String filePath) {
    File vcfFile = new File(filePath);
    if (vcfFile.exists()) {
    long lFileSize = vcfFile.length();
    tv_unique.setText("파일 OK/"+lFileSize+"bytes");
    String content = readFile(filePath);
    if (content.isEmpty())
    tv_unique.setText(tv_unique.getText().toString()+"/주소록 내용을 읽을 수 없습니다.");
    else {
    ...
    }
    }
    else {
    report10sec("주소록 파일이 없습니다.");
    }
    }

    2. 테스트 환경 : 폰(삼성 갤럭시S3/갤럭시S5), 파일(MMS에 첨부된 .mp4 동영상파일), 안드로이드 스튜디오 2.3, 윈7(64비트)

    동영상 파일의 경우도 위와 비슷합니다.

    "파일 OK/707989bytes"

    // 비디오 재생
    public void viewVideo(final String filePath) {
    File videoFile = new File(filePath);
    if (videoFile.exists()) {
    long lFileSize = videoFile.length();
    tv_unique.setText("파일 OK/"+lFileSize+"bytes");
    ...
    }
    else {
    report10sec("비디오 파일이 없습니다.");
    }
    }

    위 ... 부분의 코드에 따라서 2가지 테스트 결과입니다.

    1) startActivity(intent);

    삼성폰, 엘지폰 모두 비디오가 재생되지 않습니다.

    (엘지) java.lang.NullPointerException: Attempt to invoke virtual method 'android.app.ActivityThread$ApplicationThread android.app.ActivityThread.getApplicationThread()' on a null object reference

    (삼성) java.lang.NullPointerException

    2) videoView.start();

    엘지폰에서는 정상으로 재생이 됩니다.

    삼성폰에서는 에러 로그는 없으나, "재생할 수 없는 동영상입니다./확인" 메시지가 뜨고 비디오가 재생되지 않습니다.

    읽어 주셔서 고맙습니다.

  2. Blog Icon
    김병희

    <답변> 존재하고 크기도 있는 파일의 FileNotFoundException = 권한 없음/[Android] http://blog.daum.net/andro_java/1121

뜻밖에도 JDK7에 Closure가 도입됩니다.

이전 Java 7 로드맵 업데이트와 커뮤니티의 반응.(새 창으로 열기) 포스팅을 통해 JDK7에서의 클로저 누락에 대한 언급을 한 적이 있는데요. 뜻밖에도 JDK7에 클로저를 포함하기로 했다는 뉴스를 접했습니다.

Java SE의 수석 엔지니어 Mark Reinhold는 지난 자신의 의견에 반하여 JDK7에 클로저를 도입하기로 했다는군요. JDK 출시 일정은 조금 지연되어 2010년 9월께가 될 듯합니다.

Coin 프로젝트(새 창으로 열기)의 수석 엔지니어인 Joseph D. Darcy는 다음 버전의 JDK7에는 BGGA의 제안(새 창으로 열기)과 유사한 방식의 "경량의" 클로저가 포함(새 창으로 열기)되며 Java 7에서 약간의 언어상 변화가 있을 것이라고 말했습니다.

썬은 java 클로저에 회의적이었지만 자바 커뮤니티는 이미 3가지의 클로저 구현 방법을 제안(새 창으로 열기)했었습니다.
2009/12/04 15:46 2009/12/04 15:46
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

JDK 7 에서 기본 제공했으면하는 메소드는?

OpenJDK core-libs-dev 메일링 리스트에 재미있는 쓰레드가 진행되고 있습니다. ( 재미있다고 적긴 했지만 재미있기만 한 것은 아니지만요..)  What methods should go into a java.util.Objects class in JDK 7? 이란 타이틀로 진행 중인 이 쓰레드의 내용인즉, '자바 개발자가 흔히 사용하는 유틸리티 성 메소드를 구현하는 java.util.Objects 같은 클래스를 만든다면 이 Objects 클래스에서 꼭 포함 했으면 하는 메소드는 무엇인가?' 하는 내용입니다.  썬社의 Joe Darcy로부터 시작된 이 쓰레드에는 많은 회신 메일로 해당 이슈에 대한 자바 개발자의 높은 관심도를 엿볼 수 있습니다.

Darcy는 그의 첫 번째 포스트에서 Null-safe 한 equals(arg1,arg2) 와 모든 primitive type에 대응하는 compareTo(arg1, arg2) 를 제안하고 있네요.

Andrew John Hughes 같은 경우엔 toString(arg) 메소드에 대해 자바 리플랙션을 통하여 해당 객체의 상세를 보여주면 어떻겠냐는 것과 비슷한 방법으로 clone() 메소드도 구현해 버리자는 내용을 제안했습니다.

이 쓰레드가 커뮤니티의 긍정적인 회신을 받고 있기만 한 것은 아닙니다. 이런 내용의 글을 접한 Stephan Oudmaijer 같은 사람은 infoQ의 해당 내용에 대한 기사에 댓글을 통해 stupid idea란 표현과 함께 그런 유틸성 메소드는 jakarta-commons에서 구현하도록 하고 제발 JDK는 그냥 내버려 뒀으면 좋겠다고 표현하고 있네요. ^^;

여러분도 평소에 '아.. 이런 메쏘드는 기본적으로 JDK에 있었으면 좋겠는데...' 하고 생각한게 하나 둘쯤은 있을 거라 생각되는데요.. 해당 메일링 리스트에 가입하셔서 의견을 피력해 보시는것도 재미있을것 같습니다.

2009/09/14 16:26 2009/09/14 16:26
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

자바는 call by value? call by reference?

자바에서 메소드 인자의 전달이 call by value냐 call by reference냐 하는 이야기는 꽤
해묵은 논쟁 중 하나입니다.

java에서 object형을 전달할 때 일견 call by reference 인 것같아 보일 수 있습니다만,
실제로 자바는 primitive, reference 타입 모두 call by value입니다.

아래의 코드가 reference 타입도 call by value라는 사실을 극명하게 보여줄 수 있겠네요.

////// 테스트용 클래스///////
public class TargetClass {
    private String param;    
    
    public String getText() {
        return param;
    }

     public void setText(String param) {         this.param = param;     } }



///// 테스트 시도할 main 클래스/////////////
public class CallByValue {

   public static void main(String[] args){

     CallByValue cbv = new CallByValue();
     TargetClass tc = new TargetClass();
   
     tc.setText( new String("처음 입력 값입니다."));

      System.out.println( " 변경 전 : "+ tc.getText()+" "+ tc.hashCode() );      //아래 코드에서 tc변경을 시도합니다.      cbv.changeObject(tc);      //이후 내용을 찍어볼까요? tc에 변화가 없다면 call by value일테고      //변화가 있다면 call by reference이겠죠.      System.out.println( " 변경 후 : "+ tc.getText()+" "+ tc.hashCode() );    }    public void changeObject( TargetClass obj){      //넘어온 인자를 null 처리합니다.      obj = null;    } }

자바 레퍼런스타입이 정말 call by reference에 의한 전달이라면 changeObject( TargetClass obj)이
수행되고 나면 tc는 null 이어야 하지만 그렇지 않죠. 실제로 자바도 reference type을 인자로 전달할
때에 reference를 넘기지만 바로 그 reference가 아니라 reference의 사본의 값을 넘기므로 진정한
의미에서 call by reference로 볼 수 없으며, 이는 위 코드로도 충분히 증명이 되고 있습니다.

사실, 자바에서 인자 전달이 call by value냐 call by reference냐 하는 해묵은 논쟁보다는 실제로 어떻게
인자가 전달되는지 이해하고 코드를 작성하는 게 더 중요하겠지요.

추가 : http://pungjoo.tistory.com/8(새 창으로 열기) 아티클에는 finalize()메소드를 이용하여 call by value임을 증명하고있네요.

2009/03/27 21:11 2009/03/27 21:11
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다
  1. Blog Icon
    비밀방문자

    관리자만 볼 수 있는 댓글입니다.

  2. Blog Icon
    코딩 지겹다

    그냥 가려다...

    call by value 증명으로 obj 에 null 을 대입했는데..
    obj = null; 대입하지 말고 obj.setText("변경전")
    이렇게 대입해보면 tc 값이 바뀌는걸 알 수 있습니다.

    레퍼런스 변수(참조변수)을 함수의 인자로 넘기면 힙에 저장된 실객체는 복사를 안합니다. 참조 값만 넘겨주지요..

    call by value 냐 call by value냐 call by reference 냐가 중요한게 아니라
    함수의 인자로 변수가 넘어 왔을 때 그 변수를 통해서 실객체의 값을 변동할 수 있느냐 못하냐 입니다.

    위에서는 변동할 수 있다가 정답입니다.

    다른 초보 개발자가 이글 보고 잘 못 인식할까봐 몇 자 적었습니다.

  3. Blog Icon
    지나가다

    메소드에 인자 전달할때는 래퍼런스를 복제해서 넘긴다고 알고있는데 아닌가요?

    테스트 결과는 당연한데 풀이가 아리송 하군요.

  4. Blog Icon
    Lele

    jvm의 동작과관련하여 좀 더 공부해 보셔야 할듯하네요... 게다가 Java의 대표적인 Immutable 객체 String을 call by value, call reference 의 예로들고 있는 점 또한 큰 오류라 생각합니다. 지나가다.....

  5. Blog Icon
    지나가는

    잘알고 포스팅 하세요.완벽히 잘못된 예제 입니다

  6. Blog Icon
    지나가는

    맞는 포스팅인 것 같은데 뭐가 잘못되었다는건지?

  7. Blog Icon
    행인13

    잘못된 예제가 이에용


    http://trypsr.tistory.com/74
    이 글을 참고 하세요.

  8. Blog Icon
    컴돌이

    제대로 된 예제가 맞는데요..
    call by reference는 결국 주소값이 call by value로 전달되기 때문에 발생하는거죠.

  9. Blog Icon
    대박

    그렇게 따지면 C언어도 Call by value인 셈이 되는 겁니다.
    포인터의 값도 결국은 값을 넘기는거니까요.

    call by reference의 의미는 해당 변수의 주소 값을 인자 값으로 넘기는 것을 의미 합니다.
    위의 예제에서도 tc의 주소값을 넘기게 되므로 call by referece가 됩니다.

  10. Blog Icon
    대박

    cbv.changeObject(tc);
    를 통해,
    public void changeObject( TargetClass obj)
    obj가 tc의 주소값을 가지게 되어
    obj의 내용을 수정하게되면 tc의 내용도 수정되겠지만
    obj = null;을 하게되면
    obj가 가르키는 주소값이 null 값으로 바꾸게 되어 가리키는 곳을 잃게 됩니다.
    윗분들 말대로 잘못된 예제이며 tc.setText로 해서 문자열을 변경하는걸로 테스트 하는게 옳은 걸로 보입니다.

  11. Blog Icon
    속터지는행인

    결론요약, 아래 링크 참고
    http://stackoverflow.com/questions/17419257/does-java-use-call-by-value-or-call-by-reference
    -----------------------------------------------------
    http://trypsr.tistory.com/74 // 파워 오답
    위 블로그 주소글처럼 이해하고 c++ 넘어와보세요.
    c++의 *와 &만나는순간 오지게 털리니까.
    현재 블로그글이 올바르게 이해한 예제입니다. 프로그램 한번만 짜서 돌려보면 버그 나서 탈탈 털리겠구만, 탁상공론으로 올바른 글 잘못된 예제라고 몰아붙이는 사람들때문에 글 올립니다.

    행인13/Lele/지나가는/대박님이 올린글은 잘못된 글입니다. c/c++에서 & 선언의 의미를 제대로 이해하지 못한거 같군요. 그 중에서 대박님은 c/c++의 개념조차 흔들리고 계시네요.
    c/c++에서의 changeObject( TestClass* a );
    의 경우 call by value가 맞습니다.
    changeObject( TestCalss& a );
    의 경우는 call by reference 입니다.
    혹시나 물어보겠습니다.
    changeObject( TestClass*& a ); 는 c/c++에서 call by value 일까요 call by reference일까요? call by reference입니다. 포인터의 레퍼런스입니다. 바로위의경우는 클래스 인스턴스의 레퍼런스이고, 맨위는 클래스 인스턴스의 포인터값입니다.

    첨언하자면, 자바에는 레퍼런스할 수 있는 방법을 제공조차 하지 않기 때문에 이해가 힘들고 다른 언어와 같이 비교하셔야 이해가 가능합니다. ( c#은 ref라는 명령어로 존재하지만 java에는 레퍼런스 연산자 자체가 없습니다. 자바에서 c/c++의 &에 해당하는 연산자가 있던가요? )
    3차원을 사는 저희가 4차원의 모습을 상상하지 못하듯, 레퍼런스개념이 없는 자바만으로는 이해가 불가능합니다.
    그리고 현인이 달을 가리키는데 손가락만 보고있네요. 이글의 핵심은 내가 원하는 instance의 멤버변수들을 제대로 변화시키는게 중요하지 call by value냐 call by reference냐 그게 중요하다고 적은글이 아닙니다. 동작 원리를 이해하는게 더 중요합니다. 그래야 내가 원하는 동작을 얻어낼수있으니까.

    2003년에도 올라온 참으로 해묵은 논쟁이네요.
    http://okjsp.net/seq/32431

  12. Blog Icon
    들개

    하아.. 이거 신기하네요. 저도 저게 call by reference 라고 생각해왔는데.. 이 글을 보고 테스트 해보니 실제로 (주소)값 복사가 이루어지는군요.

    아마도
    1. tc의 실제 값을 저장한 메모리 공간이 있고
    2. tc는 그 메모리 공간에 대한 주소값을 값으로 가진 변수이고
    3. changeObject()의 인자로 들어온 obj 변수는 새로 생성된 변수이고
    4. obj 변수에는 tc의 실제 값의 메모리 주소값에 대한 복사가 이루어진다.

    이해는 한 듯한데, 하나 궁금한 것은 왜 자바가 이런식으로 구현되었을까 하는 점이네요..
    이렇게 함으로써 얻는 장점이 있을텐데 말이죠.

    잘보고 갑니다.

  13. Blog Icon
    개발 종사자

    8년전 글이네요.
    작성자분도 그만큼 경험이 생기셨으니 이제는 이해하시겠지만 몇 자 적어봅니다.
    자바의 기본동작이 PBV니 PBR하는 글은 이미 수도없이 바왔습니다.
    실재로 많은 전문가들이 PBV라고 확인했기에 이에 토를 달고 싶지는 않네요.
    그런데 자바를 실재로 사용해보면 PBR처럼 동작하는 경우를 많이 보 실 수 있습니다.
    이상하지요.(ㅎㅎ웃음) 네 저도 이상하다고 생각합니다. 어던 메카니즘으로 움직이길래 이럴까요?
    솔직히 저도 잘 모릅니다. 다만 오브젝트를 상속받은 객체들에게서 자주 보입니다.
    이제는 동작방식을 놓고 싸우지 마시고 자바의 동작원리를 이해하시면 됩니다.
    primitive 타입의 변수와 immutable 객체들은 실 데이터들을 직접 가지고 있는 녀석들이죠.
    다른 데이터를 할당하면 객체가 새로 생성되어버립니다. 이전의 값들은 어딘가에서 떠돌다가 GC에 의해서 사라져버립니다.
    list나 map같은 주소를 기반으로 동작하는 객체들은 좀 다릅니다.
    변수의 목적이 값을 저장하기 위함인데, 제 생각으로는 값을 저장하기 위한 목적 보다는 값들을 저장하거나 또는 값들간의 관계를 연결하기 위함이라고 생각합니다.
    때문에 위와같은 객체들은 PBR처럼 보입니다. PBR이라고 생각해도 됩니다. 프로그래밍을 해보면 그렇게 동작하거든요.
    각 변수들이 동작하는 방식을 이해하고 적당한 방법으로 그것을 사용할 줄 아는게 더 중요하다고 생각합니다.
    어차피 PBV, PBR 개념을 알고 그에 맞게 사용하면 되는거고, 각 변수들이 어떤식으로 동작하는지 알면 되는겁니다.

스트럿츠 2.1 릴리즈!! Committer 인터뷰

스트럿츠 2.1.이 릴리즈 되었습니다. 요즘 MS쪽 어플리케이션 개발 프로젝트를 하고있지만 여전히 자바쪽 흐름을 읽는것도 게을리 하고 있지 않습니다만, 쉽지 않네요.

스트럿츠 2.1은 많은 양의 코드를 Plug-In Framework로 옮기는 리펙토링, Convention plug-in에 의한 XML 설정 감소, 향상된 REST 지원에 초첨을 두고 진행되었습니다.

InfoQ에서 스트럿츠2 커미터인 Musachy Barroso씨와 인터뷰한 기사가 올라와서 포스팅 합니다.

2.0과 2.1의 차이점은 무엇인가요?
많은 수의 버그픽스가 있었습니다. 그리고 REST, Convention, Java Template과 같은 플러그인이 추가되었습니다.

많은 기능이 플러그-인 형태로 변경되었습니다. 이렇게 한 이유는 무엇인가요?
스트럿츠 코어에는 진정한 core만을 남기자는 아이디어에서 출발했습니다. 그리고 나머지는 플러그인에 집어 넣는거죠. 이렇게 하면서 코드의 유지보수가 쉬워 졌습니다. 그러면서 Dojo 플러그인 같은 것들은 더 이상 스트럿츠에서 지원하지 않습니다. 이런 변화는 제거된 플러그인을 사용하지 않는 개발자와 작은 footprint를 원하는 개발자 이외의 사람에게 직접적인 장점은 없습니다.
 
Ajax 태그를 depreciate 한 이유는 무엇인가요?
Struts2의 ajax 태그는 Dojo 0.4.x에 기반하고 있습니다. 그것을 Dojo의 최신버전에 맞춰 포팅하는것은 모든 ajax 태그의 코드를 다시 작성해야한 다는것과도 같은 이야기입니다. Dojo의 새로운 버전은 너무 빨리 출시되고 마이너 버전에서도 변경되는 코드의 양이 너무 많습니다. 태그가 Dojo의 모든 기능을 다 포함하고 있지 않기때문에 개발자는 주로 Dojo 라이브러리를 직접 사용하는 경향이 있습니다. 이런 이유들과 ajax 태그 개발 지원자의 부족으로 ajax 태그를 depreciate 했습니다.

어떤 이유로 CodeBehind 플러그인들을 Convention 플러그인으로 바꾸게 되었나요?
Convention은 외부 프로젝트였고 늦게 Struts에 추가되었습니다. Convention은 좀 더 빠른 ClassPath Scanner, 더 나은 Configuration elements, 로깅, 다양한 configuration 옵션, configuation reloading, 더 나은 문서화 등을 지원합니다.

Java Template 플러그인은 무엇인가요?
Java Template은 FreeMarker를 이용하여 java만으로 구현한 'simple theme' 구현체입니다. 이 플러그인의 태그는 재작성이 불가능한 약점이 있는 원래의 그것보다 4~5배 가량 빠르게 동작합니다.

다른 많은 Web Framework가 있는데 우리는 왜 Strtus2를 선택해야 하나요?
스트럿츠2는 아마도 가장 약한 커플링(loosely-coupled)으로 구현된 프레임워크일 겁니다. 많은 기능이 커스터마이징 없이, 혹은 약간의 커스터마이징만으로 사용할 수 있으며, 프레임워크를 익히기가 쉽습니다. 약한 커플링은 스트럿츠의 실체에 대한 지식 없이도 비지니스 로직을 작성 할 수 있도록 해 줍니다. 그러면서도 스트럿츠는 대용량 트래픽을 발생하는 사이트에서 유연한 확장성을 담보하고 있다는 점입니다.

마지막으로 한마디.
스트럿츠 2.1 출시까지 오랜 기간 공을들였습니다. 우리는 스트럿츠 프레임워크의 빌드와 릴리즈 프로세스 개선을 위해 정말 열심히 일하고 있습니다. 앞으로는 좀 더 짧은 주기로 새로운 버전이 릴리즈 되는것을 기대하셔도 좋습니다.
2009/02/03 16:37 2009/02/03 16:37
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

double 값을 문자열 형식의 퍼센트값으로 변환하기

2008/08/01 23:09

서비 JAVA , , ,

double을 퍼센트(%)로 표현하기위해 여러가지 방법을 이용할 수 있지만  java.text 패키지의 NumberFormat 클래스
API를 이용하면 아래와 같이 간단히 double값을 퍼센트 문자열로 변환할 수 있다.

package javacodesnipet;

import java.util.Locale; /**  *  * @author 신윤섭  */ public class NumberFormatPercent {  public static void main(String[] args){       //아래 double 값을 퍼센트 문자열로 표현해 보자     double value = 0.343234532d;     //NumberFormat 객체로 부터 PercentInstance를 얻어온다.     java.text.NumberFormat pformat = java.text.NumberFormat.getPercentInstance(Locale.KOREA);     //퍼센트로 표현할 소수점 이하의 자리수를 정한다.     pformat.setMaximumFractionDigits ( 4 );     //자... 이제 double을 String형식의 퍼센트로 변환하자.     String sPercent = pformat.format ( value);     //값을 확인 해 보자 -> 34.3235% 과 같이 표현 된다.     System.out.println(sPercent);     } }

2008/08/01 23:09 2008/08/01 23:09
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

자바 파일복사 코드와 성능 2 :: Java File Copy Code & Perfomance Issue. part 2

2008/07/13 21:21

서비 JAVA , , , , , ,

지난 포스트를 통해 자바로 파일을 복사하는 몇가지 방법을 알아보았다.
이번시간에는 각 코드의 성능을 간단히 확인해 보고자 한다.

/*
 * author 신윤섭
 */
package filecopy;

import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException;

/**  * Stream을 이용한 파일복사 코드 스니핏  * @author 신윤섭  */ public class StreamCopy {

 /**   * source에서 target으로의 파일 복사   * @param source   * @param target   */  public void copy(String source, String target) {   //복사 대상이 되는 파일 생성   File sourceFile = new File( source );     //스트림 선언   FileInputStream inputStream = null;   FileOutputStream outputStream = null;     try {    //스트림 생성    inputStream = new FileInputStream(sourceFile);    outputStream = new FileOutputStream(target);        int bytesRead = 0;    //인풋스트림을 아웃픗스트림에 쓰기    byte[] buffer = new byte[1024];      while ((bytesRead = inputStream.read(buffer, 0, 1024)) != -1) {     outputStream.write(buffer, 0, bytesRead);    }       } catch (Exception e) {    e.printStackTrace();   }finally{    //자원 해제    try{     outputStream.close();    }catch(IOException ioe){}    try{     inputStream.close();    }catch(IOException ioe){}   }

 } }


/*
 * author 신윤섭
 */
package filecopy;

import java.io.File; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException;

/**  * Buffer를 이용한 파일복사 코드 스니핏  * @author 신윤섭  */ public class BufferCopy {

 /**   * source에서 target으로의 파일 복사   * @param source   * @param target   */  public void copy(String source, String target) {   //복사 대상이 되는 파일 생성   File sourceFile = new File( source );     //스트림, 버퍼 선언   FileInputStream inputStream = null;   FileOutputStream outputStream = null;   BufferedInputStream bin = null;   BufferedOutputStream bout = null;     try {    //스트림 생성    inputStream = new FileInputStream(sourceFile);    outputStream = new FileOutputStream(target);    //버퍼 생성    bin = new BufferedInputStream(inputStream);    bout = new BufferedOutputStream(outputStream);        //버퍼를 통한 스트림 쓰기    int bytesRead = 0;    byte[] buffer = new byte[1024];    while ((bytesRead = bin.read(buffer, 0, 1024)) != -1) {     bout.write(buffer, 0, bytesRead);    }

  } catch (Exception e) {    e.printStackTrace();   } finally {    //자원 해제    try{     outputStream.close();    }catch(IOException ioe){}    try{     inputStream.close();    }catch(IOException ioe){}    try{     bin.close();    }catch(IOException ioe){}    try{     bout.close();    }catch(IOException ioe){}   }  } }


/*
 * author 신윤섭
 */
package filecopy;

import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.nio.channels.FileChannel; import java.io.IOException;

/**  * NIO Channel을 이용한 파일복사 코드 스니핏  * @author 신윤섭  */ public class ChannelCopy {

 /**   * source에서 target으로의 파일 복사   * @param source 복사할 파일명을 포함한 절대 경로   * @param target 복사될 파일명을 포함한 절대경로   */  public void copy(String source, String target) {   //복사 대상이 되는 파일 생성   File sourceFile = new File( source );

  //스트림, 채널 선언   FileInputStream inputStream = null;   FileOutputStream outputStream = null;   FileChannel fcin = null;   FileChannel fcout = null;

  try {    //스트림 생성    inputStream = new FileInputStream(sourceFile);    outputStream = new FileOutputStream(target);    //채널 생성    fcin = inputStream.getChannel();    fcout = outputStream.getChannel();        //채널을 통한 스트림 전송    long size = fcin.size();    fcin.transferTo(0, size, fcout);

  } catch (Exception e) {    e.printStackTrace();   } finally {    //자원 해제    try{     fcout.close();    }catch(IOException ioe){}    try{     fcin.close();    }catch(IOException ioe){}    try{     outputStream.close();    }catch(IOException ioe){}    try{     inputStream.close();    }catch(IOException ioe){}   }  } }



이상의 샘플코드를 이용하여 700Mbytes 짜리 파일을 5번 복사하여 그 시간을 측정해 본 결과는 아래와 같다.
테스트는 Win XP Pro sp3, Intel Core2 Duo 2GHz, 2Gbytes, 5400rpm의 노트북용 HDD 에서 JDK 1.6.0_06
을 이용하여 이루어졌다.

결과는 아래와 같다.

스트림을 이용한 파일 카피

Stream을 이용한 파일 복사


버퍼를 이용한 파일 카피

Buffer를 이용한 파일 복사


채널을 이용한 파일 카피

Channel을 이용한 파일 복사



프로파일러를 이용하여 측정한 값이기 때문에 프로파일러의 처리량 만큼의 차이는 있겠지만 상대적 성능 비교
에는 문제가 없으리라 생각 된다.
실측에서도 예상대로 Stream , Buffer, Channel 순으로 파일 복사 시간이 줄어들고 있음을 볼 수있다.

이번에는 조금 더 들여다 보기로 하자. 700m짜리 파일을 한번 복사하는데 어떤 클래스와 메소들이 참여하고
있는지, 그리고 메소드가 몇번이나 호출되고 있는지 확인 해 보는것도 재미있을 것이다.

스트림이용

FileInputStream.read()실행에 대부분의 시간을 소비하고 있다.


스트림을 이용한 파일복사이다. FileInputStream.read()메소드가 71만여번 호출되고있으며 실행시간의 대부분을
이 메소드를 실행 하는데 소비하고 있음을 알 수 있다.

버퍼이용

Stream보다는 나아졌다고는 하나 역시 read()메소드가 대부분의 실행시간을 소비하고 있다.


Buffer를 이용한 방법. 위의 Stream을 이용한 방법에 비해 수행시간이 약간은 줄어들었지만 이는 Buffer를 활용
함으로써 FileOutputStream.write() 수행시간을 줄인데 따른 성능 향상이며, FileInputStream.read()메소드는
약 9만번 호출되고 있다.

채널이용

위 두 방식과는 확연히 다른 동작 성향을 보여주고 있다.


마지막으로 채널을 이용한 파일복사의 경우 위 두 경우와 비교하여 호출되는 메소드나 호출횟수등 전혀 다른
동작 성향을 보이고 있다. read 도 하지 않은채 FileDispatcher.write() 메소드를 단 한번 호출 하는것으로 파일
복사를 끝내고 있다. 이 FileDispatcher.write() 하부구조에서는 OS의 네이티브IO를 호출하고 있으리라 미루어
짐작할 수 있다.

이상으로 파일복사(스트림전송)의 세가지 방식과 그 성능에 대해 간략하게 알아보았다.
위 실험 결과는 크기가 비교적 큰 파일의 복사에서 나타나는 성향며, 다수의 작은 크기의 파일을 복사한다면
그 결과가 달라질 수도 있음을 밝혀둔다.

io작업이 필요한데 JDK 1.4 이상의 버전을 이용할 수 있다면 나은 성능을 보장하는 nio를 사용하지
않을 이유가 없어보인다.

2008/07/13 21:21 2008/07/13 21:21
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다
  1. 안녕하세요 ^^
    글이 내용이 유용해서 좋아서 제가 퍼갔습니다. ^^
    문제가 있으시다면, 언제든지 알려 주세요 ^^

    링크는 다음과 같습니다. ^^
    http://cafe.naver.com/javacircle/31059

  2. Blog Icon
    서비

    도움이 되셨다니 기쁩니다.
    담아가셔도 크게 개의치 않습니다. ^^

  3. 감사합니다 ^^

  4. Blog Icon
    lahuman

    늘 사용하는 Stream 관련 좋은 정보 감사합니다.

  5. Blog Icon
    야기

    자바 성능검사를 어떻게 하셨는지 궁금합니다 ^^;

  6. Blog Icon
    서비

    글에 관심가져 주셔서 감사합니다.
    해당 프로파일러에 대한 정보는 http://www.yunsobi.com/blog/462
    글을 참고해 주시면 감사하겠습니다.

  7. Blog Icon

    생각보다 성능차이가 많이 나네요. 유용한 자료 잘 보고 갑니다.

    아 그리고 BufferedInputStream 생성자의 인자로 넘겨준 InputStream은 BufferedInputStream의 close()가 호출 될 때
    같이 close 됩니다. Channel 의 경우도 Lazy pattern 으로 생성되었다가 InputStream이 close 될 때 같이 close 되네요.
    이 글을 보고 혹시나 해서 궁금해서 소스를 뒤져보니 그렇게 되어있네요. 덕분에 배우고 갑니다 ^^

  8. Blog Icon
    컴장이

    좋은글 퍼갈께요.
    출처는 남기겠습니다.
    감사합니다.

  9. Blog Icon
    엘리냥

    파일 복사로 고민하던 차에 좋은 정보 얻어갑니다!!
    저런 성능 테스트 부분은 정말 유용하네요.
    성능 테스트하는 것도 더 알아봐야겠어요~

  10. Blog Icon
    노란사자

    좋은글 감사합니다.
    출처를 표기하고 퍼가겟습니다.

  11. Blog Icon
    이홍재

    좋은글 감사합니다.

    해당사항 담아갈게요.

    출처표기하겠습니다.

    담아가는 곳은 http://blog.naver.com/hongjae83

    문제가 될시 삭제하겠습니다.

    감사합니다.

  12. 좋은 정보 공유해주셔서 감사합니다

  13. Blog Icon
    jini

    좋은 정보 감사합니다.

  14. Blog Icon
    sbkim

    감사합니다^^~~~

  15. 감사합니다.
    http://blog.daum.net/andro_java/210
    채널카피 올렸습니다.

  16. 감사합니다. 많은 도움이 되었습니다.
    퍼갈께요. http://cafe.naver.com/stweb

  17. Blog Icon
    지나가던개발자

    이걸 안드로이드에 적용시켰더니 파일 복사 속도가 대략 3분의 1로 줄었습니다. 엄청난 성능입니다. 감사합니다.

자바 파일복사 코드와 성능 1. :: Java File Copy Code & Perfomance Issue. part 1

2008/07/13 00:05

서비 JAVA , , , , , ,

자바로 파일을 복사할 수 있는 방법은 크게 3가지 정도가 있다.
InputStream, OutputStream을 이용한 방법, Buffer를 이용한 방법, Channel을 이용한 방법이 그것이다.
물론 Buffer를 이용하면서도 단순히 Stream에 Buffer 필터를 적용할 수도, MappedByteBuffer를 쓸 수도 있고
Channel을 이용하면서도 inputChannel과 outputChannel을 이용하거나 transterTo()를 이용하는 등
다양한 방법을 구사할 수 있다.
여기서는 자바로 구현 할 수 있는 대표적인 파일 복사 코드를 살펴보고 각 코드간의 성능에 대한 이야기도 나눠
보도록 하겠다.

Java입문서등을 통하여 io (Input/Output)부분을 언급하며 나오는 개념이 Stream일 것이다. 스트림의 개념을
설명하고 처음 접하는 코드는 아래와 유사할 것이다. 파일을 인풋스트림으로 읽어들인 후 그 길이만큼 아웃풋
스트림에다 흘려보내는 방식으로 파일을 복사할 수 있다.

FileInputStream inputStream = new FileInputStream(file);
FileOutputStream outputStream = new FileOutputStream(saveFullPath);

int bytesRead = 0;
byte[] buffer = new byte[1024];

while ((bytesRead = inputStream.read(buffer, 0, 1024)) != -1) {
    outputStream.write(buffer, 0, bytesRead);
}

outputStream.close();
inputStream.close();

* InputStream과 OutputStream을 이용한 기본적인 파일 복사 코드.
위 코드는 기본적인 Stream의 사용법을 잘 보여주고 있지만 성능상에 심각한 문제를 안고 있다.
파일크기(정확하게는 스트림의 길이)만큼 while문을 돌면서 끊임없이 읽고쓰기를 반복하고 있는데
이는 CPU, DISK모두에게 부담을 주는 결과를 초래한다.

이어지는 코드가 아마 가장 널리쓰이고 흔하게 볼수 있는 코드 일 것이다. 위에서 살펴본 Stream간의 데이터
전송이 썩 좋은 성능을 내지 못하기 때문에, 스트림을 버퍼를 장착(wrapping, chainning)하여 입출력 횟수를 줄여
성능 향상을 꾀하고 있다.

FileInputStream inputStream = new FileInputStream(file);
FileOutputStream outputStream = new FileOutputStream(saveFullPath);

BufferedInputStream bin = new BufferedInputStream(inputStream);
BufferedOutputStream bout = new BufferedOutputStream(outputStream);

int bytesRead = 0;
byte[] buffer = new byte[1024];
while ((bytesRead = bin.read(buffer, 0, 1024)) != -1) {
    bout.write(buffer, 0, bytesRead);
}

bout.close();
bin.close();

outputStream.close();
inputStream.close();

* Stream에 Buffer Filter를 연결하여 성능을 향상.
위와같은 방법으로 충분히 만족할만 한가? 그렇다고 할수도있고 아니라고 할수도 있다. 위 두 방식은 스트림으로
데이터를 전송하는데 항상 cpu의 연산을 필요로 한다. 즉 스트림을 처리하는동안 cpu가 계속해서 명령을 처리
해줘야 한다는것이다.(비록 cpu사용율은 얼마 안될지 모르지만.. )

컴퓨터의 입장에서 본다면 IO는 상당히 느린 작업중의 하나이다. 이런 작업을 조금이라도 빨리 처리하기위해
하드웨어 혹은 운영체제 수준에서 많은 기법들을 제공하고 있다.
자바는 버전 1.4에 이르러서 기존 io와는 차별화된 nio(new io) 패키지가 추가되었는데 이 nio를 통하여
운영체제가 제공해 주는 향상된 io기능을 활용할 수 있게 되었다. 그 대표적인 것이 Channel과 Selector일 것이다.
아래와 같은 코드는 JDK 1.4이상부터 사용 가능하며 transferTo() 메소드를 호출하면 내부적으로 OS의 네이티브IO
기능을 활용하여 더욱 효율적인 스트림 전송이 가능하다.
 

FileInputStream inputStream = new FileInputStream(file);         
FileOutputStream outputStream = new FileOutputStream(saveFullPath);

FileChannel fcin =  inputStream.getChannel();
FileChannel fcout = outputStream.getChannel();

long size = fcin.size();
fcin.transferTo(0, size, fcout);

fcout.close();
fcin.close();

outputStream.close();
inputStream.close();

* Channel을 이용한 네이티브OS 기능 사용하기.

이상으로 3가지 대표적인 자바 파일복사 코드를 살펴보았다. 다음 포스트에서는 각 방식의 성능 차이에 대해
알아보도록 하겠다.

자바 파일복사 코드와 성능 2(새 창으로 열기)

2008/07/13 00:05 2008/07/13 00:05
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다
  1. 안녕하세요 ^^
    글이 내용이 유용해서 좋아서 제가 퍼갔습니다. ^^
    문제가 있으시다면, 언제든지 알려 주세요 ^^

    링크는 다음과 같습니다. ^^
    http://cafe.naver.com/javacircle/31058

  2. Blog Icon

    유익한 내용.. 출처 남기고 퍼가겠습니다 ^^

  3. Blog Icon
    SSH

    잘 썼습니다! 파일채널은 첨 써보는데 잘되네요!!

  4. 좋은 내용 감사합니다.

  5. Blog Icon
    우주인

    좋은 글 감사 합니다. 출처 남기고 퍼가겠습니다^^

  6. Blog Icon
    dennis

    좋은 정보 감사합니다.

Java 6의 새로운 기능, 향상된 부분.

2008/01/20 22:53

서비 JAVA ,




Java 6가 릴리즈 된지 꽤 시간이 흘렀지만, 아직까지 어디가 어떻게 변경되고, 향상되었는지 찾아보지 못하고 있었다.
아래 두 링크의 기사는 java 6의 새로운 기능화, 어떤부분이 개선되었는지 잘 나타내고 있으므로 시간을 내어 꼭 한번
읽어두도록하자.

What's New in Java SE 6
Features and Enhancements

2008/01/20 22:53 2008/01/20 22:53
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

넷빈즈 6.0 출시 :: NetBeans 6.0 Released!!

마일스톤, 베타, 캔디데이트를 거쳐 드디어 넷빈즈 6.0이 정식 출시 되었습니다.
넷빈즈 6.0 출시에 발맞추어 5.0 출시때와 마찬가지로 netbeans.org의 화면도 변화가 있네요.
(하지만 플러그인 탭으로 들어가면 아직까진 5 버전때의 화면을 볼 수 있습니다.)

netbeans.org
새 디자인이 적용된 netbeans.org


아래는 앞으로 넷빈즈의 개발 로드맵입니다. 현재 정식출시된 6.0 버전의 마이너 업그레이드는
계속 되겠지만, 메이저 업그레이드는 한동안 없을 것 같군요.
netbeans roadmap

넷빈즈 6.0 다운로드는 여기에서 할 수 있습니다.
다운로드 할 수 있는 패키지 형식도 다양해 졌습니다..
지금까진 NetBeans only,  NetBeans + J2SE, NetBeans + J2EE Server 세가지 종류의 패키지로
배포가 되었는데 이제는
Web & Java EE,  Mobility,  Java SE,  Ruby,  C/C++,  All  등으로 좀더 특화/세분화 되었습니다.
 물론 어떤 패키지를 받더라도 플러그인 다운로드를 통하여 다른 패키지의 기능을 추가할 수 있습니다.

넷빈즈 패키지 테이블



2007/12/06 12:40 2007/12/06 12:40
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

Java SE 6.0 Performance White Paper

2007/11/05 14:04

서비 JAVA ,

SDN( Sun Developer Network ) 에 JAVA SE 6.0 성능 백서가 발표되었습니다.

성능 개선과 추가된 기능들, 새로운 플랫폼 지원, 개발 진행 방향이라는 세 가지 꼭지로 정리된 이 백서에는 지금까지 JDK가 그래 왔던 것처럼 성능향상을 위해 컴파일러, 버추얼머신, 가비지콜렉션, I/O, 자료구조와 알고리즘 개선 부분을 성능 향상의 포인트로 두고 있습니다.

특히  JAVA 6.0 SE에서는, Boot Class 로딩 속도의 향상이라든지, SWING GUI 어플리케이션에 Double Buffering이 기본 지원사양으로 포함되었다든지, 버추얼 머신이 시작되기 전 Splash Screen을 처리할 수 있는 기능 등이 포함되는 등 JAVA 데스크탑 어플리케이션을 위한 성능 향상부분에 많은 노력을 기울이고 있다는 것을 알 수 있는데요.

JAVA 데스크톱 어플리케이션이 특정분야에 한정되어있고, GUI 디자인도 서서히 MARK-UP 형식의 언어로 넘어가는 현실에서 Swing, AWT와같은 Form-Based GUI 디자인이 언제까지 계속될진 모르겠지만 Swing 데스크탑 어플리케이션 개발을 위한 지원이 계속되고 있다는 것은 반길만한 일이 아닌가 합니다.

백서의 전문은
http://java.sun.com/performance/reference/whitepapers/6_performance.html(새 창으로 열기)
에서 확인하실 수 있습니다.
2007/11/05 14:04 2007/11/05 14:04
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다

JAVA.UTIL.SCANNER로 텍스트 스캔하기

JAVA.UTIL.SCANNER로 텍스트 스캔하기

J2SE 5.0에는 일상적 태스크를 좀 더 쉽게 구현할 수 있도록 하는 클래스와 메소드들이 추가되었다. 이번 팁에서는 새로 추가된 java.util.Scanner클래스를 이용함으로써 일반 표현문을 사용하는 스트링과 프리미티브 타입을 읽고 파싱(parsing)하는 것이 어떻게 좀 더 쉬워졌는지 알아보도록 하자.

J2SE 5.0의 출시 이전에는 파일에서 텍스트를 읽으려면 다음의 TextReader 클래스 같은 코드를 작성해야했다.


  1. import java.io.BufferedReader;
  2. import java.io.FileReader;
  3. import java.io.IOException;
  4. import java.io.File;
  5.  
  6.  public class TextReader {
  7.   private static void readFile(String fileName) {
  8.     try {
  9.       File file = new File(fileName);
  10.       FileReader reader = new FileReader(file);
  11.       BufferedReader in = new BufferedReader(reader);
  12.       String string;
  13.       while ((string = in.readLine()) != null) {
  14.         System.out.println(string);
  15.       }
  16.       in.close();
  17.     } catch (IOException e) {
  18.       e.printStackTrace();
  19.     }
  20.   }
  21.  
  22.   public static void main(String[] args) {
  23.     if (args.length != 1) {
  24.       System.err.println("usage: java TextReader "
  25.         + "file location");
  26.       System.exit(0);
  27.     }
  28.     readFile(args[0]);
  29.   }
  30. }

이와 같은 클래스에서의 기본적인 접근법은 하드 드라이브의 실제 파일과 일치하는 File 오브젝트를 생성하는 것이다. 그리고 나서 그 파일과 관련된 FileReader와 그 FileReaderBufferedReader를 생성하고, 그 후 BufferedFile 리더를 사용하여 한번에 한 줄씩 읽는다.

실행되는 TextReader클래스를 보기위해서는 클래스에 대한 문서를 생성하여 읽고 파싱해야한다. 문서를 생성하기 위해서는 TextReader와 같은 디렉토리 안에 있는 TextSample.txt라는 파일에 다음과 같은 두 줄의 텍스트를 저장해야 한다.

   Here is a small text file that you will
   use to test java.util.scanner.

TextReader를 컴파일하고 다음을 입력하여 구동시켜보자.

   java TextReader TextSample.txt

표준 출력으로 되돌아온 원본 파일을 보게 될 것이다.

프리미티브 타입과 스트링을 파싱하는 클래스인 java.util.Scanner를 이용하여 TextReader의 코드를 간단하게 할 수 있다.


  1. import java.io.File;
  2. import java.io.FileNotFoundException;
  3. import java.util.Scanner;
  4.  
  5. public class TextScanner {
  6.  
  7.   private static void readFile(String fileName) {
  8.     try {
  9.       File file = new File(fileName);
  10.       Scanner scanner = new Scanner(file);
  11.       while (scanner.hasNext()) {
  12.         System.out.println(scanner.next());
  13.       }
  14.       scanner.close();
  15.     } catch (FileNotFoundException e) {
  16.       e.printStackTrace();
  17.     }
  18.   }
  19.  
  20.   public static void main(String[] args) {
  21.     if (args.length != 1) {
  22.       System.err.println("usage: java TextScanner1"
  23.         + "file location");
  24.       System.exit(0);
  25.     }
  26.     readFile(args[0]);
  27.   }
  28. }

TextScanner를 컴파일하고 다음과 같이 구동하자.

   java TextScanner TextSample.txt

다음과 같은 결과가 나타난다.

   Here
   is
   a
   small
   text
   file
   that
   you
   will
   use
   to
   test
   java.util.scanner.

TextScanner 는 파일로부터 Scanner 오브젝트를 생성한다. Scanner는 파일의 컨텐츠를 구획자 패턴을 이용하여 분해한다. 구획자 패턴의 디폴트 값은 흰 여백이다. 그 후 TextScannerScannerhasNext() 메소드를 호출한다. 이 메소드는 Scanner 입력값에 파일의 마지막 부분에 이를 때까지 다른 token이 있으면 'true'를 리턴한다. next() 메소드는 다음 token을 나타내는 스트링을 리턴한다. 따라서 TextScanner는 파일의 마지막부분에 이를 때까지 각 라인에서 next()에 의해 리턴되는 스트링을 프린트한다.

ScanneruseDelimiter 를 이용해 입력물을 토큰화하는 데 이용하는 구획자를 변경시킬 수도 있다. 메소드에 스트링 또는 java.util.regex.Pattern에 전달해주면 된다. 어떤 패턴들이 적절한 지에 대해서는 JavaDocs page for Pattern를 참조하기 바란다. 예를 들어 newline(\n)을 구획자로 이용하여 한번에 한 줄의 입력물을 읽을 수 있다. 다음은 새줄 문자를 구획자로 이용하는 수정된 readFile() 메소드이다.


  1.    private static void readFile(String fileName) {
  2.      try {
  3.        Scanner scanner = new Scanner(new File(fileName));
  4.        scanner.useDelimiter
  5.          (System.getProperty("line.separator"));
  6.        while (scanner.hasNext()) {
  7.          System.out.println(scanner.next());
  8.        scanner.close();
  9.      } catch (FileNotFoundException e) {
  10.        e.printStackTrace();
  11.      }
  12.    }

마지막 줄을 찾는 다른 옵션들도 있다. 예를 들어 새줄 문자로 끝나는 라인이나 캐리지 리턴(enter키)과 newline으로 끝나는 라인들을 조사할 수 있다. "\r\n|\n" 일반 표현문을 이용하여 이를 실행할 수 있다. java.util.regex.Pattern의 JavaDocs는 또다른 라인 종결기들을 보여주므로 좀 더 복잡한 분석은 "\r\n|[\r\n\u2028\u2029\u0085]"표현문을 이용한다. 또한 Scanner 클래스의 hasNextLine()nextLine() 메소드를 이용할 수 있다. 어느 경우이던 수정된 TextScanner를 사용하면 결과물은 TextSample.txt의 컨텐츠와 레이아웃에 부합될 것이다. 다음을 참고하기 바란다.

   Here is a small text file that you will
   use to test java.util.scanner.

Scanner에 의해 사용된 구획자의 패턴을 간단하게 변경하여 큰 효과와 유연성을 얻을 수 있다. 예를 들어 다음의 구획자를 지정하면,

   scanner.useDelimiter("\\z");

한번에 전체 파일을 읽는다. 이는 Pat Niemeyer가 java.net blog에서 제안하고 있는 요령과도 비슷하다. 몇 개의 중간 오브젝트를 생성하지 않고도 웹페이지의 모든 컨텐츠를 읽을 수 있는 것이다. 다음 WebPageScanner클래스의 코드는 java.net homepage의 현재 컨텐츠를 읽고 있다.


  1.    import java.net.URL;
  2.    import java.net.URLConnection;
  3.    import java.io.IOException;
  4.    import java.util.Scanner;
  5.  
  6.    public class WebPageScanner {
  7.      public static void main(String[] args) {
  8.        try {
  9.          URLConnection connection =
  10.            new URL("http://java.net").openConnection();
  11.          String text = new Scanner(
  12.            connection.getInputStream()).
  13.            useDelimiter("\\Z").next();
  14.        } catch (IOException e) {
  15.          e.printStackTrace();
  16.        }
  17.      }
  18.    }

Scanner 클래스로 스트링 이외의 것들도 다룰 수 있다. 프리미티브 타입으로 이루어진 데이터를 파싱하는 데에도 사용할 수 있다. 이에 대한 예제로, 다음의 세 라인을 Employee.data라는 이름의 파일(TextSample와 같은 디렉토리 안)에 저장하자.

   Joe, 38, true
   Kay, 27, true
   Lou, 33, false

이를 하나의 큰 스트링으로 취급하여 이 스트링을 파싱한 후에 대화문을 실행할 수도 있지만, 대신에 이 파일을 두가지 단계로 파싱해보자. 이는 다음의 클래스 DataScanner에 설명되어 있다.


  1.    import java.util.Scanner;
  2.    import java.io.File;
  3.    import java.io.FileNotFoundException;
  4.  
  5.    public class DataScanner {
  6.  
  7.      private static void readFile(String fileName) {
  8.        try {
  9.          Scanner scanner =
  10.            new Scanner(new File(fileName));
  11.          scanner.useDelimiter
  12.            (System.getProperty("line.separator"));
  13.          while (scanner.hasNext()) {
  14.            parseLine(scanner.next());
  15.          }
  16.          scanner.close();
  17.        } catch (FileNotFoundException e) {
  18.          e.printStackTrace();
  19.        }
  20.      }
  21.  
  22.      private static void parseLine(String line) {
  23.        Scanner lineScanner = new Scanner(line);
  24.       lineScanner.useDelimiter("\\s*,\\s*");
  25.        String name = lineScanner.next();
  26.        int age = lineScanner.nextInt();
  27.        boolean isCertified = lineScanner.nextBoolean();
  28.        System.out.println("It is " + isCertified +
  29.          " that " + name + ", age "
  30.          + age + ", is certified.");
  31.      }
  32.  
  33.      public static void main(String[] args) {
  34.        if (args.length != 1) {
  35.          System.err.println("usage: java TextScanner2"
  36.            + "file location");
  37.          System.exit(0);
  38.        }
  39.        readFile(args[0]);
  40.      }
  41.    }


DataScanner의 바깥쪽 Scanner 오브젝트는 한번에 한 라인씩 파일을 읽는다. readFile() 메소드는 각 라인을 두번째 스캐너에 전달하고, 이 두번째 스캐너는 콤마로 ,구획된 데이터를 파싱하고 콤마 양쪽의 흰 여백을 삭제한다. 다음 token이 특정타입의 token인지 아닌지 분석하여 다음 token을 그 타입의 인스턴스로 취급하도록 하는 hasNext()next()메소드들도 있다. 예를 들어 nextBoolean()은 다음 token을 boolean으로 취급하여 "true" 또는 "false" 스트링과 매치시킨다. 매칭이 이뤄지지 않으면 java.util.InputMismatchException이 던져진다. DataScannerparseLine() 메소드는 각 라인이 어떻게 String, int, boolean으로 파싱되는지 보여준다.

Compile DataScanner. Then run it as follows:

DataScanner를 컴파일하고 다음과 같이 구동시키자.

   java DataScanner Employee.data

다음과 같은 결과가 나타난다.

   It is true that Joe, age 38, is certified.
   It is true that Kay, age 27, is certified.
   It is false that Lou, age 33, is certified.

콤마를 구획문자로 사용하고 싶을 것이다. 다시 말해 다음과 같이 시도해보려고 할 것이다.

   lineScanner.useDelimiter(",");

이는 결국 InputMismatchException로 끝날 것이다. 이는 boolean으로 변경하려는 token에 여분의 공간이 포함되며 이 공간은 "true"나 "false" 에 매치되지 않기 때문이다. 일반적인 표현문의 모든 애플리케이션에 해당되는 케이스이므로 패턴을 구축하는 데 있어서 특히 세심한 주의가 필요할 것이다.

Scanner에 대한 좀 더 자세한 정보는 formal documentation를 참고하기 바란다.

저자 : Daniel H. Steinberg
원문 출처 : http://kr.sun.com/developers/techtips/c2004_1201.html(새 창으로 열기)

2007/06/24 11:28 2007/06/24 11:28
Trackback Address:이 글에는 트랙백을 보낼 수 없습니다