나를 기록하다
article thumbnail
반응형

2. 단항 연산자

2.1 증감 연산자 ++ --

  1. 전위형 : 값이 참조되기 전에 증가시킴. ex) j = ++i;
  2. 후위형 : 값이 참조된 후에 증가시킴. ex) j = i++;

 

2.2 부호 연산자 + -

  • 부호 연산자는 boolean 형과 char 형을 제외한 기본형에만 사용할 수 있다.

 

3. 산술 연산자

 
  •  int / int → int : 나누기 연산자의 두 연산자의 피연산자가 모두 int 타입인 경우 결과값도 int 타입이다.
    ex) 10 / 4 = 2 ( 2.5에서 int 타입은 소수점 이하의 값은 버리기에 2가 출력된다.)
    → 올바른 연산결과를 얻기 위해서는 두 피연산자 중 어느 한 쪽을 실수형으로 형변환해야 함.
    → 10 / 4.0f = 2.5f (float 타입이 int 타입보다 범위가 넓으므로 float 타입으로 일치시킨다.)
  • 피연산자가 정수형인 경우, 나누는 수로 0을 사용할 수 없다 → 만일 0으로 나누면 오류(ArithmeticException) 출력
  • 부동 소수점 값인 0.0f, 0.0d로 나누는 것은 가능하지만 그 결과는 Infinity(무한대)이다.
  • 나눗셈 연산자(Division) ‘/’와 나머지 연산자(Modulus) ‘%’의 피연산자가 무한대(Infinity) 또는 0.0인 경우의 결과
  • 피제수(Dividend), 제수(Divisor), 몫(Quotient)
x y x / y x % y
유한수 ±0.0 ±∞ NaN
유한수 ±∞ ±0.0 x
±0.0 ±0.0 NaN NaN
±∞ 유한수 ±∞ NaN
±∞ ±∞ NaN NaN

NaN(Not a Number) → 숫자가 아니라는 뜻

 

3.1 연산에서 에러 발생의 원인

  • [예제] byte 타입의 덧셈 연산
public class Operator {
    public static void main(String[] args) {
        byte a = 10;
        byte b = 20;
        byte c = a + b; // -> 에러 발생!
        System.out.println(c);
    }
}
  • 에러 발생 이유
    연산자 ‘+’는 이 두 개의 피연사자들의 자료형을 int 형으로 변환한 다음 연산(덧셈)을 수행
    byte의 값을 1 byte의 변수에 형변환없이 저장하려고 했기 때문에 에러 발생
    ‘byte c = a + b;’ ⇒ ‘byte c = (byte)(a + b);와 같이 변경해야 컴파일 에러가 발생하지 않음.
    따라서 ‘a+b’의 연산결과는 byte 형이 아닌 int형(4 byte)임.
    a와 b는 모두 int 형보다 작은 byte 형
  • [예제] 1_000_000 x 2_000_000 = ?
public class _03_OperatorEx3 {
    public static void main(String[] args) {
        long a = 1_000_000 * 1_000_000;
        long b = 1_000_000 * 1_000_000L;

        System.out.println("a = " + a);
        System.out.println("b = " + b);
    }
}
// 결과
a = -727379968
b = 1000000000000

a의 경우 int 타입 x int 타입인데 연산결과가 int 타입의 최대값인 약 2 x 10⁹를 넘으므로 오버플로우가 발생

→ 오버플로우가 발생한 값을 아무리 long 타입의 변수에 저장을 해도 소용이 없다.

b의 경우 int 타입 x long 타입의 연산이기에 결과가 long 타입이므로 올바른 결과를 얻을 수 있음.

 

  • 같은 의미의 식이지만 연산의 순서에 따른 결과의 차이
public class _04_OperatorEx4 {
    public static void main(String[] args) {
        int a = 1000000;

        int result1 = a * a / a;
        int result2 = a / a * a;

        System.out.printf("%d * %d / %d = %d%n", a, a, a, result1);
        System.out.printf("%d * %d / %d = %d%n", a, a, a, result2);
    }
}
// 결과
1000000 * 1000000 / 1000000 = -727
1000000 * 1000000 / 1000000 = 1000000

a * a 부터 실시할 경우 오버플로우가 발생, a * a = -727379968, a* a / a = -727

a / a = 1, a / a * a = 1000000

→ 같은 의미의 식이라도 연산의 순서에 따라 다른 결과를 얻을 수 있음!

 

3.2 연산 - 숫자와 영문자의 유니코드

  • [예제] 문자의 연산(유니코드)
public class _05_CharOperationEx {
    public static void main(String[] args) {
        char a = 'a';
        char d = 'd';
        char zero = '0';
        char two = '2';

        System.out.printf("'%c'-'%c'=%d%n", d, a, d-a);
        System.out.printf("'%c'-'%c'=%d%n", two, zero, two - zero);
        System.out.printf("    '%c'=%d%n", a, (int)a);
        System.out.printf("    '%c'=%d%n", d, (int)d);
        System.out.printf("    '%c'=%d%n", zero, (int)zero);
        System.out.printf("    '%c'=%d%n", two, (int)two);
    }
}
// 결과
'd'-'a'=3
'2'-'0'=2
    'a'=97
    'd'=100
    '0'=48
    '2'=50

문자는 실제로 해당 문자의 유니코드(부호없는 정수)로 바뀌어 저장됨, 주로 문자간의 뺄셈을 하는 경우가 대부분임

ex) 문자 ‘2’를 숫자로 변환하려면? ‘2’ - ‘0’ → 50 - 48 → 2

 

 

3.2.1 숫자와 영문자의 유니코드

문자
코드
문자
코드
문자
코드
0
48
A
65
a
97
1
49
B
66
b
98
2
50
C
67
c
99
3
51
D
68
d
100
4
52
E
69
e
101
5
53
6
54
W
87
w
119
7
55
X
88
x
120
8
56
Y
89
y
121
9
57
Z
90
z
122
  • [예제] 문자와 숫자의 연산
public class _06_CharOperationEx2 {
    public static void main(String[] args) {
        char c1 = 'a';
        char c2 = c1;
        char c3 = ' ';

        int i = c1 + 1; // 98

        c3 = (char)(c1 + 1); // 'b'
        c2++; // 98
        c2++; // 99

        System.out.println("i = " + i); // i = 98
        System.out.println("c2 = " + c2); // c2 = c
        System.out.println("c3 = " + c3); // c3 = b
    }
}
// 결과
i = 98
c2 = c
c3 = b

→ c2++ 은 c2에 저장되어 있는 값을 1 증가시킴 → 1씩 두번 증가되었기에 99, 코드값이 10진수로 99인 문자는 ‘c’이기에 ‘c’가 출력

 

  • [예제] char 타입과 int 타입간의 연산
public class _07_CharOperationEx3 {
    public static void main(String[] args) {
        char c1 = 'a';

//        char c2 = c1 + 1; // 컴파일 에러 발생
        char c2 = 'a' + 1; // 컴파일 에러 없음
        System.out.println(c2);
    }
}
// 결과
b

덧셈 연산자와 같은 이항 연산자는 int 보다 작은 타입의 피연산자를 int 로 자동 형변환한다고 배웠는데 문제가 없는 이유?

‘a’ + 1 이 리터럴 간의 연산이기 때문! : 상수 또는 리터럴 간의 연산은 실행 과정동안 변하는 값이 아니기 때문에 컴파일 시에 컴파일러가 계산해서 그 결과로 대체함으로써 코드를 보다 효율적으로 만든다.

 

  • 컴파일러에 의해서 최적화된 코드 비교
컴파일 전의 코드 컴파일 후의 코드
char c2 = ‘a’ + 1; int sec = 60 * 60 * 24; char c2 = ‘b’; int sec = 86400;

라인 5와 같이 수식에 변수가 들어가 있는 경우에는 컴파일러가 미리 계산을 할 수 없음. → 형변환을 해주지 않을 시 에러 발생 

 

  • 코드의 가독성과 유지보수성을 위해 리터럴 연산을 풀어쓰는 경우 존재
컴파일 전의 코드 컴파일 후의 코드
char c2 = ‘a’ + 1; int sec = 60 * 60 * 24; char c2 = ‘b’; int sec = 86400;

ex) int 타입의 변수 sec에 하루(day)를 초(second) 단위로 변환한 값을 저장하는 코드 → ‘86400’ 이라는 값 보다는 ‘60 * 60 * 24’ 

 

  • [예제] 문자의 출력(유니코드)
public class _08_CharOperationEx4 {
    public static void main(String[] args) {
        char c = 'a';
        for(int i=0; i<26; i++) {
            System.out.print(c++); // abcde...xyz
        }
        System.out.println();

        c = 'A';
        for(int i=0; i<26; i++) {
            System.out.print(c++); // ABCDE...XYZ
        }
        System.out.println();

        c='0';
        for(int i=0; i<10; i++) {
            System.out.print(c++); // 0123456789
        }
    }
}
// 결과
abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ
0123456789

→ 알파벳은 총 26개이며 대문자와 소문자 간의 코드값 차이는 10진수로 32이다.

 

  • [예제] 소문자를 대문자로 변경하기
public class _09_LowerCaseToUpperCase {
    public static void main(String[] args) {
        char lowerCase = 'a';
        char upperCase = (char)(lowerCase - 32);
        System.out.println(upperCase); // 65 -> 'A'
    }
}
// 결과
A

 

  • [예제] int / float
public class _10_IntDividedFloat {
    public static void main(String[] args) {
        float pi = 3.141592f;
        float shortPi = (int)(pi*1000)/1000f;
        System.out.println(shortPi); // 3.141
    }
}
// 결과
3.141

 

  • [예제] 반올림하는 방법
public class _11_RoundMethod1 {
    public static void main(String[] args) {
        double pi = 3.141592;
        double shortPi = (int)(pi*1000+0.5)/1000.0;

        System.out.println(shortPi); // 3.142
    }
}
// 결과
3.142

 

  • [예제] Math.round() 사용
public class _12_MathRound {
    public static void main(String[] args) {
        double pi = 3.141592;
        double shortPi = Math.round(pi*1000)/1000.0;

        System.out.println(shortPi); // 3.142
    }
}
// 결과
3.142

round 메서드는 매개변수로 받은 값을 소수점 첫째자리에서 반올림하고 그 결과를 정수로 돌려주는 메서드

 

3.3 나머지 연산자(Modulus) %

  • 나머지 연산자의 사용 → 주로 짝수, 홀수, 배수 검사 등에 사용
  • [예제] 나머지 연산자 활용 예제 - 홀수, 짝수 검사
public class _13_Modulus {
    public static void main(String[] args) {
        for (int i=1; i<10000; i=i*3+1) {
            if(i%2 == 0) {
                System.out.printf("%d는 짝수입니다.%n", i);
            } else {
                System.out.printf("%d는 홀수입니다.%n", i);
            }
        }
    }
}
// 결과
1는 홀수입니다.
4는 짝수입니다.
13는 홀수입니다.
40는 짝수입니다.
121는 홀수입니다.
364는 짝수입니다.
1093는 홀수입니다.
3280는 짝수입니다.
9841는 홀수입니다.
​
 
반응형
profile

나를 기록하다

@prao

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

profile on loading

Loading...