💡산술 연산자
산술 연산자에는 사칙연산에 해당하는 +, -, *, /와 나머지 %가 있다.
2항 연산자이며, 피연산자를 숫자형(정수, 실수)으로 가진다.
정수형 연산
int a = 10;
int b = 3;
System.out.printf("%d + %d = %d\n", a, b, a + b); // 10 + 3 = 13
System.out.printf("%d - %d = %d\n", a, b, a - b); // 10 - 3 = 7
System.out.printf("%d * %d = %d\n", a, b, a * b); // 10 * 3 = 30
System.out.printf("%d / %d = %d\n", a, b, a / b); // 10 / 3 = 3
System.out.printf("%d %% %d = %d\n\n", a, b, a % b); // 10 % 3 = 1
이때 printf() 메소드에서 큰따옴표 안에 %를 하나만 쓰면 에러가 난다는 점을 주의하자.
이미 Java 내에서 나머지를 계산하는 기능이 있기 때문에 %% 두 번 사용함으로써 콘솔에 출력할 수 있다.
실수형 연산
System.out.println(10 / 3); // 3, 정수끼리의 연산은 정수가 된다.
System.out.println(10.0 / 3); // 3.3333333333333335
System.out.println(10.0 / 3.0); // 3.3333333333333335
System.out.println(10 / 3.0); // 3.3333333333333335
실수를 연산하는 경우, 하나라도 실수가 연산에 사용되면 결과로 실수가 출력된다.
Infinity
System.out.println(100 / 0.0); // Infinity
System.out.println(-100 / 0.0); // -Infinity
나누기 연산을 할 때, 0.0으로 나누는 경우 Infinity 또는 -Infinity가 출력된다.
자료형 변환
System.out.println(10 / 3); // int / int = int
System.out.println(10.0 / 3); // double / int = double
System.out.println(10.0 / 3.0); // double / double = double
System.out.println(10 / 3.0); // int / double = double
모든 산술 연산자의 결과 자료형은 두 피연산자의 자료형 중 더 크기가 큰 자료형으로 반환된다.
int / int를 연산한 경우 int형으로 결과가 출력되며, double이 연산에 사용된 경우 double의 자료형이 가장 크기 때문에 double형으로 결과가 출력된다.
오버플로우 발생
int e = 1000000000;
int f = 2000000000;
// int + int 이므로 오버플로우 발생
System.out.println(e + f); // 30억이 아닌 -1294967296 출력
// 피연산자 중 하나를 long형으로 형변환
System.out.println((long)e + f);
위로 넘치는 현상을 Overflow, 아래로 넘치는 현상 Underflow라고 하는데, 소스코드에서 이러한 현상이 발생하고 있다. 오버플로우, 언더플로우는 형변환으로 해결이 가능하다.
형변환의 종류에는 암시적 형변환(자동 타입 변환), 명시적 형변환(강제 타입 변환)이 있으며, 위의 경우는 강제로 타입을 변환하는 명시적 형변환에 해당한다.
오버플로우는 컴파일 에러가 발생하지 않으므로 나중에 문제가 발생한 지점을 찾기 어려울 수 있다. 따라서 형변환을 통해 미연에 방지할 수 있도록 해야 한다.
💡비교 연산자
비교 연산자에는 >, >=, <, <=, ==(equals), !=(not equals)가 있다.
피연산자들의 우위를 비교하는 연산자이며, 피연산자는 숫자형을 가진다.
2항 연산자이며, 연산의 결과는 항상 boolean형으로 나온다는 특징이 있다.
정수형 비교
int a = 10;
int b = 3;
System.out.printf("%d > %d = %b\n", a, b, a > b);
System.out.printf("%d >= %d = %b\n", a, b, a >= b);
System.out.printf("%d < %d = %b\n", a, b, a < b);
System.out.printf("%d <= %d = %b\n", a, b, a <= b);
System.out.printf("%d == %d = %b\n", a, b, a == b);
System.out.printf("%d != %d = %b\n", a, b, a != b);
문자형 비교
System.out.println('A' == 'A'); // true
System.out.println('A' == 'a'); // false
문자열(참조형) 비교
String s1 = "Samsung";
String s2 = "Samsung";
String s3 = "Apple";
String s4 = "Sam";
s4 = s4 + "sung";
System.out.println(s4); // Samsung
System.out.println(s1 == s2); // true "Samsung" == "Samsung"
System.out.println(s1 == s3); // false
System.out.println(s1 == s4); // false "Samsung" == "Samsung"
모든 값형은 결과가 제대로 출력된다. 하지만 문자열의 비교는 주의가 필요하다.
위 소스코드를 보자. 비교할 때에는 분명히 같은 Samsung인데, 왜 전자는 true이고 후자는 false일까?
System.out.println(s1.equals(s2)); // true s1 == s2
System.out.println(s1.equals(s3)); // false s1 == s3
System.out.println(s1.equals(s4)); // true s1 == s4
그 이유는 문자열을 비교할 때 ==, != 연산자를 사용하지 않기 때문이다. 문자열의 비교는 equls() 메소드를 사용한다.
equls() 메소드를 사용했을 때 결과가 제대로 출력되는 것을 확인할 수 있다.
💡논리 연산자
논리 연산자에는 &&(and), ||(or), !(not), ^(not)가 있다.
이중 2항 연산자는 &&, ||, ^가 있으며, 1항 연산자로는 !가 있다.
피연산자를 대상으로 정해진 규칙을 따라 연산 결과를 반환하는 역할을 하며, 이때 피연산자의 자료형은 반드시 boolean이어야 한다.
논리곱
System.out.println(true && true); // 이렇게 사용하지 않는다.
int age = 20;
System.out.println((age > 19) && (age < 30));
논리곱은 AND 연산자를 나타내는 것으로, 주어진 두 개의 명제가 모두 참인 경우에만 결과가 참이 되고, 그 외의 경우에는 거짓이 된다.
논리 연산자 중 부정은 논리를 반대로 뒤집는 역할을 한다.
💡대입 연산자
대입 연산자는 할당 연산자 라고도 하며, =(equal)이 있다.
복합 대입 연산자 +=, -=, *=, /=, %=로 사용할 수 있다.
LValue(변수) = RValue(상수, 변수) 방식으로 작성하며, 이때 LValue와 RValue의 자료형은 반드시 동일해야 한다. 만약 자료형이 다를 경우 형변환을 통해 똑같이 맞춰주는 작업이 필요하다.
대입 연산자는 모든 연산자 중 우선 순위가 가장 낮다.
int n = 10;
복합 대입 연산자
n += 1;
System.out.println(n); // 11
n -= 2;
System.out.println(n); // 9
n *= 3;
System.out.println(n); // 27
💡증감 연산자
증감 연산자에는 ++(증가), --(감소)가 있다.
1항 연산자이며, 피연산자는 숫자형을 가진다.
누적 연산을 해서 기존의 값에 1을 더하거나 1을 빼는 연산을 하는데, 무조건 1씩만 더하거나 뺄 수 있다. 2를 더하거나 빼는 것은 불가능하다.
전치(전위 배치)와 후치(후위 배치)를 이용하여 연산자와 피연산자의 위치를 바꿀 수 있다. 위치에 따라 연산자의 우선 순위가 달라진다는 점에서 중요하다.
전치(전위 배치)
n = 10;
int result = 0;
result = 10 + ++n;
System.out.println(result); // 21
전치는 연산자는 우선 순위가 가장 높다.
전위 연산의 경우 증감 연산자가 1등이 된다. n은 11이 되고, 산술 연산자 +가 실행된 후 대입 연산자 =가 실행되어 result에 21이 저장된다.
후치(후위 배치)
n = 10;
result = 0;
result = 10 + n++;
System.out.println(result); // 20
후치는 연산자는 우선 순위가 가장 낮다.
후위 연산의 경우 산술 연산자가 먼저 실행되어 10 + 10이 대입 연산자로 인해 20이 result에 저장된다. 이후 증감 연산자가 실행되어 21이 되었지만, 우선 순위가 가장 낮으므로 저장되지 않았다.
++ n;
result = 10 + n;
System.out.println(result);
소스코는 최대한 알아보기 쉽게 작성하는 것이 좋다.
한 문장에 넣으면 헷갈리므로 증감 연산자를 다른 연산자와 한 문장에서 같이 사용하지 않도록 한다.
💡조건 연산자
조건 연산자는 A ? B : C 형태로 작성하며, A 조건이 참이면 B를 반환하며, 거짓이면 C를 반환한다.
A는 boolean값을 가지고, B, C: 상수 혹은 변수 값(데이터 값)을 가진다. 이때 문장이 오는 경우도 있지만 보통 데이터 값을 가진다.
유일한 3항 연산자로, 피연산자를 3개 필요로 한다는 특징이 있다.
boolean flag = true;
String m1 = "참";
String m2 = "거짓";
flag ? m1 : m2;
// 반환 값을 가지고 아무것도 하지 않으면 에러가 난다.
String result = flag ? m1 : m2;
System.out.println(result2); // 참
A 조건이 참이므로 B(참)가 출력된다. 반면 거짓일 경우 C(거짓)이 출력된다.
삼항연산자
try {
Scanner scan = new Scanner(System.in);
System.out.printf("나이: ");
age = scan.nextInt();
// 19세 이상 60세 미만이면 통과 or 거절
result = (age >= 19 && age < 60) ? "통과" : "거절";
System.out.printf("입력한 나이 %d세는 %s입니다.\n", age, result);
} catch(Exception ex)
{
}
위와 같이 삼항연산자를 활용할 수 있다.
💡비트 연산자
비트 연산자에는 &, |, ^, ~, <<, >>, >>>가 있다.
0과 1의 비트 단위 연산을 하며, 그중에서도 정수 타입의 비트 연산을 한다.
일반적인 프로그래밍에서는 사용하지 않고, 네트워킹 프로그래밍에서 사용되곤 한다.
a = 10;
b = 5;
System.out.println(a & b); // 0
a = 10;
b = 3;
System.out.println(a | b); // 11
And 연산은 양쪽 다 1이어야 1을 돌려준다. a는 1010, b는 0101 이므로 10 & 5는 0이 된다.
Or 연산은 하나라도 1이면 1을 돌려준다. a는 1010, 0011 이므로 10 | 3은 11이 된다.