본문 바로가기

Java

[WS live-study] 3주차: 연산자

산술 연산자

수학적 연산에 사용되는 연산자다. 기본적으로 알고 있는 덧셈, 뺄셈, 나눗셈, 곱셈에서 사용되는 연산자이고, 여기서 몇가지의 연산자가 더 추가된다.

 

산술연산자는 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";
};

 


정리하는데 참고했던 곳