본문 바로가기

언어/자바

자바 자료형 사용 시 주의

1. 무한대 비교는 하지 마라.

아래 코드는 무한루프에 빠진다.

public void test1() {                   
    double t = Double.POSITIVE_INFINITY;
    while(t == t+1) {                   
                                        
    }                                   
    System.out.println("end");          
}                                       

이유는 무한대에 값을 더해도 무한대이기 때문에 == 이 true로 성립

 

2. NaN을 비교 하지마라.

아래 코드는 무한루프에 빠진다.

public void test2() {          
    double t = 0.0/0.0;        
    while(t != t) {            
                               
    }                          
    System.out.println("end"); 
}                              

이유는 0.0/0.0은 NaN이 나오는데, 이 것은 숫자가 아니라는 뜻이다.

이 값은 본인을 비롯한 어떠한 수와도 일치하지 않는다.

 

3. 자료형 변환에 주의하라.

public void test4() {          
    short t = -1;              
    while(t != 0) {            
        t >>>=1 ;              
    }                          
    System.out.println("end"); 
}                              

>>>=은 복합 대입연산자이다. >>>는 비트를 옮기는데, 새로운 공간을 0으로 채운다.

예를 들어 0101 >>> 1 은 0010 이고, 1100 >>>1 은 0110 이다.

따라서 위 코드는 16번의 루프 후에 end를 출력할 것이다.

 

하지만 실제로는 무한루프에 빠진다. 

이유는 오버플로우때문이다.

 

>>> 1 연산을 할 때 short는 int형으로 변경된다. 이 때 자료형 확장이 일어나고 -1은 음수라서 상위비트가 1이다.

따라서 1의 확장이 일어난다.

결과적으로 11111111 11111111 11111111 11111111 비트를 >>>1 하게 되면 01111111 11111111 11111111 11111111 인데 

이 것을 다시 short로 자동 형변환해서 대입하게 된다. (복합 대입연산자는 자동 형변환을 해준다)

 

그러면 다시 11111111 11111111이 된다.

이것이 반복되면 무한루프가 된다.

자료형 변환은 항상 주의하라.

가급적 byte, short, char은 복합 대입연산자 사용을 자제하자.

 

4. 래퍼 클래스 비교시 주의하자.

public void test5() {                                  
    //d1 <= d2 && d1 >=d2 && d1!=d2 이 true가 되려면?       
    Character d1 = new Character('a');                 
    Character d2 = new Character('a');                 
                                                       
    System.out.println(d1 <= d2 && d1 >=d2 && d1!=d2); 
}                                                      

위 코드는 true를 출력한다. 

 

5. 오버플로우를 주의하자.

public void test6() {                   
    //i==-i && i!=0 을 true가 되게 하려면?     
    int i = Integer.MIN_VALUE;          
                                        
    while(i==-i && i != 0) {            
                                        
    }                                   
    System.out.println("end");          
}

이 코드는 무한 루프에 빠진다.

이유는 int의 표현범위와 2의 보수 개념을 살펴보면 알 수 있다.

int는 2의 23승 개의 수를 표현가능한데, 0을 빼면 홀수개의 정수를 표현할 수 있다.

이 때 음의 정수가 1개 더 많은데, 이것이 Integer.MIN_VALUE이다.

 

이 값을 부호 변환하면 2의 보수가 이뤄지는데, 1의 보수한 결과에 1을 더하게 된다.

Integer.MIN_VALUE의 1의 보수(2의 보수 아니다. 1의 보수다!) 의 결과는 Integer.MAX_VALUE인데,

여기에 1을 더하면 오버플로우가 발생해서 다시 Integer.MIN_VALUE가 된다.

 

따라서 무한루프가 발생한다.

항상 오버플로우를 주의하자. 특히 큰 값을 다룰때.

 

6. float은 가급적 사용하지 말자.

public void test7() {               
    float t1 = 2000000000;          
    float t2 = 2000000050;       
    System.out.println(t1 != t2);   
}                                   

놀랍게도 true를 출력한다.

이유는 float의 정확한 값 범위를 ㄴ넘어섰기에 값 버림이 이뤄지기 때문이다.

 

가능하면 double을 사용하여 실수를 표현하자.