[Java] 연산자
자바에서 사용할 수 있는 연산자들에 대해 살펴보자.
산술 연산자
연산자 | 설명 | 예 |
---|---|---|
+ | 덧셈 | 1+2=3 |
- | 뺄셈 | 2-1=1 |
* | 곱셈 | 2*3=6 |
/ | 나누기 몫 | 7 / 3 = 2 |
% | 나누기 나머지 | 7 % 3 = 1 |
public class ArithmeticOperators {
public static void main(String[] args) {
int a = 11;
int b = 4;
System.out.println("a : " + a);
System.out.println("b : " + b);
System.out.println("덧셈 : " + (a + b));
System.out.println("뺄셈 : " + (a - b));
System.out.println("곱셈 : " + (a * b));
System.out.println("나눗셈의 몫 : " + (a / b));
System.out.println("나눗셈의 나머지 : " + (a % b));
}
}
a : 11
b : 4
덧셈 : 15
뺄셈 : 7
곱셈 : 44
나눗셈의 몫 : 2
나눗셈의 나머지 : 3
대입 연산자
자바에서 대입 연산자는 등호 기호(=)로, 오른쪽 항의 데이터를 왼쪽 항의 변수에 할당한다.
char alp = 'A';
또한, 복합 대입 연산자도 존재한다.
연산자 | 같은 표현 |
---|---|
a += b | a = a + b |
a -= b | a = a - b |
a *= b | a = a * b |
a /= b | a = a / b |
a %= b | a = a % b |
위 표에서, 오른쪽 열에 있는 일반적인 대입 방법과 달리, 복합 대입 연산자만의 특징은, 두 피연산자들의 자료형이 다를 경우, 강제 형변환이 필요하지 않다는 것이다. 즉, 자동 형변환이 일어난다. 위 표의 오른쪽 열과 같이 일반 대입 연산자를 이용한다면, 두 피연산자의 자료형이 다를 때, 왼쪽 항의 변수에 오른쪽 연산 결과값을 할당하고자 한다면 강제 형변환이 필요하다.
public class AssignOperators {
public static void main(String[] args) {
// 복합 대입 연산자 예
int a = 1;
a += 10l; // 자동 형변환
System.out.println(a);
a = (int)(a + 20l); // 강제 형변환
System.out.println(a);
}
}
11
31
부호 연산자
부호 연산자는 숫자의 양수, 음수를 나타낼 때 사용되는 연산자이다.
public class signOperator {
public static void main(String[] args) {
int positive = +1;
int negative = -1;
int normal = 1;
System.out.println(positive);
System.out.println(negative);
System.out.println(normal);
System.out.println(positive == normal); // positive와 normal은 같은가?
}
}
1
-1
1
true
숫자 앞에 + 기호를 생략해도 해당 숫자는 양수로 인식된다. (이는 수학에서도 동일하다)
증감 연산자
숫자 데이터 앞이나 뒤에 ‘+’ 기호 또는 ‘-’ 기호를 두 번 연속 작성한 ‘++’, ‘--’ 기호는 각각 해당 숫자를 1만큼 증가 또는 감소시키는 연산자이다. 그런데 숫자 데이터의 앞에 쓰느냐 뒤에 쓰느냐에 따라 증감 효과 적용 순서가 바뀐다. 다음 예제를 보자.
public class incDecOperator {
public static void main(String[] args) {
// 증감 연산자 관련 예제
int a = 10;
int b = a++;
int c = ++a;
System.out.println(a);
System.out.println(b);
System.out.println(c);
}
}
12
10
12
int b = a++;
코드를 보면, a 변수 뒤에 ‘++’라는 증가 연산자가 쓰였다. 이렇게 증가 연산자가 숫자 데이터의 뒤에 붙으면, 먼저 변수 b에 a의 값을 대입하는 연산이 먼저 진행된다. 그 후에 변수 a의 값이 1 증가한다. 위 예제에서는 변수 b의 선언과 할당이 이뤄지면 b = 10, a = 11인 상태이다. 그 다음, int c = ++a;
코드를 만나면, 증가 연산자 ‘++’가 변수 a의 앞에 붙어있다. 이 경우 아까와는 다르게 연산 순서가 바뀐다. 즉, a의 값이 먼저 1 증가한 다음, 그 후에 변수 c에 a의 값이 할당된다. 따라서 a가 12가 된 후에 그 12가 변수 c에 할당된다. 따라서 위와 같은 결과가 나온다.
즉, 정리하면 다음과 같다.
- ++a, --a 와 같이 증감 연산자가 숫자 데이터 앞에 존재하는 경우, 해당 숫자가 먼저 1 증가(또는 감소)한 뒤에 다른 연산이 뒤이어 진행된다.
- a++, a--와 같이 증감 연산자가 숫자 데이터 뒤에 존재하는 경우, 다른 연산이 먼저 진행된 뒤에 a의 값이 1 증가(또는 감소)한다.
비교 연산자 (관계 연산자)
비교 연산자는 두 피연산자를 비교한 결과에 따라 true 또는 false를 반환한다.
연산자 | 설명 |
---|---|
== | 두 피연산자의 값이 같으면 true, 아니면 false를 반환. |
!= | 두 피연산자의 값이 다르면 true, 아니면 false를 반환. |
> | a > b ⇒ a가 b보다 크면 true, 아니면 false를 반환. |
>= | a >= b ⇒ a가 b보다 크거나 같으면 true, 아니면 false를 반환. |
< | a < b ⇒ a가 b보다 작으면 true, 아니면 false 반환. |
<= | a <= b ⇒ a가 b보다 작거나 같으면 true, 아니면 false를 반환. |
논리 연산자
연산자 | 설명 | 예시 |
---|---|---|
&& | 논리곱, And. 두 항이 모두 true이면 true를, 하나라도 false면 false를 반환. | (1!=2) && (1>=2) ⇒ true |
|| | 논리합, Or. 두 항 중 하나라도 true이면 true, 모두 거짓이면 false를 반환 | (3%2==0) || (3 > 2) ⇒ false |
! | 부정, Not. 값이 true이면 false를, 값이 false면 true로 변환. | !(2==2) = false |
참고. 0을 false, 0을 제외한 나머지 수를 true라 생각하면… 논리곱의 경우. 우선 논리곱 대신 곱셈 연산을 각각 해본다면…
1 * 1 = 1 1 * 0 = 0 0 * 1 = 0 0 * 0 = 0
그런데 위 결과에서 곱셈 연산을 && 연산자로 변경해도 성립된다. 논리곱이 헷갈리면 이렇게 알아둬도 기억하기 쉬울 것이다. 논리합에 대해서도, 먼저 덧셈 연산에 대해 진행해보면…
1 + 1 = 2 1 + 0 = 1 0 + 1 = 1 0 + 0 = 0
여기서, 보통의 프로그래밍 언어들에서 그러하듯, 0을 false, 0 이외의 모든 수를 true라 가정한다면, 위 표에서 덧셈 연산을 논리합(||) 연산자로 변경해도 성립된다. 논리합의 경우의 수가 헷갈린다면 위와 같이 생각하면 기억하기 쉬울 것이다.
논리 연산자는 비교 연산자와 합쳐 쓰면 조건문으로 사용할 수 있음을 알 수 있다.
Short-Circuit Evaluation (최단 거리 평가, SCE)
자바스크립트에서 JS - [기본 문법] 조건문 (해당 페이지 준비 중) 의 “단축 평가” 챕터에서도 같은 이야기를 언급하였다.
true 또는 false를 반환하는 어떤 비교 연산식 A, B가 있다고 가정해보자. 그러면 논리곱의 경우, A && B 가 있다면, A만 false이면 그 뒤에 B가 true이든 false이든 상관없이 자동으로 해당 논리 연산식은 false가 된다. 그래서 B의 연산 결과를 굳이 알 필요가 없어진다. 논리합도 마찬가지로, A || B가 있을 때, A가 true이면, B가 true이든 false이든 상관없이 해당 논리 연산 결과는 자동으로 true로 결정된다. 따라서 이러한 경우, 그 뒤의 B 연산식은 연산이 수행되지 않아도 된다. 이는 자바에서도 마찬가지이다. 즉, 위와 같은 경우일 경우, 논리 연산자 뒤의 연산식은 연산되지 않고 다음으로 넘어간다. 이러한 현상을 Short-Circuit Evalution이라 한다.
정말로 SCE 현상이 사실일까? 다음의 코드를 보자.
public class SCE {
public static void main(String[] args) {
// Short-Circuit Evalution 예제
int math = 90;
int english = 95;
// 조건문 1
if (math++ % 2 == 0 || english++ % 2 == 0) {
System.out.println("적어도 점수 하나는 짝수이다.");
} else {
System.out.println("모든 점수가 홀수이다.");
}
System.out.println("math: " + math);
System.out.println("english: " + english);
System.out.println("=========");
// 조건문 2
if (math++ >= 100 && english++ >= 100) {
System.out.println("점수가 이상합니다.");
}
System.out.println("math: " + math);
System.out.println("english: " + english);
}
}
적어도 점수 하나는 짝수이다.
math: 91
english: 95
=========
math: 92
english: 95
위 코드에서 만약 SCE 현상이 존재하지 않았다면, 각 논리 연산자 뒤의 연산식도 실행되었을 것이다. 즉, english++ 연산이 실행되어 english 변수값도 초기값보다 증가했을 것이다. 그런데 위 코드의 실행결과를 보면 math 변수값의 값만 증가하였을 뿐, english 변수값은 전혀 증가되지 않았음을 알 수 있다. 각각 논리 연산자의 앞에 나오는 연산식만 보고, 해당 연산식의 boolean 결과값이 논리 연산식의 전체값을 결정한다면 그 뒤의 연산식은 실행되지 않음을 알 수 있다.
이는 논리 연산자의 뒤에 존재하는 연산식도 실행되었을 때에 비하면 상대적으로 연산 속도가 빠를 것이다. 따라서 위 사실을 잘 이용하여 논리곱의 경우, false 값이 나올 가능성이 높은 연산식을 맨 앞에 배치하거나, 논리합의 경우, 결과값이 true가 나올 가능성이 높은 연산식을 맨 앞에 배치하면 전체적인 연산 속도를 조금이라도 더 높일 수 있겠다.
조건 연산자
조건 연산자는 총 3개의 항을 사용하는 삼항 연산자로, 조건식이 참일 때와 거짓일 때의 경우에 따라 실행되는 것이 달라지는 연산자이다. 형태는 다음과 같다.
조건식 ? 참일 때 실행 : 거짓일 때 실행;
다음은 조건 연산자를 활용하여 두 수의 양의 차를 구하는 예제이다.
public class condOperator {
public static void main(String[] args) {
// 조건 연산자 예제.
int a = 10;
int b = 20;
// 조건 연산자를 이용하여 두 수의 양의 차이를 구한다.
// 조건식 ? 참일 경우 실행 : 거짓일 경우 실행;
int positiveDiff = (a > b) ? (a - b) : (b - a);
// 조건식 (a > b)가 거짓이므로, (b - a)식이 실행된 결과값이 해당 변수에 할당됨.
System.out.println(positiveDiff);
}
}
10
References
[1] 이재환, “이재환의 자바 프로그래밍 입문”, (골든래빗, 2021)
This content is licensed under
CC BY-NC 4.0
댓글남기기