Programming/JAVA

연산자란?

잇나우 2020. 12. 22. 18:52
반응형

연산자란?

주어진 식의 결과 값을 산출하는 것을 연산이라고 하는데, 연산을 위해 사용하는 기호를 연산자라고 한다.

산술 연산자 (Arithmetic Operator)

  • 사칙연산과 나머지를 구하는 연산까지 5가지가 있다. (더하기, 빼기, 곱하기, 나누기(몫), 나누기(나머지))
  • boolean타입을 제외한 모든 Primitive type에서 사용이 가능하다.
  • 컴퓨터 시스템적으로 곱하기와 나누기의 연산방식은 비트를 Shift하여 계산한다.
  • 피연산자들 중 부동 소수점이 있다면 부동 소수점으로 산술된다.

더하기
더하기는 + 연산자를 사용하고, 기본적으로는 두 수의 합을 산출할 때 사용하지만 문자열을 연결 시킬때도 사용할 수 있다. 피연산자 중 문자열이 포함되어 있다면 다른 피연산자도 문자열로 취급되어 결과값도 문자열로 변환된다.

int a = 5;
int b = 3;
System.out.println(a + b);  // 8

int a = 10;
String b = "30";
System.out.println(a + b);   // 1030

빼기
빼기는 - 연산자를 사용한다. 앞 피연산자에서 뒤 피연사자를 빼는 연산자이다. + 연산자와는 다르게 문자열은 - 연산할 수 없다.

int a = 5;
int b = 3;
System.out.println(a - b);    // 2
System.out.println(b - a);     // -2

곱하기
곱하기는 * 연산자를 사용하며, 두 수를 곱한다. 문자열 연산은 불가능하다.

int a = 5;
int b = 3;
System.out.println(a * b);  // 15
System.out.println(b * a);    // 15

나누기 (몫)
몫을 구하는 나누기의 경우 / 연산자를 사용한다. 첫번째 피연산자를 두번째 피연산자로 나눈다. 사칙연산과 다른 점은 정수끼리 연산했을때 값이 실수가 되어도 java에서는 정수의 몫만 산출된다는 점이다. 하지만 피연산자중에 부동 소수점이 있다면 몫 또한 부동소수점으로 산출된다.

int a = 5;  
int b = 3;  
// 실제 5 / 3의 값은 1.666666666...
System.out.println(a / b);    // 1  (정수끼리 나누었기 때문에 몫또한 정수)
//============================
double a = 5.0;  
int b = 3;  
//double의 가수부 정밀도가 15 ~ 16자리 이기 떄문에 소수점이하 16자리 까지 출력이 가능하다.
System.out.println(a / b);    // 1.6666666666666667

정수를 0으로 나누면 ArithmeticException이 발생한다.

System.out.println(5 / 0);

실수를 0으로 나눈다면 Infinity혹은 NaN이 결과로 나온다.

System.out.println(3.0 / 0);    // Infinity
System.out.println(3.0 / 0.0);    // Infinity

나누기 (나머지)
나머지를 구하는 나누기에 경우 % 연산자를 사용한다. 첫번째 피연산자를 두번째 피연산자로 나누고 남은 나머지를 리턴한다. 리턴된 결과는 첫번째 피연산자의 부호와 동일하다. 실수에도 사용이 가능하고 결과값도 실수로 리턴된다.

System.out.println(5 % 3);     // 2
System.out.println(-5 % 3);     // -2
System.out.println(5 % -3);     // 2
System.out.println(5 % 3.00000);    // 2.0

나누기와 마찬가지로 정수를 0으로 나머지 연산할 경우 ArithmeticException이 발생하고 실수를 0으로 연산하면 NaN이 발생한다.

System.out.println(5 % 0);        // ArithmeticException 발생
System.out.println(5.13 % 0);    // NaN

연산과정에서 타입 캐스팅과 타입 프로모션이 자주 일어날 수 있다. 타입 프로모션의 경우 상관이 없지만 타입 캐스팅이 일어날 경우 변환 과정에서 값 손실이 일어날 수 있기 때문에 주의해야한다.

단항 연산자

단항 연산자로 증감 연산자가 있는데 ++-- 연산자를 사용한다. 값을 +1 하거나 -1을 하는 연산자이다.

int a = 3;  
int b = 3;  
System.out.println(a++); // 3  
System.out.println(a); // 4  
System.out.println(++b); // 4

++ 연산자가 변수 뒤에 붙을 경우 후위 연산이라고 하며 해당 라인을 지나고 나서 연산이 실행된다. 그래서 a++의 경우 4가 아닌 3으로 출력이 되고 그 다음줄 a의 출력에선 4가 나오는것이다.
반대로 ++ 연산자가 변수 앞에 붙을 경우에는 전위 연산이라고 하며 해당 라인이 실행될때 바로 연산되기 때문에 ++b의 출력문에 경우 4가 출력이 된다. -- 연산자의 경우 ++ 연산에서 값을 더하지 않고 뺀다고 생각하면 똑같다.

단항 마이너스 연산 (Unary minus)

- 연산자를 단항 연산자로 사용하면 값의 부정이 수행된다.

int a = 1;
System.out.println(-a);    // -1
int b = -1;
System.out.println(-b);    // 1

비트 연산자

컴퓨터에서는 값을 저장할때 2진법으로 변환하여 값을 저장한다. 0과 1로 이루어진 한 단위를 bit라고 하고 8 bit는 1 byte라고 한다. 비트 연산자는 데이터를 비트 단위로 연산하기 떄문에 0과 1로 표현이 가능한 정수만 비트 연산이 가능하다. 비트 연산자 및 시프트 연산자는 개별 비트를 조작하는 저수준(low-level) 연산자이다.

NOT 연산자

~ 연산자는 비트 반전 또는 NOT 연산자라고 한다. 2진법으로 나타낸 수의 0은 1로 1은 0으로 변환한다.

int a = ~1;                 
int b = ~-1;
System.out.println(a);    // -2
System.out.println(b);    // 0

AND 연산자

& 연산자는 두 피연산자를 비트곱 연산을 한다. 비트곱 연산은 두 수의 해당 비트가 서로 1일때만 1을 리턴하고 그렇지 않으면 0을 리턴한다.

int a = 3;            // 011
int b = 7;            // 111       
System.out.println(a & b);    // 3     // 011

OR 연산자

| 연산자는 두 피연산자를 비트합 연산합니다. 비트합 연산은 두 수의 해당 비트가 하나라도 1이면 1을 리턴합니다.

int a = 3;            // 011
int b = 7;            // 111       
System.out.println(a | b);    // 7     // 111

XOR 연산자

^ 연산자는 두 수의 해당 비트가 같으면 0을 리턴, 다르면 1을 리턴합니다.

int a = 3;            // 011
int b = 7;            // 111       
System.out.println(a | b);    // 4     // 100

시프트 연산

  • 왼쪽 시프트 연산 (<<)
    << 연산자는 비트를 왼쪽으로 두번째 피연산자로 적혀있는 수만큼 이동 시킨다. 시프트가 될 때 가장 왼쪽 비트는 삭제되고 오른쪽 빈 비트는 0으로 채워진다.

    int a = 5;                // 0b00000101
    int shift1 = a << 1        // 0b00001010    // 10
    int shift2 = a << 2        // 0b00010100    // 20
  • 오른쪽 시프트 연산 (>>)
    >> 연산자는 왼쪽 시프트 연산과는 반대로 우측으로 두번째 피연산자의 수만큼 비트를 이동시킵니다. 가장 오른쪽에 있는 비트는 삭제되고 왼쪽에 빈 비트는 0으로 채워집니다. 그런데 원래 값이 음수인 경우는 빈 비트가 1로 채워집니다. 즉 빈 비트는 MSB로 채워진다.

    int a = 5;                // 0b00000101
    int shift1 = a >> 1        // 0b00000010    // 2
    int shift2 = a >> 2        // 0b00000001    // 1
    int b = -5;                // 0b11111111111111111111111111111011
    int shift3 = a >> 1        // 0b11111111111111111111111111111101    // -3
    int shiff4 = a >> 2        // 0b11111111111111111111111111111110    // -2

    왼쪽 시프트는 곱셈이였지만 오른쪽 시프트는 나눗셈이 된다.

    int a = b >> c;        // a = b / (2 * c);
  • unsigned 오른쪽 시프트 연산 (>>>)
    MSB와 관계없이 오른쪽으로 밀려 생긴 빈 비트가 무조건 0으로 채워진다. 음수의 값에 >>> 연산을 한다면 결과가 양수가 된다.

    int a = 5;                // 0b00000101
    int shift1 = a >> 1        // 0b00000010    // 2
    int shift2 = a >> 2        // 0b00000001    // 1
    int b = -5;                // 0b11111111111111111111111111111011
    int shift3 = a >> 1        // 0b1111111111111111111111111111101    // 2147483645
    int shiff4 = a >> 2        // 0b111111111111111111111111111110        // 1073741822

    int는 4 byte 이기 때문에 총 32개의 비트가 채워져 있어서 음수를 >>>연산했을 경우 큰 값이 나온다. int가 아닌 byte 데이터 타입에 경우 JVM에서 int와 같은4 byte로 놓고 계산하기 때문에 IDE에서 확인했을 경우 int와 byte에 값에 큰 차이가 없다.

관계 연산자

관계 연산자는 연산자를 중심으로 양쪽의 값이 어떤 관계를 가지고 있는지 산출하는 연산자이다.

연산자 설명
== 양쪽 값이 같으면 true, 다르면 false
!= 양쪽 값이 다르면 true, 같으면 false
> 왼쪽 값이 오른쪽 값보다 크면 true, 작으면 false
>= 왼쪽 값이 오른쪽 값보다 크거나 같으면 true, 작으면 false
< 왼쪽 값이 오른쪽 값보다 작으면 true, 크면 false
<= 왼쪽 값이 오른쪽 값보다 작거나 같으면 true, 크면 false
! true의 값은 false로, false는 true로 변환한다.

== 연산자

Primitive Type을 비교할 떄 두 수의 값이 같다면 true를 반환, 그렇지 않다면 false를 반환한다.
String같은 Reference Type에 경우 동일한 객체인지를 판단한다.

int a = 5;
int b = 5;
a == b // true;
String c = "c";
String d = "c";
System.out.println(c == d); // true

두 수의 타입이 다를때는 크기가 작은 피연산자 타입이 큰 피연산자의 타입으로 변환되어 비교한다. (타입 프로모션)

// a가 float타입으로 변환한 뒤에 비교한다.
int a = 5;
float b = 5.0F;
System.out.println(a == b);    // true

!= 연산자

!= 연산자는 == 연산자와 반대로 두 수의 값이 다르면 true를 반환하고 같으면 false를 반환한다. 참조 타입에 경우 동일한 객체인지를 비교한다.

int a = 4;
int b = 5;
System.out.println(a != b);    // true

< 연산자, <= 연산자

왼쪽의 값이 오른쪽의 값보다 작은지, 혹은 작거나 같은지 판단할때 사용한다.

int a = 5;
int b = 6;
System.out.println(a < b);    // true;
System.out.println(a <= b);    // true;
System.out.println(b <= a);    // false;

> 연산자, >= 연산자

<, <= 연산자와는 정반대로 왼쪽의 값이 오른쪽의 값보다 크거나, 크거나 같은지를 판단할때 사용한다.

int a = 5;
int b = 6;
System.out.println(a > b);    // false;
System.out.println(a >= b);    // false;
System.out.println(b >= a);    // true;

논리 연산자

Boolean Operators으로 관계 연산자와 마찬가지로 truefalse를 반환한다.

  • 논리 AND 연산자
    && 연산자를 사용하고, 연산자를 기준으로 양 쪽의 값이 모두 truetrue를 반환하고 한쪽이라도 false라면 false를 반환합니다.

    boolean b1 = true;
    boolean b2 = true;
    System.out.println(b1 && b2);    // true
    System.out.println(b1 && 5 < 4);    // false
  • 논리 OR 연산자
    || 연산자를 사용하고, 연산자를 기준으로 양 쪽의 값이 하나라도 truetrue를 반환한다. 양쪽 모두 false일 경우에만 false를 반환한다.

    boolean b1 = true;
    boolean b2 = false;
    System.out.println(b1 || b2);    // true
    System.out.println(b1 || 5 < 4);    // true

    단축 평가 논리 계산법 (Short Circuit Evaluation)&& 연산자와 || 연산자를 사용할때 앞에 논리 연산에 따라 이미 결과가 정해졌을 경우 뒤에 논리연산은 하지않고 넘어가는것을 말한다.

  • && 연산자의 경우 앞에 결과가 false일 경우 뒤에 연산을 하지 않고 false를 반환한다.

  • || 연산자의 경우 앞에 결과가 true일 경우 뒤에 연산을 하지 않고 true를 반환한다.

    int a = 1;  
    int b = 2;  
    // || 연산자의 경우 a > 0 에서 true를 반환헀기 때문에 뒤에 b++ == 3은 연산하지 않고 넘어가기 때문에
    // b의 값이 그대로 2이다.
    if (a > 0 || b++ == 3) {  
    System.out.println(b);   // 2
    }
    // b++ == 3의 값은 false이지만 뒤에 a > 0이 true이기 때문에 if 문안에 출력문이 실행되고
    // b++ == 3을 비교를 했기 때문에 b의 값이 다음줄에 1증가하여 3으로 출력한다.
    if (b++ == 3 || a > 0) {  
    System.out.println(b);      // 3
    }
    int a = 1;  
    int b = 2;  
    // a < 0이 false를 반환하기 때문에 뒤에 논리 연산은 하지 않고 넘어간다 그래서 b의 값이 그대로 2로 출력
    if (a < 0 && b++ == 3) {  
    System.out.println(b);      // 실행 안됨
    }  
    System.out.println(b);        // 2
  • 부정 연산자
    ! 연산자를 사용하고 단항 연산자로써 해당 값의 결과를 반대로 반환한다.

    boolean t = true;
    System.out.println(!t) // false

    &, |, ^ 연산자비트연산에서 사용했던 연산자들과 같다. 논리 연산에서도 사용할 수 있다. &| 연산자의 경우 각각 &&|| 연산자와 똑같지만 단축 평가 논리 계산법 (Short Circuit Evaluation)이 적용되지 않는다.

    int a = 1;  
    int b = 2;  
    if (a < 0 & b++ == 3) {  
    System.out.println(b);  // 실행안됨
    }  
    System.out.println(b);        // 3
    int a = 1;  
    int b = 2;  
    if (a > 0 | b++ == 3) {  
    System.out.println(b);      // 3
    }

    ^ 연산자의 경우 두 결과값이 서로 다를때 true를 반환한다. 양쪽 다 true의 결과값이라면 false를 반환한다. 이 연산자도 위 연산자들과 같이 단축 평가 논리 계산법 (Short Circuit Evaluation)이 적용되지 않는다.

    boolean c = true;  
    boolean d = false;  
    System.out.println(c ^ d);    // true
    boolean c = false;  
    boolean d = false;  
    System.out.println(c ^ d);    // false
    boolean c = true;  
    boolean d = true;  
    System.out.println(c ^ d);    // false
    boolean c = true;  
    boolean d = false;  
    System.out.println(c ^ d ^ true);    // false

instanceof

객체 또는 배열이 어떤 참조 타입인지 확인하는 연산자이다. instanceof를 설명할때는 다형성으로 설명을 많이한다. PolyMorphism(다형성)은 상위 클래스 타입의 참조 변수로 하위 클래스의 인스턴스를 참조할 수 있음을 뜻한다.

"eatnows" instanceof String // true
null instanceof String false

// 다형성
Object arr = new int[]{1, 2, 3};
arr instanceof int[]  // true 
int[] instanceof arr   // 에러 '

int a = 5;
a instanceof int // primitive type은 사용할 수 없다.

instanceof는 캐스팅 하기전에 상위 클래스로 형변환된 인스턴스의 원래 데이터 타입을 확인할 때 쓰이는 연산자이다.

Object arr = new int[]{1,2,3};
if (arr instanceof int[]) {
    int[] arr2 = (int[]) arr;
}

대입 연산자 (Assignment Operator)

자바에서는 = 연산자를 대입 연산자라고 부른다. 실제 수학에서 처럼 두 수가 같다는 의미로 사용하는 것이 아니라 = 연산자를 기준으로 오른쪽의 있는 값을 왼쪽의 있는 변수에 저장한다는 의미이다.

// a에 변수에 값 5를 저장한다. 할당한다. 대입한다.
int a = 5;

이 대입 연산자는 산술 연산자, 비트 연산자, shift 연산자와 결합하여 사용할 수 있다. 이를 복합 대입 연산자라고 한다.

int a = 5;
// 산술 연산자와 결합
a += 1;        // a = a + 1;
a -= 2;     // a = a - 2;
a *= 3;     // a = a * 3;
a /= 2;     // a = a / 2;
a %= 4;     // a = a % 4;
// 비트 연산자와 결합
a &= 2;        // a = a & 2;
a |= 2;     // a = a | 2;
a ^= 2;     // a = a ^ 2;
// 시프트 연산자와 결합
a <<= 3;    // a = a << 3;
a >>= 3;    // a = a >> 3;
a >>>= 3     // a = a >>> 3;

화살표 연산자 (->)

화살표 연산자는 JAVA 8부터 도입된 연산자로 람다 표현식(Lambda Expression) 에서 사용되는 연산자이다. 자바에서 함수형 프로그래밍이 가능하도록 하기 이해 등장했다. 함수형 프로그래밍 언어에서 주로 사용되던 문법으로 유연성이 좋다. 람다 표현식은 익명 객체로 함수형 인터페이스을 통해 구현된다.

// (메소드의 파라미터) -> {메소드의 내용이 들어간다.}
(a, b) -> {
    System.out.println(a)
    System.out.println(b)
}
// 메소드의 내용이 한줄이면 {} 코드블록을 생략할 수 있다.

3항 연산자

if의 기능을 연산자로 대체하여 표현할 수 있다. 조건에 따라 truefalse에 해당하는 값을 반환할 수 있다.

// 조건 ? 참 : 거짓
System.out.println(1 > 0 ? "true" : "false");     // true

연산자 우선순위

출처:https://3.bp.blogspot.com/-7FuhIInDVBU/W3JBhTXxlyI/AAAAAAAAAAU/r7gR0wvUlmslOMiGI3W0BM7f7RA0LnCsQCLcBGAs/s1600/%25EC%259E%2590%25EB%25B0%2594%2B%25EC%2597%25B0%25EC%2582%25B0%25EC%259E%2590%2B%25EC%259A%25B0%25EC%2584%25A0%25EC%2588%259C%25EC%259C%2584.png
출처: https://unknownyun.blogspot.com/2018/08/blog-post_86.html

Switch 연산자

자바 12이상에 추가된 연산자이며 yield 키워드에 경우 자바 13이상에서 추가되었다고 한다. 기존의 switch문 과는 다르게 새로 추가된 연산자라고 한다. 같은 행위를 하는 케이스들을 묶을 수도 있고, 화살표 연산자를 통해 break도 생략할 수 있다. yield 키워드를 이용하여 리턴할 수 있습니다. case 별로 한 문장으로 리턴이 가능하면 yield 키워드를 생략할 수 있다.

int result = switch(test) {
    case 1 -> 1;
    case 2 -> 2;
    case 4, 5 -> {
        System.out.println("케이스4, 5");
        yield 4;
    }
    default -> 0;
}

참고
https://blog.baesangwoo.dev/posts/java-livestudy-3week/
https://velog.io/@uhan2/Java-Operator

반응형

'Programming > JAVA' 카테고리의 다른 글

JUnit이란?  (0) 2020.12.31
제어문이란?  (0) 2020.12.29
데이터 타입, 변수, 배열 그리고 타입추론  (0) 2020.12.21
JVM이란?  (0) 2020.12.21
[JAVA] Arrays.asList()  (0) 2020.09.17