른록노트
[Java] 연산자 본문
목표
자바가 제공하는 다양한 연산자를 학습하세요.
학습할 것
- 산술 연산자
- 비트 연산자
- 관계 연산자
- 논리 연산자
- instanceof
- assignment(=) operator
- 화살표(->) 연산자
- 3항 연산자
- 연산자 우선 순위
- (optional) Java 13. switch 연산자
산술연산자
산술연산자는 기본자료형(primitive data type) boolean을 제외한 나머지 타입에서는 사용할 수 있지만 참조 자료형(reference data type)은 사용할 수 없습니다. 단 String 클래스만 + 연산이 가능합니다.
-
+ : 더하기 연산자.additive operator
-
- : 빼기 연산자. subtraction operator
-
* : 곱하기 연산자. multiplication operator
-
/ : 나누기 연산자. division operator
-
% : 나머지 연산자. remainder operator
이러한 연산자들은 많이 실행해 봤을거라 생각하고 예제코드는 담지 않겠습니다. 하지만 이걸 적으면서 갑자기 든 의문은
타입이 다른 변수를 System.out.println()안에서 계산하고 출력시켰을때 매개변수의 타입은 타입 프로모션이 일어날까요? 아니면 타입 캐스팅이 일어날까요?
public class HelloWorld {
public static void main(String[] args){
int a = 2_100_000_000; // 자바 7 이후부터 _표현 가능 (쉼표랑 같다고 생각하시면 됩니다.)
short b = 2;
long c = 3;
System.out.println(b*a*c); //public void println(long x) { <= long 매개변수를 받는 함수가 실행됩니다.
// long으로 자동으로 타입 프로모션이 일어납니다.
System.out.println(b*a); //public void println(int x) { <= int 매개변수를 받는 함수가 실행됩니다.
// int로 자동으로 타입 프로모션이 일어납니다.
System.out.println(b);
test(b);
// 자동으로 int로 타입 프로모션이 일어나네요.
}
public static void test(int a){
System.out.println("안녕하세요");
}
}
비트연산자
비트 연산자는 비트 단위로 데이터를 처리할 때 사용하는 연산자입니다.
크게 두 개의 숫자를 비교하는 bitwise 연산자와 비트를 이동하는 bit shift 연산자가 있습니다.
분류 | 비트연산자 | 설명 |
bitwise | & | AND 연산 => 비교하는 비트 두개가 모두 1이면 1을 반환) |
| | OR 연산 (inclusive OR 연산) => 비교하는 비트 두개가 하나라도 1이면 1을 반환 | |
^ | XOR 연산 (exclusive OR 연산) => 비교하는 비트 두개가 서로 다르면 1을 반환 | |
~ | unary 연산 (Not 연산) => 비교하는 비트의 반대를 반환 | |
bit shift | << | 왼쪽 이동 => 비트를 왼쪽으로 밀기 ( 빈칸 0으로 채우기) * 부호비트를 신경쓰지 않으니 당연히 <<<는 없음 |
>> | 오른쪽 이동 => 비트를 오른쪽으로 밀기 ( 맨 앞에 비트로 빈칸 채우기 ) | |
>>> | 부호 상관 없는 (unsigned)오른쪽 이동 => ( 맨 앞에 비트 상관없이 0으로 채우기 ) |
아래 예제를 참고하시면 이해하는데 도움이 될 것 입니다.
public class HelloWorld {
public static void main(String[] args){
printBit(-1);
printBit(~-1);
printBit(0);
printBit(1);
printBit(-1>>1);
printBit(-1);
printBit(-1<<2);
printBit(-1>>200);
printBit(-1>>>2);
printBit(0>>200);
/*
위부터 결과 입니다.
11111111111111111111111111111111 -1
00000000000000000000000000000000 ~-1
00000000000000000000000000000000 0
00000000000000000000000000000001 1
00000000000000000000000000000000 -1>>1
11111111111111111111111111111111 -1
11111111111111111111111111111100 -1<<2
11111111111111111111111111111111 -1>>200
00111111111111111111111111111111 -1>>>2
00000000000000000000000000000000 0>>200
*/
}
public static void printBit(int number){
int zeroCnt = Integer.numberOfLeadingZeros(number);
for (int i = 0; i < zeroCnt; i++) {
System.out.printf("0");
}
if(number != 0) {
System.out.println(Integer.toBinaryString(number));
}else{
System.out.println();
}
}
}
* 참고로 비트 연산자로 중간값 구하는 방법입니다.
public class findMid{
public static void main(String[] args){
int start = 2_000_000_000;
int end = 2_100_000_000;
int mid = start + (end - start) / 2 //오버플로우를 면할 수 있습니다.
// int mid = (start + end ) >>> 1 비트를 오른쪽으로 밀면 2로 나눌 수 있습니다.
}
}
관계연산자(비교연산자)
분류 | 관계연산자 | 설명 |
Equality Operator (모든 타입 가능) |
== | 같음 (참조자료형은 그 주소 값이 같은지 확인합니다.) |
!= | 같지 않음 (참조자료형은 그 주소 값이 같은지 확인합니다.) | |
Relational Operator (boolean을 제외한 모든 기본 자료형 가능) |
> | (왼쪽 값이) 큼 |
>= | (왼쪽 값이) 같거나 큼 | |
< | (왼쪽 값이) 작음 | |
<= | (왼쪽 값이) 같거나 작음 |
모든 비교 연산자의 결과는 반드시 boolean 입니다. 해당 조건이 맞으면 true 그렇지 않으면 false가 됩니다.
논리연산자(Conditional Operator)
분류 | 논리연산자 | 설명 |
Conditional AND | && | AND 결합, 두 개의 조건이 모두 true일 때만 true로 처리한다. |
Conditional OR | || | OR 결합, 두 개의 조건 중 하나라도 true일 때 true로 처리한다. |
if문에서 |와 ||의 차이입니다.
||는 앞에 하나만 맞아도 멈추는데 |는 두개다 비교합니다.
public class ConditionalTest{
public static void main(String[] args){
int i = 0;
int j = 0;
if(i++ == 0 || j++ == 0){}
System.out.println(i); // 1
System.out.println(j); // 0
}
}
public class ConditionalTest{
public static void main(String[] args){
int i = 0;
int j = 0;
if(i++ == 0 | j++ == 0){}
System.out.println(i); // 1
System.out.println(j); // 1
}
}
instanceof
객체의 타입을 구분하는데 사용하는 예약어입니다.
A(객체) instanceof B(타입)
public class InstanceofTest {
public static void main(String[] args) {
String string = "test";
Parent parent = new Parent();
Child child = new Child();
System.out.println(string instanceof Object); // 모든 자바 클래스는 java.lang.Object 클래스를 상속 받았습니다. true
System.out.println(parent instanceof Child); // parent는 Child 클래스의 상속을 받지않았으므로 false
System.out.println(child instanceof Parent); // child 는 Parent 클래스를 상속 받았으므로 true
//instanceof 결과가 true일 경우 오른쪽 타입(상위타입)의 변수에 하위 타입형으로 객체를 생성할 수 있습니다. (상속성/다형성)
Parent boy = new Child(); //아들도 나중에 아빠가 될 수 있습니다.
}
public static class Parent{
}
public static class Child extends Parent{
}
}
assignment(=) operator
대입연산자는 Assignment Operator 라고 합니다.
ex) int i = 1; //여기서 '=' 이 문자가 대입연산자입니다.
그리고 복합 대입 연산자가 있습니다. (Compound Assignment Operator)
자신의 값에 특정 값을 연산할 경우 다음과 같이 간단하게 처리할 수 있습니다.
- += : 기존 값에 우측 항의 값을 더한 값을 대입
- -= : 기존 값에 우측 항의 값을 뺀 값을 대입
- *= : 기존 값에 우측 항의 값을 곱한 값을 대입
- /= : 기존 값을 우측 항의 값으로 나눈 값을 대입
- %= : 기존 값을 우측 항의 값으로 나눈 나머지를 대입
추가로 단항 연산자가 있습니다.
- + : 단항 플러스 연산자. Unary plus operator (ex => int a = +1;)
- - : 단항 마이너스 연산자. Unary minus operator (ex => int a = -1;)
- ++ : 증가 연산자 (전치 : 해당 변수를 참조하기 전에 연산, 후치 : 해당 변수를 참조 한 후 연산) ++a, a++
- -- : 감소 연산자 (전치 : 해당 변수를 참조하기 전에 연산, 후치 : 해당 변수를 참조 한 후 연산) --a, a--
- ! : 논리 부정 연산자 (ex => !true)
화살표(->) 연산자 (Arrow Token)
자바 8부터 제공하는 람다 표현식에서 사용하는 화살표 토큰입니다.
람다 표현식과 기존 표현식의 차이를 비교하며 이해하면 좋습니다.
public class ArrowTokenTest {
interface Calculate {
int operation(int a, int b); //인터페이스에 메소드가 하나여야합니다. 함수형 인터페이스 (Functional Interface)
}
private void calculateClassic(){
Calculate calculateAdd = new Calculate() { //여기에 괄호로 바로 정의해주는 클래스를 익명 클래스라고 합니다
@Override
public int operation(int a, int b) {
return a+b;
}
};
System.out.println(calculateAdd.operation(1,2));
}
// calculateAdd라는 익명 클래스 객체를 람다 표현식으로 처리한다면 아래와같습니다. 람다식으로 처리하려면 함수형 인터페이스만 가능합니다.
private void calculateLambda(){
Calculate calculateAdd = (a,b) -> a+b;
System.out.println(calculateAdd.operation(1,2));
}
}
3항 연산자 (Conditional operator ? :)
변수 = (boolean조건식) ? true일때값 : false일때값;
연산자 우선 순위
우선순위 | 연산자 |
1 | (), [] |
2 | !, ~, ++, -- |
3 | *, /, % |
4 | +, - |
5 | <<, >>, >>> |
6 | <, <=, >, >= |
7 | ==, != |
8 | & |
9 | ^ |
10 | | |
11 | && |
12 | || |
13 | ? : |
14 | =, +=, -=, *=, /=, <<=, >>=, &=, ^=, ~= |
Java 13. switch 연산자
Java12부터 switch 연산자가 추가 되었습니다.
기존에 switch문이 변경된것이 아니라 switch 연산자가 추가 된것입니다.
[switch statement]
다수의 case,break가 존재하게 된다.
break; 를 빼먹을 경우 다음 분기로 넘어가게 됨.
return값이 존재할수없다.
[switch operator]
break를 사용하지 않아도 된다.
yield 존재함
return값 존재해도됨
case -> A 같은 형식으로 표현가능
switch의 반환값이 따로 필요하지 않거나 case가 switch 들어오는 모든 인자를 커버하는 경우
default 항목을 넣어주지 않아도 되나 그렇지 않은 경우는 default -> code를 작성해야 한다.
[Java12]
1. ->(화살표) 표현이 가능하고 data만 존재할 경우 return이 가능하다.
2. -> 구문을 사용할 경우 break;를 적지 않아도 다음 case 구문으로 넘어가지 않는다.
3. -> 표현 오른쪽은 꼭 단일 수행일 필요는 없다. 블록 {} 안에서의 작업도 가능하다.
[Java13]
1. yield 예약어가 추가됨. yield x 하게 되면 x가 리턴됨.
2. yield는 예약어이지만 변수명으로 사용가능하다. int yield = 3;
(출처 : castleone.tistory.com/6)
자바 12, 자바 13 switch 연산자를 정리한 예시입니다.
public class SwitchTest {
public static void main(String[] args) {
/*
* 가장 기본적인 형태의 switch 문
*/
System.out.println(switchBasic("a")); // 1
System.out.println(switchBasic("e")); // 3
/*
* java 12 부터 쉼표(, 콤마)를 사용하여 여러 case 를 한 줄에 나열
*/
//System.out.println(switchWithMultiCase("d")); // 3
//System.out.println(switchWithMultiCase("f")); // 3
/*
* java 12 부터 화살표 (arrow ->) 를 사용하여 결과 반환
* 더 이상 break 키워드를 사용하지 않아도 원하는 결과를 받아볼 수 있음
* 실행 결과를 바로 변수에 할당
*/
//System.out.println(switchWithArrow("c")); // 2
//System.out.println(switchWithArrow("e")); // 3
/*
* java 13 부터 yield 키워드를 사용하여 switch 결과 반환
*/
//System.out.println(switchWithJava13Yield("a")); // 1
//System.out.println(switchWithJava13Yield("e")); // 3
}
private static int switchBasic(String str) {
int result;
switch (str) {
case "a":
case "b":
result = 1;
break;
case "c":
result = 2;
break;
case "d":
case "e":
case "f":
result = 3;
break;
default:
result = -1;
}
;
return result;
}
/*
private static int switchWithMultiCase(String str) {
int result;
switch (str) {
case "a", "b":
result = 1;
break;
case "c":
result = 2;
break;
case "d", "e", "f":
result = 3;
break;
default:
result = -1;
};
return result;
}
private static int switchWithArrow(String str) {
int result = switch (str) {
case "a", "b" -> 1;
case "c" -> 2;
case "d", "e", "f" -> 3;
default -> -1;
};
return result;
}
private static int switchWithJava13Yield(String str) {
int result = switch (str) {
case "a", "b":
yield 1;
case "c":
yield 2;
case "d", "e", "f" : {
System.out.println("{} 블록을 사용하여 추가 로직을 수행할 수 있다.");
yield 3;
}
default:
yield -1;
};
return result;
}
*/
}
(출처 : blog.naver.com/hsm622/222150928707)
참고문헌
- 이상민(2017). 자바의 신 2. 서울: 로드북