2017년 4월 23일 일요일

[java] List에서 int[] 로 바꾸는 방법 (on java8)

List에서 int[]로 바꾸는 손쉬운 방법은 없었다. Arrays의 toArray()는 Object[]를 반환하기 때문에 불가능했고
toArray(T[] ...) 얘도 primitive type인 int[]를 담을 순 없었다.

하지만 Java8에서는 쉽게 변환할 수 있다.
List list = new ArrayList<>();
...
int[] i_arr = list.stream().mapToInt(i -> i).toArray();
어떻게 이렇게 쉽게 되는 걸까?
list.stream()은 게다가 아직 Integer이다. 무슨 일이 벌어진 걸까?
java8부터 primitive type을 다룰 수 있는 IntStream이라는 것이 있다.
우리는 이놈으로 바꿔야만 한다. 그래서 사용하는 것이 mapToInt이다 얘는 IntStream을 리턴한다.
mapToInt이라는 이름처럼 요소 하나하나를 매개변수 안에 있는 로직대로 이행한 후 IntStream으로 리턴하는 듯하다.

그래서 실제로는 이렇게 되야 한다.
mapToInt((Integer i) -> i.intValue()) or mapToInt(Integer::intValue())
Integer에 있는 메소드 intValue로 int로 변환하는 함수를 넣는 것이 정상이다. 그런데 왜 그냥 아무짓도 안해도 에러가 안나고 잘 되는 걸까?
바로 언박싱을 이용하는 것인데, 리턴값은 int로 정해져있고 컴파일러가 그걸 확인할 것이다.

만약 자바8을 쓸 수 없다면?
Guava를 사용하면 되겠다.

[java][design pattern] 더블 디스패치 패턴은 언제 쓰일까?

더블디스패치 패턴은 대체 왜 쓰이는 걸까?
자바는 싱글디스패치만을 지원한다고 한다.
그 말은 더블디스패치를 사용하려면 패턴으로 메꿔야 한다는 말인가보다.
예전에는 싱글디스패치만으로도 만족하고 살았지만 다른 많은 언어들이 실행시키는 인스턴스와 매개변수 둘 다 타입체크를 하여 멋져졌다 하니.
우리도 패턴으로 그것이 가능함을 보여야 하지 않겠나 해서 만들어 진 것이 아닌가 하는 상상을 해본다.

일단 만들어보자. 이제부터 할 일은 이렇게 된다.
  • 인터페이스 둘을 만든다. (Format, Post)
  • 인터페이스를 구현한다. (Post - Mail,SMS / Format - JPG,XML)
  • 이 두 인터페이스를 연결한다.
  • 실행해본다.
  • 일단 왜 더블디스패치가 없이 만들면 어떻게 되는지 보자.
    1. 인터페이스 둘을 만든다.
    interface Format {}
    interface Post {}
    
    2. 인터페리스를 구현한다. (총 4개)
    public class JPG implements Format { }
    public class XML implements Format { }
    
    public class Mail implements Post { }
    public class SMS implements Post { }
    
    이제 인터페이스에 필요한 내용들 추가하고 구현도 해서 이 두 인터페이스를 연결하자.
    Post인터페이스는 JPG / XML에 따라 보내는 방식이 다를 수 있다. 그래서 그 타입에 따라 다른 일을 하도록하자.
    public interface Post {
      void send(Format format);
      void send(JPG jpg);
      void send(XML xml);
    }
    
    게다가 SMS/MAIL에 따라 다를 것이다.
    public class Mail implements Post {
    
      @Override
      public void send(Format format) {
        throw new RuntimeException("Mail.send(Format format) :: 타입을 알 수 없습니다.");
      }
    
      @Override
      public void send(JPG jpg) {
        System.out.println("Mail.send(JPG jpg)");
      }
    
      @Override
      public void send(XML xml) {
        System.out.println("Mail.send(XML xml)");
      }
    
    }
    
    public class SMS implements Post {
    
      @Override
      public void send(Format format) {
        throw new RuntimeException("SMS.send(Format format) :: 타입을 알 수 없습니다.");
      }
    
      @Override
      public void send(JPG jpg) {
        System.out.println("SMS.send(JPG jpg)");
      }
    
      @Override
      public void send(XML xml) {
        System.out.println("SMS.send(XML xml)");
      }
    
    }
    
    다 되었다. 실행해보자.
    public class Test {
      public static void main(String[] args) {
        Post post = new Mail();
        Format format = new JPG();
        post.send(new JPG());
        post.send(format);
      }
    }
    
    잘 될까?
    Mail.send(JPG jpg)
    Exception in thread "main" java.lang.RuntimeException: Mail.send(Format format) :: 타입을 알 수 없습니다.
     at designpattern.doubledispatch.post.Mail.send(Mail.java:11)
     at designpattern.doubledispatch.Test.main(Test.java:13)
    
    하나는 잘 되었고, 다른 하나는 잘 되지 않았다. 왜냐하면 메소드 오버로딩은 정적 디스패치(static dispatch)를 한다. 이 말은 런타임에 타입을 동적으로 체크하는 것이 아니라 미리 컴파일 이전에 타입을 미리 제대로 정해 놔야 한다는 말이다.
    에러가 난 곳은 정확한 타입(JPG)를 넣은 것이 아니라. Format이라는 인터페이스를 넣었다. 이것이 문제가 되는 것
    그러면 어떻게 해야 할까?
    일단 자바에서는 매개변수 타입체크를 동적으로 하지않는다고 하니까 타입체크를 두 번 하도록 해보자.
    지금부터 할일은
    1. Post 인터페이스를 매개변수가 Format인 것만 남기고 삭제한다. (어짜피 이걸로 타입체크를 못함)
    2. Format 인터페이스에 Mail,SMS(Post의 구현체 전부)를 각각 매개변수로 하여 void send(T t)형식의 메소드를 추가한다
    3. Post의 구현체에서 해당 메소드를 호출한다.
    4. 실제로 로직을 실행하는 곳은 Format의 구현체들에서 각각 구현한다.
    말이 잘 전달되지 않은 것 같은데 일단 코드를 한 번 짜보자.
    // 1. 매개변수가 Format 인것 빼고 다 삭제
    public interface Post {
      void send(Format format);
    }
    // 2. Mail,SMS를 각각 매개변수로 send라는 메소드를 추가
    public interface Format {
      /*
       * 여기에서 타입체크를 하는 것이다. 원래는 Post에서 했지만
       * 한 번 더 하기 위해, Format에서 한다.
       * 
       */
      void send(Mail mail);
      void send(SMS sms);
    }
    
    이제 인터페이스를 바꿨으니 구현체들을 바꿔보자.
    // 3. 새로 만든 메소드 호출
    public class Mail implements Post {
    
      @Override
      public void send(Format format) {
        format.send(this); // 여기서 이미 this는 타입체킹이 되어있음.
      }
    }
    
    public class SMS implements Post {
    
      @Override
      public void send(Format format) {
        format.send(this);
      }
    
    }
    
    이제 실제 로직이 들어있는 곳을 보자.
    // 4. 실제 로직이 있는 곳 변경
    public class JPG implements Format {
    
      @Override
      public void send(Mail mail) {
        System.out.println("mail send JPG");
      }
    
      @Override
      public void send(SMS sms) {
        System.out.println("SMS send JPG");
      }
    
    }
    
    public class XML implements Format {
    
      @Override
      public void send(Mail mail) {
        System.out.println("mail send XML");
      }
    
      @Override
      public void send(SMS sms) {
        System.out.println("SMS send XML");
      }
    
    }
    
    한번 실행해보자.
    public class Test {
      public static void main(String[] args) {
        Post post = new Mail();
        Format format = new JPG();
        post.send(new JPG());
        post.send(format);
      }
    }
    
    과연 결과는??
    mail send JPG
    mail send JPG
    
    성공이다. 이 패턴은 비지터 패턴과 아주 유사하다고 하는데, 비지터 패턴은 내 생각에는 클래스를 변경하지 않고 새로운 로직을 추가하기 위해 필요한 패턴인 것 같고
    더블디스패치패턴은 좀 더 일반적인 기술같다. 양쪽의 타입을 제대로 체크하기 위해 만든 기술인듯하다.

    [java] interface constant는 왜 쓰면 안될까?

    가끔 이런 생각을 해보기도 한다.
    귀찮은데 그냥 상수도 인터페이스로 넣어서 쓰면 안되나?
    아니면 implements로 상수를 전부 가져와서 이름만으로 써도 되지 않을까?
    아래의 예시가 왜 쓰면 안되는지 도움이 될 것 같다. 우선 클래스 안에 있는 상수들을 보자.
    public class ClassCons {
     public static final double CONS = 0.0;
     public static final String CONS1 = "22";
     public static final int CONS2 = 1;
    }
    
    이제 이것들을 인터페이스 상수로 바꿔보자.
    interface InterCons {
     double CONS = 0.0;
     String CONS1 = "22";
     int CONS2 = 1;
    }
    
    인터페이스는 어짜피 public이다. 그러니 public이 필요없다. 바뀌지 않을 것이니 final도 필요없다.
    마치 짧아진 코드를 보며 내가 뭔가 해낸(?)사람 처럼 느낄 수도 있지만 아님을 바로 깨달을 수 있다.
    public class BadIdea implements InterCons{
     public BadIdea() {
      System.out.println(CONS);
      System.out.println(CONS1);
      System.out.println(CONS2);
     }
     public static void main(String[] args) {
      BadIdea badIdea = new BadIdea();
     }
    }
    
    이 내용은 위에서 만든 인터페이스 상수를 가져온 것이다. 과연 이렇게 하면 잘 될까?
    0.0
    22
    1
    
    예상한 대로 나왔다. 하지만 이렇게 한다면?
    public class BadIdea implements InterCons{
     private int CONS = 100;
     public BadIdea() {
      System.out.println(CONS);
      System.out.println(CONS1);
      System.out.println(CONS2);
     }
     public static void main(String[] args) {
      BadIdea badIdea = new BadIdea();
     }
    }
    
    다시 실행해보자.
    100
    22
    1
    
    값이 바뀌어 있다. 이 말은 인터페이스 상수를 가져오는 순간 해당 클래스와 그 서브 클래스들이 상수들로 더러워(?)진다는 것을 말한다.
    자칫하면 값들이 꼬일 수 있다. 에러도 잘 보이지 않을 거고 디버깅에도 애를 먹을 수도 있겠다.

    2017년 4월 20일 목요일

    [java] volatile이란 뭘까?

    Dzone에서 volatile내용을 보고 있다가 좀 적어놔야 할 것같아서 적는다.
    자바의 keyword 중에 하나인 volatile은 대체 정확히 어떨 때 쓰는 것일까?
    애초에 volatile은 뭘까?
    volatile은 휘발성 이란 의미를 가지고 있다. 잘 날아간다는 말이니까. 금방금방 그 값이 사라진다고 말 할수도 있고, 그 값이 의미없어진다고도 말 할수 있겠다.
    volatile은 값을 읽고, 쓰는 것에 대한 원자성(Atomic)을 유지해주는 것 같다.

    왜 이게 필요한가 하면 멀티스레드 환경에서 스레드 각각이 변수들의 값을 캐싱해서 사용한다는 것때문이다. 덕분에 값을 조회할 때마다 실제 값을 조회할 필요가 없이 사용할 수 있지만 만약 공유하는 값이 있고 그 값이 자주 변한다면 문제가 생길 수 있지 않을까?
    그때 volatile을 사용하면 되지 않을까 싶다.
    
    public class VolatileTest {
      private static volatile int count = 0;
    //private static int count = 0;
      public static void main(String[] args) {
        new IwillGetIt().start();
        new IwillChangeIt().start();
      }  
      
      static class IwillGetIt extends Thread {
        @Override
        public void run() {
          int my_local = count;
          while (my_local < 5) {
            if (my_local != count){
              System.out.println("바꼈다!!! : " + count);
       my_local = count;
     }
          }
        }
      } 
      static class IwillChangeIt extends Thread {
        @Override
        public void run() {
          int my_local = count;
          while (my_local < 5 ) {
            System.out.println("값을 증가 시킴 : " + (++my_local));
            count = my_local;
            try {
              Thread.sleep(2000);
            } catch (InterruptedException e) {
       e.printStackTrace();
     }
          }
        }
      }
    }
    
    어떻게 될까? 위의 내용은 volatile을 넣은 것이다. count라는 값은 두개의 스레드가 공유를 한다. 서로 IwiilChangeIt은 바꾸는 아이고 IwillGetIt은 바꾸는 현장을 포착하는 아이다.
    값을 증가 시킴 : 1
    바꼈다!!! : 1
    값을 증가 시킴 : 2
    바꼈다!!! : 2
    값을 증가 시킴 : 3
    바꼈다!!! : 3
    값을 증가 시킴 : 4
    바꼈다!!! : 4
    값을 증가 시킴 : 5
    바꼈다!!! : 5
    
    그렇다면 이 상태에서 저 위에 volatile이 없는 녀석의 주석을 풀고, volatile이 있는 녀석은 주석을 걸어보고 다시 실행하자.
    값을 증가 시킴 : 1
    바꼈다!!! : 1
    값을 증가 시킴 : 2
    값을 증가 시킴 : 3
    값을 증가 시킴 : 4
    값을 증가 시킴 : 5
    
    그렇다면 volatile은 항상 쓰는 것이 스마트한 것일까?
    난 잘 모르겠지만 그렇게는 쓰지 않는 것이 좋을 것 같다. 왜냐하면?
    1. volatile은 변수에게 특권을 주는 것과 같다. 그 특권을 남발하면 안된다.
    2. volatile을 모든 변수에게 주면 코드가 지저분하다.
    3. 1번과 일맥상통한 것인데 volatile을 죄다 쓰면 누가 진짜 필요한 volatile인지 누가 알 수 있을까. 왜 이렇게 썼는지 고민하고 있지 않을까?
    4. 성능의 이슈는 없을까? 하지만 이건 아직 내가 신경쓸 것은 아닌 듯 하다.

    2017년 4월 13일 목요일

    [JavaScript] 자바스크립트에서 private변수 사용하기

    자바스크립트에서는 private을 넣는다고 private 변수가 되지 않는다.
    var my obj = {
      myprop: 1,
      getProp: function() { return this.prop; }
    }
    console.log(myobj.myprop);
    1
    console.log(myobj.getProp()); 
    1
    
    다른 방법으로도 한번 만들어보자.
    function G() {
      this.name '지';
      this.age = function() { return 1; }
    }
    var g = new G();
    console.log(g.name);
    '지'
    console.log(g.age());
    1
    

    Solution

    자바스크립트는 별도의 syntax가 없어도 private변수를 만들 수 있다.
    function new_G() {
      var name = 'G의 숨은 뜻은 지메일'; // private
      this.getName = function() { return name; };
    }
    var secret_g = new new_G();
    console.log(secret_g.name);
    undefined
    console.log(secret_g.getName());
    'G의 숨은 뜻은 지메일'
    
    생성자가 함수의 클로저를 만들고 그 클로저 스코프 안에 속하는 변수들을 만든다. closure scope는 생성자 외부로 노출되지 않는다.

    2017년 4월 12일 수요일

    [java][thread] join을 이용하여 thread가 끝났는지 확인하기

    join()을 이용하여 thread가 끝났는지 확인하자.

    오늘 이런 형태의 소스를 보았다. (아래 내용은 예시)
    RunnableClass01 rc01 = new RunnableClass01();
    RunnableClass02 rc02 = new RunnableClass02();
    RunnableClass03 rc03 = new RunnableClass03();
    
    Thread th01 = new Thread(rc01);
    Thread th02 = new Thread(rc02);
    Thread th03 = new Thread(rc03);
    
    th01.start();
    th02.start();
    th03.start();
    
    DB.updateThreadEndsTime(); // 이것이 문제
    
    대충 이런식이었는데... 쓰레드는 끝나지도 않았지만 시작하자마자 스레드가 끝났다는 로직을 실행시킨다.
    전체 소스를 보지 않은 나의 탓이 크지만
    쓰레드가 완료되었다는 시간을 처리하는 로직은 '당연히' 쓰레드가 전부 끝났을 때 업데이트 할 것이라는 가정이 있었기에 로직 수정 후 낭패를 보았다.
    그 후 나는 동료에게 물었다.
    "왜 이렇게 해야 하죠? 쓰레드가 끝나고 완료 업데이트를 하면 안되나요?"
    "쓰레드는 원래 그래요. 서로 독립적으로 실행되기 때문이죠."
    나는 단순하게 join()을 사용해서 그것이 가능함을 보이려 했다.
    RunnableClass01 rc01 = new RunnableClass01();
    RunnableClass02 rc02 = new RunnableClass01();
    RunnableClass03 rc03 = new RunnableClass01();
    
    Thread th01 = new Thread(rc01);
    Thread th02 = new Thread(rc02);
    Thread th03 = new Thread(rc03);
    
    th01.start();
    th02.start();
    th03.start();
    
    try {
      th01.join();
      th02.join();
      th03.join();
    }catch (Exception e) { }
    
    DB.updateThreadEndsTime(); // 이제 스레드 전부 완료되면 된다.
    
    "이러면 쓰레드 하나가 끝나면 다른 하나가 시작되는 것 아녜요?"
    나는 말했다.
    "아닙니다. 시작은 같이 하고 끝나는 것만 동기되는 거예요.
    어짜피 다 끝나야 완료처리 되야 하는 거니까 다 끝나야 일을 하는것이 맞다고 생각해요." 이렇게 끝났다. 하지만 여기서 하나 더 수정을 해야겠다.
    Thread th01 = new Thread(new RunnableClass01());
    Thread th02 = new Thread(new RunnableClass02());
    Thread th03 = new Thread(new RunnableClass03());
    
    th01.start();
    th02.start();
    th03.start();
    
    try {
      th01.join();
      th02.join();
      th03.join();
    } catch (Exception e) { }
    
    DB.updateThreadEndsTime(); // 이제 스레드 전부 완료되면 된다.
    
    물론 다른 방법도 많겠지만, 실력의 부족과 상황이 여의치 않아 이렇게 단순하게 바꾸는 것 만으로도
    로직의 큰 변화가 왔다.
    join(), wait(), notify() 같은 것은 기본적으로 알아야할 기능 같다.