산술 연산자
수학적 연산에 사용되는 연산자다. 기본적으로 알고 있는 덧셈, 뺄셈, 나눗셈, 곱셈에서 사용되는 연산자이고, 여기서 몇가지의 연산자가 더 추가된다.
산술연산자는 boolean을 제외한 기본형 타입의 값의 연산에 사용할 수 있다.
피연산자 중에 부동소수점이 있다면 결과도 부동소수점이 되고, 모두 정수라면 결과는 정수가 된다.
+ (더하기)
두 개 이상의 숫자를 더할 때 사용한다. 또한 문자열을 연결시키는 데에도 사용한다.
피연산자 중에 숫자와 문자열이 함께 있다면 문자열의 위치에 따라 결과가 달라진다.
연산 시 왼쪽에서 오른쪽 순서대로 되기 때문에 문자열 이전에 두 개 이상의 숫자가 나온다면 숫자끼리 연산이 된 다음 문자열 연결이 되고, 문자열이 나온 후에 숫자가 나온다면 문자열로 이미 타입이 바뀌었기 때문에 숫자는 문자열 뒤에 연결만 된다.
public static void main(String[] args) {
System.out.println(3 + 5 + "Hi"); // --> 8Hi
System.out.println("Hi" + 3 + 5); // --> Hi35
}
- (빼기)
두 개 이상의 숫자를 뺄 때 사용한다. 더하기처럼 문자열 연산을 하지 못한다.
* (곱하기)
두 개 이상의 숫자를 곱할 때 사용한다.
/ (나누기)
첫번째 피연산자가 두번째 피연산자로 나뉜다.
이 때 피연산자 둘 다 정수라면 결과에서 소수점이 발생하더라도 내림되어 정수만 반환한다.
둘 중 하나가 부동소수점이라면 결과에서 소수점도 같이 반환한다.
public static void main(String[] args) {
System.out.println(7 / 3); // --> 2
System.out.println(7 / 3.0); // --> 2.3333333333333335
}
단, 나눴을 때 정수 0으로 나눴을 때는 ArithmeticException 이 발생한다.
또한 부동소수점 0.0으로 나눴을 때는 Infinity또는 NaN이 출력된다.
public static void main(String[] args) {
System.out.println(3 / 0); // --> ArithmeticException 발생!!
System.out.println(3 / 0.0); // --> Infinity
System.out.println(0 / 0.0); // --> NaN
}
% (나머지)
첫번째 피연산자를 두번째 피연산자로 나누면 발생하는 나머지에 대해 반환한다.
public static void main(String[] args) {
System.out.println(8 % 3); // --> 2
}
단, 이 연산자 또한 위의 나누기 연산자처럼 정수, 부동소수점 0으로 나누었을 때 같은 에러가 발생한다.
public static void main(String[] args) {
System.out.println(3 % 0); // --> ArithmeticException 발생!!
System.out.println(3 % 0.0); // --> NaN
System.out.println(0 % 0.0); // --> NaN
}
- (단항 마이너스 연산)
하나의 숫자 앞에 - 연산을 붙이면 값의 부정이 수행된다.
public static void main(String[] args) {
int a = 1;
int b = -1;
System.out.println(-a); // --> -1
System.out.println(-b); // --> 1
}
비트 연산자
데이터를 비트단위로 연산할 때 비트연산자를 사용한다. 따라서 0과 1로 표현 가능한 정수형이나 정수형으로 캐스팅이 가능한 자료형만 피연산자로 연산가능하다. 비트 연산자는 기능에 따라 비트 이동 연산자와 비트 논리 연산자로 구분된다.
비트 이동 연산자
x << y | x를 y 비트만큼 왼쪽으로 이동한다. (빈자리는 0으로 채워진다.) |
x >> y | x를 y 비트만큼 오른쪽으로 이동한다. (빈자리는 정수 a의 최상위 부호비트와 같은값으로 채워진다.) |
x >>> y | x를 y 비트만큼 오른쪽으로 이동한다. (빈자리는 0으로 채워진다.) |
예를 들어 정의해보겠다.
2 << 3
왼쪽으로 3만큼 (y만큼) 이동하고 0으로 채워진 것을 볼 수 있다.
16 >> 3
위와 같이 밀려난 비트만큼 최상위 비트인 0으로 채워진것을 확인할 수 있다.
음수로 예를 들어보겠다.
-16 >> 3
최상위 비트부호에 따라 밀려난만큼 1로 채워진다.
-16 >>> 3
같은 피연산자이지만 위의 결과와 달리 빈자리가 최상위 비트부호가 아닌 0으로 채워진 것을 확인할 수 있다.
비트 논리 연산자
& | AND | 두 비트 모두 1일 경우 연산결과가 1, 아닐 경우 0 |
| | OR | 두 비트 중 하나가 1일 경우 연산 결과가 1, 아닐 경우 0 |
^ | XOR | 두 비트 중 하나는 1이고 다른 하나가 0일 경우 연산 결과가 1, 둘 다 같을 경우 0 |
~ | NOT | 비트의 반전(1의 보수) |
아래는 비트연산자 하나씩 예를 들어가며 이해보겠다.
& AND연산
public static void main(String[] args) {
System.out.println(15 & 25); // --> 9
}
그럼 결과가 9이 나온다. 연산과정은 다음과 같다.
같은 위치의 두 비트가 1인 경우에만 1이 되어 연산하면 결과가 9인 것을 확인할 수 있다.
| OR연산
public static void main(String[] args) {
System.out.println(15 | 25); // --> 31
}
결과는 31이 나온다. 연산 과정은 다음과 같다.
^ XOR연산
public static void main(String[] args) {
System.out.println(15 ^ 25); // --> 22
}
~ NOT연산
public static void main(String[] args) {
System.out.println(~25); // --> -26
}
관계 연산자
관계 연산자는 두 피연산자를 비교하며 boolean 값을 반환한다. true, false 값을 가려내기 때문에 조건문 연산자나 반복문 연산자를 수행할 때 비교연산자를 많이 사용한다. 이해하기 쉽기 때문에 코드로 예를 들고 가겠다.
== (Equal)
public static void main(String[] args) {
int a = 100;
int b = 100;
System.out.println(a == b); // --> true
b = 120;
System.out.println(a == b); // --> false
}
public static void main(String[] args) {
int a = 100;
float b = 100.0f;
double c = 100.5;
System.out.println(a == b); // --> true
System.out.println(b == c); // --> false
}
주의할 점은 참조 변수를 비교할 경우 같은 값인지 확인할 목적으로 이 연산자를 사용할 수 없다. 값이 같다고 해도 동일한 객체가 아니라면 false를 반환하기 때문이다.
!= (Not Equal)
public static void main(String[] args) {
int a = 100;
int b = 100;
System.out.println(a != b); // --> false
b = 300;
System.out.println(a != b); // --> true
}
>, >= (큼, 크거나 같음)
public static void main(String[] args) {
int a = 500;
int b = 100;
System.out.println(a > b); // --> true
System.out.println(a >= b); // --> true
a = 100;
System.out.println(a > b); // --> false
System.out.println(a >= b); // --> true
}
<, <= (작음, 작거나 같음)
public static void main(String[] args) {
int a = 100;
int b = 500;
System.out.println(a < b); // --> true
System.out.println(a <= b); // --> true
a = 500;
System.out.println(a < b); // --> false
System.out.println(a <= b); // --> true
}
논리 연산자
관계연산자와 동일하게 boolean을 리턴한다. 주로 여러개의 비교연산을 할 때 논리연산을 이용하여 true/false 값을 가려낸다.
&& (AND 연산)
두 피연산자 중에 하나라도 false라면 결과는 false다. true가 되려면 두 피연산자 모두 true여야 한다.
public static void main(String[] args) {
boolean a = true;
boolean b = false;
System.out.println(a && b); // --> false
b = true;
System.out.println(a && b); // --> true
}
|| (OR 연산)
두 피연산자 중 하나라도 true라면 true가 된다. 둘 다 false면 결과는 false이다.
public static void main(String[] args) {
boolean a = true;
boolean b = false;
System.out.println(a || b); // --> true
b = false;
System.out.println(a || b); // --> false
}
단락회로 평가 (&&, ||)
&&, || 연산자로 연산을 할 때 첫번째 피연산자의 값에 따라 결과가 나와 두번째 피연산자를 실행할 필요가 없을 때 실행이되지 않는다.
예를 들어 methodA()는 true를 반환하고, methodB()의 경우 false를 반환하는 메소드를 미리 생성해보겠다.
public boolean methodA() {
System.out.println("methodA() 실행");
return true;
}
public boolean methodB() {
System.out.println("methodB() 실행");
return false;
}
&& 연산자는 두 피연산자가 모두 true가 나와야 true가 된다. 하나라도 false가 되면 그 뒤에 나오는 피연산자의 결과를 볼 것도 없이 결과는 정해져있다. 따라서 첫번째 피연산자가 false일 경우 두번째 피연산자를 생략하고 결과가 출력된다.
하지만 첫번째 피연산자가 true일 경우에는 두번째 피연산자에 따라 결과가 달라진다. 따라서 두개의 피연산자를 모두 실행한다.
System.out.println(methodB() && methodA());
/*
출력 결과:
methodA() 실행
false
*/
System.out.println(methodA() && methodB());
/*
출력 결과:
methodA() 실행
methodB() 실행
false
*/
OR 연산자도 마찬가지이다. 첫번째 피연산자에서 true가 나온다면 결과는 true이기 때문에 두번째 피연산자를 실행할 필요가 없다. 따라서 두번째 피연산자는 생략되고 실행된다.
System.out.println(methodA() || methodB());
/*
출력 결과:
methodA() 실행
true
*/
! (부정 연산)
boolean 값의 반대의 결과를 출력하는 연산자다. true면 false를, false면 true를 반환한다.
public static void main(String[] args) {
boolean a = true;
System.out.println(!a); // --> false
a = false;
System.out.println(!a); // --> true
}
instanceof
참조값(객체 또는 배열)이 어떤 참조유형과 맞는 값인지 평가할 때 이 연산자를 사용한다. 보통 캐스팅하기 전 특정 참조 변수가 캐스팅 가능 여부가 확실하지 않은 경우 에러 발생 방지를 위하여 이 연산자를 사용하여 true를 확인하고 한다.
public static void main(String[] args) {
System.out.println("olivejua" instanceof String); // --> true
Object obj = new int[] {1,2,3};
System.out.println(obj instanceof int[]); // --> true
System.out.println(obj instanceof String[]); // --> false
}
대입 연산자 (=)
어떤 변수에 값을 할당할 때 이 연산자를 사용하며, 해당 값을 저장할 수 있는 메모리가 할당되거나 저장한다는 의미이다.
String a = "String type";
int b = 1;
또한 산술연산자와 대입연산자를 결합한 복합 대입연산자도 있다.
+= | 더하고 대입 |
-= | 빼고 대입 |
*= | 곲하고 대입 |
/= | 나누고 대입 |
%= | 나머지 대입 |
public static void main(String[] args) {
int a = 15;
System.out.println(a += 10); // --> 25
System.out.println(a -= 10); // --> 15
System.out.println(a *= 10); // --> 150
System.out.println(a /= 10); // --> 15
System.out.println(a %= 10); // --> 5
}
화살표 연산자 (->)
java8부터 추가된 기능으로, 람다식은 하나의 메소드를 하나의 식으로 표현한 것이다. 이 람다식에 사용되는 연산자가 화살표 연산자이다. 파라미터 목록, 연산자, 실행 내용 순서로 작성하면 된다. 또한 실행 내용이 한줄일 경우 {} 는 생략가능하다.
interface Operator
{
int add(int a, int b);
}
class Study {
public static void main(String[] args) {
Operator operator = new Operator() {
@Override
public int add(int a, int b) {
return a + b;
}
};
int result = operator.add(3, 5);
System.out.println(result); // --> 8
// 람다식
Operator operatorL = (int a, int b) -> a + b;
result = operatorL.add(3, 5);
System.out.println(result); // --> 8
}
}
위와 같이 operater의 경우 람다식이 표현하고자하는 메소드의 본래 형식이다. 이 코드를 좀 더 간결하게 하면 operaterL처럼 한줄로 표현할 수 있고 가독성도 좋은 것을 확인할 수 있다.
3항 연산자
3항 연산자는 (조건문) ? 참 : 거짓 의 형태로 if, else문을 간략한 형태로 사용하고 싶을 때 적합하다.
int a = 10;
int b = 20;
boolean result = a < b ? true : false;
System.out.println(result); // --> true
또는 메서드 리턴문에 사용할 수 있다.
public int maxNumber(int a, int b) {
return a > b ? a : b;
}
연산자 우선순위
우선 순위 | 연산자 | 결합 방향 | 동작 |
1 | 단항 연산자 | ← | ++, --, +(부호연산자), -(부호연산자), ~, !, (type) |
2 | 산술 연산자 | → | *, /, % |
→ | +, - | ||
→ | <<, >> | ||
3 | 비교 연산자 | → | <, >, <=, >=, instanceof |
→ | ==, != | ||
4 | 논리 연산자 | → | & |
→ | ^ | ||
→ | | | ||
→ | && | ||
→ | || | ||
5 | 삼항 연산자 | → | ? : |
6 | 대입 연산자 | ← | =, +=, -=, *=, /=, %=, <<=, >>=, &=, ^=, |= |
Java 13. switch 연산자
yield 키워드를 이용해서 switch 표현식을 사용할 수 있다.
-> 연산자를 사용하면 간결한 구문처리가 가능하다.
break문으로 처리한 switch 표현식
String result;
switch (input) {
case 1:
result = "a";
break;
case 2:
result = "b";
break;
case 3:
result = "c";
break;
case 4, 5:
result = "f";
break;
default:
result = "z";
}
yield 키워드를 사용한 switch 표현식
result = switch (input) {
case 1:
yield "a";
case 2:
yield "b";
case 3:
yield "c";
case 4, 5:
yield "f";
default:
yield "z";
};
-> (화살표)를 사용하면 더욱 간략하게 처리할 수 있다.
result = switch (input) {
case 1 -> "a";
case 2 -> "b";
case 3 -> "c";
case 4, 5 -> "f";
default -> "z";
};
정리하는데 참고했던 곳
- 자바의 정석 [책] 연산자 우선순위 참고
- blog.baesangwoo.dev/posts/java-livestudy-3week/
- coding-factory.tistory.com/521
'Java' 카테고리의 다른 글
[WS live-study] 6주차: 상속 (0) | 2021.02.04 |
---|---|
[WS live-study] 5주차: 클래스 (0) | 2021.02.03 |
[WS live-study] 4주차: 제어문 (0) | 2021.02.02 |
[WS live-study] 2주차: 자바 데이터 타입, 변수 그리고 배열 (0) | 2021.01.27 |
[WS live-study ] 1주차:JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가 (0) | 2021.01.24 |