2. 단항 연산자
2.1 증감 연산자 ++ --
- 전위형 : 값이 참조되기 전에 증가시킴. ex) j = ++i;
- 후위형 : 값이 참조된 후에 증가시킴. 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는 홀수입니다.
'Java > Java의 정석' 카테고리의 다른 글
[Java의 정석/2-5] 논리 연산자 (1) | 2023.03.15 |
---|---|
[Java의 정석/2-4] 비교 연산자 (0) | 2023.03.15 |
[Java의 정석/2-1] 연산자(Operator) (1) | 2023.03.05 |
[Java의 정석/1-5] 형변환(Casting) (0) | 2023.03.05 |
[Java의 정석/1-4] 기본형 (0) | 2023.03.05 |