JAVA8에 대해 알아보자(번외)

java8 번외

갑자기 생각나서 쓴다.
java8 의 추가된 기능 중 interface에 관한 내용이다.
java8 interface는 static 메소드도 구현 가능하다.
이로써 util interface를 구현 할 수 있다는 거다.

또 다른 하나는 default 키워드가 추가 되어 메소드 바디를 갖는 인터페이스가 추가 되었다.
그러면서 다중 상속의 개념이 다시 등장했다.
그래서 한번 테스트를 해봤다.

interface Man {
    default void print(String name) {
        System.out.println("Man :"  + name);
    }
}

interface WoMan {
    default void print(String name) {
        System.out.println("WoMan :"  + name);
    }
}

이런 두개의 인터페이스가 있다고 가정하자.

그리고 두개의 인터페이스를 상속해보자

class Hermaphrodite implements Man,WoMan {
}

그럼 intellij에선 컴파일 에러가 난다.
같은 동일한 메소드가 다 구현 되어 있어서 에러를 내는거 같다.
만약 메소드가 동일 하지 않다면 에러를 내뱉지 않는다.
이로써 다아이몬드 상속은 해결된건가?

다음 코드도 한번 보자.

interface Human{
    default void print(String name) {
        System.out.println("Human "  + name);
    }
}

interface Man extends Human{
    default void print(String name) {
        System.out.println("Man :"  + name);
    }
}

interface WoMan extends Human{
    default void print(String name) {
        System.out.println("WoMan :"  + name);
    }
}

class Hermaphrodite implements Man,WoMan {

    @Override
    public void print(String name) {
        System.out.println("Hermaphrodite : " + name);
    }
}

네개의 클래스와 인터페이스를 만들고 해보자.

public static void main(String[] args) {
    Human man = new Hermaphrodite();
    man.print("wonwoo");
}

실행 결과는 Hermaphrodite : wonwoo
무조건 구현해야 되기 때문에 나올 수 밖에 없다.
그럼 Woman의 default 메소드를 제거하고 Hermaphrodite 구현체를 제거해보자.

interface WoMan extends Human{
}

class Hermaphrodite implements Man,WoMan {
}

다시 실행해보자.

public static void main(String[] args) {
    Human man = new Hermaphrodite();
    man.print("wonwoo");
}

기대했던 결과는

Man wonwoo

일 것이다.
그럼 다음 코드를 보자.

interface Human {
    default void print(String name) {
        System.out.println("Human " + name);
    }
}

interface Man extends Human {
    default void print(String name) {
        System.out.println("Man " + name);
    }
}

interface WoMan extends Human {
    default void print(String name) {
        System.out.println("Man " + name);
    }
}

class Hermaphrodite implements Man, WoMan {
    @Override
    public void print(String name) {
        Man.super.print("wonwoo");
        WoMan.super.print("no!");
    }
}
Human man = new Hermaphrodite();
man.print("wonwoo");
wonwoo
no!

이렇게 하면 다중상속이 된다.

JAVA8에 대해 알아보자(3)

java8

이번엔 메소드 레퍼런스에 대해 알아보자.
메소드 레퍼런스를 알아보기전에 알아두어야 할 것이 있다.
first-class citizen(일급 시민) 이 용어는 60년대에 크리스토퍼 스트래치 라는 분이 만들었다.
first-class citizen란 무엇인가.
일단 내가 알고 있는 것으로 설명하겠다.
1. 파라미터로 전달받을 수 있어야 한다.
2. 리턴 값으로 반환 할 수 있어야 한다.
3. 변수 혹은 Data 구조에 담을 수 있어댜 한다.

그럼 필자가 말한 위에 3개가 자바에서 가능 한지를 알아보겠다.
첫 번째로 파라미터롤 전달 받을 수 있는지 알아보자.

일단 function을 담을수 있는 functionalInteface를 만들자

@FunctionalInterface
interface Functional{
    String apply(Integer i);
}

그리고 메소드를 전달하기 위한 메소드를 만들어 보자

private static String methodReferenceParameter(Functional functional){
    return "result : " + functional.apply(1);
}

간단하다 methodReferenceParameter라는 메소드는 Functional을 파라미터로 받고 String으로 돌려주는 메소드이다.
그럼 일반적으로 람다를 쓸경우엔 어떻게 쓰는지 보자.

String lambda = methodReferenceParameter(i -> String.valueOf(i));
System.out.println(lambda);

이렇게 호출하면 result : 1 이런 결과값을 얻을 수 있다.
다음은 메소드 레퍼런스를 사용해보자.
일단 메소드를 넘길려면 메소드를 만들어야 된다. 위에 람다에서 사용했던 String.valueOf(i)를 메소드로 만들어 보자

private static String methodReference(int i){
    return String.valueOf(i);
}

이제 사용해보자!

String methodReference = methodReferenceParameter(MethodReferenceExample::methodReference);
System.out.println(methodReference);

결과는 같을 것이다.

다음으론 리턴 값을 반환 할 수 있는지 알아보자.
일단 비교를 위해 lambda로 먼저 해보겠다.

private static Functional methodReferenceReturnlambda(){
    return i -> String.valueOf(i);
}

사용해보자.

Functional functional = methodReferenceReturnlambda();
System.out.println("string : " + functional.apply(1));

string을 리턴하는 것 이기에 string 이라는 문자를 넣었다.

다음은 메소드 레퍼런스를 사용하여 리턴 값을 만들어 보자.

private static Functional methodReferenceReturn() {
    return MethodReferenceExample::methodReference;
}

호출해보자.

Functional methodReferenceReturn = methodReferenceReturn();
System.out.println("methodReferenceReturn : " + methodReferenceReturn.apply(1));

정상적으로 컴파일 후 실행이 될 것이다.

다음은 모지? 아 변수 혹은 Data구조에 담아 둘 수 있어야 한다.
List<T>에 담기는지 보자.

List<Functional> functionals = Arrays.asList(MethodReferenceExample::methodReference, i -> String.valueOf(i));

컴파일도 잘된다.
실행해보자

System.out.println(functionals.get(0).apply(100));
System.out.println(functionals.get(1).apply(200));

이렇게 사용하면 된다.
부가적으로 Syntax를 보자.
static 메소드는 ClassName::MethodName 으로 하면 된다.
인스턴스 메소드는 object::instanceMethodName으로 하고
생성자ClassName::new으로 정의하면된다.

이상으로 자바8의 변경사항을 알아봤다.

주키퍼 설치 및 설정

주키퍼 설치 및 설정

주키퍼를 설치 해보자. 다운로드 여기서 다운 받으면 되겠다

압축을 풀고 원하는 디렉토리에 넣어두자. 필자는 /usr/local/에 넣어 두었다.
${home}/conf/zoo.cfg 파일이 주키퍼 설정 파일이다.

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/var/zookeeper1
clientPort=2184

설정을 저장하자.
서버를 실행시켜보자!

./bin/zkServer.sh start

JMX enabled by default
Using config: /usr/local/zookeeper1/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED

주키퍼 클라이언트를 이용해서 접속해보자!

./bin/zkCli.sh -server localhost:2184

접속이 완료되었다.
간단하게 노드를 만들어보자.

[zk: localhost:2184(CONNECTED) 0] create /zoo_test my_data
Created /zoo_test

만들어진 노드를 확인해보자

[zk: localhost:2184(CONNECTED) 1] ls /
[zoo_test, zookeeper]

잘 만들어져 있다.
정보도 한번 보자.

[zk: localhost:2184(CONNECTED) 2] get /zoo_test
my_data
cZxid = 0x500000007
ctime = Wed Mar 02 08:37:55 UTC 2016
mZxid = 0x500000007
mtime = Wed Mar 02 08:37:55 UTC 2016
pZxid = 0x500000007
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 7
numChildren = 0

다음은 replication 설정을 해보자
세개의 주키퍼가 필요하므로 세개를 복사하자.
필자는 이렇게 했다.
/usr/local/zookeeper1
/usr/local/zookeeper2
/usr/local/zookeeper3
그리고 설정을 바꿔줘야한다.
다시 zoo.cfg 파일을 열어서 아래와 같이 바꾸자.

/usr/local/zookeeper1

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/var/zookeeper1
clientPort=2184
server.1=localhost:2888:3888
server.2=localhost:2889:3889
server.3=localhost:2890:3890

/usr/local/zookeeper2

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/var/zookeeper2
clientPort=2185
server.1=localhost:2888:3888
server.2=localhost:2889:3889
server.3=localhost:2890:3890

/usr/local/zookeeper3

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/var/zookeeper3
clientPort=2186
server.1=localhost:2888:3888
server.2=localhost:2889:3889
server.3=localhost:2890:3890

아래의 세줄이 추가 되었고 디렉토리가 변경되었다.
3개의 주키퍼 모두 바꾸자! 디렉토리는 각기 다르게! 물리적으로 서버가 같다면 포트를 나눠줘야한다.
2888 포트는 각각의 통신하기 위한 포트 3888은 마스터를 선출하기 위한 노드라 한다.
server.1,server.2,server.3 의 숫자는 /var/zookeeper1/myid의 값과 동일해야된다.

cat /var/zookeeper1/myid
1
cat /var/zookeeper2/myid
2
cat /var/zookeeper3/myid
3

세개의 노드를 실행해야된다.
귀찮다.
스크립트로 대충 만들었다

#!/bin/bash

param=$1

ZOO1_HOME="/usr/local/zookeeper1/"
ZOO2_HOME="/usr/local/zookeeper2/"
ZOO3_HOME="/usr/local/zookeeper3/"

case $param in
  start)
    $ZOO1_HOME/bin/zkServer.sh start
    $ZOO2_HOME/bin/zkServer.sh start
    $ZOO3_HOME/bin/zkServer.sh start

    ;;
  stop)
    $ZOO1_HOME/bin/zkServer.sh stop
    $ZOO2_HOME/bin/zkServer.sh stop
    $ZOO3_HOME/bin/zkServer.sh stop
    ;;
  restart)
    $0 stop
    sleep 1
    $0 start
    ;;
  *)
   echo  "Usage: $0 {start|stop|restart}"
esac

이제 실행해보자!
잘된다!
다시 접속해보자!

./bin/zkCli.sh -server localhost:2184

그리도 노드를 한개더 생성해보자

[zk: localhost:2184(CONNECTED) 0] create /test test
Created /test
[zk: localhost:2184(CONNECTED) 0] ls /

test가 있는 걸 확인 후 빠져나오자 quit

./bin/zkCli.sh -server localhost:2185

이번엔 2185로 접속해보자

[zk: localhost:2185(CONNECTED) 0] ㅣls /

test가 있는걸 확인 할 수 있다.

2186 포트는 마찬가지로 추가 되어있을 것이다.

별도로 주키퍼 관리할 수 있는 관리자 화면을 누군가가 만들었다.
클로저로 만들었으니 클로저를 설치하자!
주키퍼웹UI