Google AdSense


[Java] Short-circuit을 적용하지 않는 논리 연산자 by Sigel

지금까지 논리 연산자는 "&&"와 "||"만 사용해 왔었다. 그리고 논리 연산자는 모두 short-circuit이 적용되는 것으로만 알고 있었다. 헌데 어제 준오가 "&&" 말고 "&"만 쓰면 short-circuit이 적용되지 않는다는 얘기를 했다. 응?? 정말?? 그렇다고?? 가끔 오타로 "&&" 대신 "&"를 사용한 적이 있긴 하지만 그런 차이가 있는 줄 몰랐다. 일단 심심한 코드를 만들어 보자.

public static void main(String [] args)
{
    System.out.println("&& operator");
    if(returnTrue() && returnFalse())
        System.out.println("1");
    System.out.println();

    System.out.println("& operator");
    if(returnTrue() & returnFalse())
        System.out.println("2");
    System.out.println();

    System.out.println("|| operator");
    if(returnTrue() || returnFalse())
        System.out.println("3");
    System.out.println();

    System.out.println("| operator");
    if(returnTrue() | returnFalse())
        System.out.println("4");
    System.out.println();
}

private static boolean returnTrue()
{
    System.out.println("return true");
    return true;
}

private static boolean returnFalse()
{
    System.out.println("return false");
    return false;
}

결과~~
&& operator
return true
return false

& operator
return true
return false

|| operator
return true
3

| operator
return true
return false
4

너무 간단해서 눈물이 TㅅT retrunTrue(), returnFalse()는 말 그대로 true와 false를 반환해 준다. 세번째인 "||"를 보면 short-circuit이 적용되어서 returnFalse()가 호출되지 않은 것을 볼 수 있다. 헌데.. 정말 "|" 연산자를 사용한 결과를 보니 returnFalse()가 호출되었다!! 오호~~

지금 이 포스트에 short-circuit 링크를 걸기 위해 위키피디아에서 찾아보니 Standard operator와 Short-circuit operator가 나뉘어져 있다. 내용을 보니 Java만 해당하는 것이 아니라 대부분의 언어가 short-circuit을 선택적으로 사용할 수 있도록 지원하고 있다. 하지만 여태 책과 수업을 통해 배울 때는 standard operator에 대한 언급은 못 본거 같다. 모지?? -ㅅ-a


예전에 다음과 같은 실수를 한 적이 있다. 아래와 같은 TestMap이라는 클래스가 있다. Map의 일종으로 key에 value를 저장하는 클래스라고 생각하자. 그리고 key에 value를 할당하는 put()메소드는 기존에 할당된 값이 있어서 그 값이 변경되게 되면 true를 반환한다고 하자. (물론, 일반적인 map의 put()은 기존에 할당된 value를 반환하는게 보통이지만 이건 예제니까.. -ㅅ-;;) 이 map에 값을 3번 넣었다. 그리고 값을 넣을 때 동일한 key에 value를 할당한 경우 기존의 key에 있는 value는 없어지기 때문에 if문으로 확인을 했다.

public static void main(String [] args)
{
    boolean changed = false;

    TestMap map = new TestMap();
    changed = changed || map.put(1, 2); // 1
    changed = changed || map.put(1, 3); // 2
    changed = changed || map.put(2, 4); // 3

    if(changed)
    {
        System.out.println("We lost some value");
    }
}

class TestMap
{
    /**
     * 주어진 key에 value를 할당한다.
     * key에 이미 할당된 value가 있어 기존의 값이 변경되는 경우 true를 반환한다.
     * @param key 주어진 value를 할당할 map의 key
     * @param value 주어진 key에 할당될 map의 value
     * @return 주어진 key에 해당하는 기존 값이 변경되면 true, 그렇지 않으면 false
     */
    public boolean put(int key, int value)
    {
        ...
    }
}

여기서 문제는.. short-circuit을 생각하지 않고 changed를 계산했다는 것이다. 1번째 put()는 순조롭게 추가되고 기존의 값이 변경되지 않았으므로 false를 반환할 것이다. 그리고 2번째 put()를 수행하면 기존의 1에 2라는 값이 있었는데 3으로 변경이 되므로 true를 반환할 것이다. 그러면 changed는 true로 변경이 되어 3번째 put()은 수행이 되지 않고 바로 빠져나오게 되어 문제가 된다. map에는 모두 넣고, 변경된 것이 있는지만 알고 싶은데 수행을 안 하면 문제지..

해결방법은?? 간단하다. changed와 map.put()의 위치를 바꾸거나.. 아니면 위에 쓴 것처럼 short-circuit을 사용하지 안는 "|"을 사용한다. 참~~ 쉽죠잉~~?? 예제가 억지 예제라 이해하기 어렵다는게 문제지..@ㅅ@

    changed = map.put(1, 2) || changed; // 1
    changed = map.put(1, 3) || changed; // 2
    changed = map.put(2, 4) || changed; // 3

    changed = changed | map.put(1, 2); // 1
    changed = changed | map.put(1, 3); // 2
    changed = changed | map.put(2, 4); // 3


트랙백

이 글과 관련된 글 쓰기 (트랙백 보내기)
TrackbackURL : http://entireboy.egloos.com/tb/4178378 [도움말]

덧글

덧글 입력 영역