본문 바로가기

Programming/Java

[기본-3]자바 연산자

목표

자바가 제공하는 다양한 연산자를 학습하세요.

* 이미 알고 있는 내용에 대해서는 간략하게 정리하였다.

목차

  • 산술 연산자
  • 비트 연산자
  • 관계 연산자
  • 논리 연산자
  • instanceof
  • assignment(=) operator
  • 화살표(->) 연산자
  • 3항 연산자
  • 연산자 우선 순위
  • (optional) Java 13. switch 연산자

 

산술 연산자

구분 예시 기능
이항연산자 a + b a와 b를 더함
a - b a에서 b를 뺌
a * b a와 b를 곱함
a / b a를 b로 나눈 몫을 구함
a % b modulo 연산자이며 a를 b로 나눈 나머지를 구함
단항연산자 +a 부호를 바꾸지 않는다.
-a 부호를 반대로 바꿈
b = ++a a의 값을 우선 하나 증가시킨 후 b에 저장
b = --a a의 값을 우선 하나 감소시킨 후 b에 저장
b = a++ a의 값을 b에 저장 후 a를 하나 증가시킴
b = a-- a의 값을 b에 저장 후 a를 하나 감소시킴

 

비트 연산자

비트 연산자는 크게 비트 논리 연산자와 비트 이동 연산자로 구분할 수 있다.

 

비트 논리 연산자

연산자 예시 기능 비고
a & b 논리곱 같은 자리의 비트가 모두 참이면 참. 10 & 6 = 1010 & 0110 = 0010 = 2
a | b 논리합 같은 자리의 비트가 하나 이상 참이면 참. 10 | 6 = 1010 | 0110 = 1110 = 14
a ^ b XOR 같은 자리의 비트가 다를 경우(0과 1) 참. 10 ^ 6 = 1010 ^ 0110 = 1100 = 12
~a NOT ~10 = ~1010 = 0101 = 5

 

비트 이동 연산자

연산자 예시 기능
a << b a의 비트를 b만큼 왼쪽으로 이동, 오른쪽을 0으로 채운다.
a >> b a의 비트를 b만큼 오른쪽으로 이동, 왼쪽을 부호비트로 채운다.
a >>> b a의 비트를 b만큼 오른쪽으로 이동하나 왼쪽을 0으로 채운다.

 

 

관계 연산자

관계 연산자는 비교 연산자라고도 하며, 두 개의 피연산자(자바에서는 객체 또는 기본타입의 값이 해당)를 비교하기 위한 연산자이다.

크거나 작은 대소비교의 경우는 숫자 자료형을 가지는 피연산자들만 비교가능하다. 

 

 

동일성은 두 개의 피연산자가 값이 같은 지 판별한다. == 연산자로 동일할 경우 동일성이 성립된다.

 

int a = 3;
int b = 3;
int c = 5;

System.out.println(a == b); // true 동일성이 성립된다.
System.out.println(a == c); // false 동일성이 성립되지 않는다.

 

 

동등성은 참조하는 객체가 다르나 그 의미가 같으면 동등성이 성립된다.

// byte배열을 변환하는 등의 이유로 생성하는 것이 아니라,
// 단순히 문자열 객체를 생성할 때는 실제로 문자열 객체를 이렇게 생성해서는 안된다. 
// String gildong = "홍길동"; // 다음과 같이 문자열을 생성해야 동일한 객체가 만들어지지 않는다.
String gildong = new String("홍길동"); 
String hong = new String("홍길동");

System.out.println(gildong == hong); // false 다른 객체이므로 동일성이 성립되지 않는다.
System.out.println(gildong == hong); // true 동등성이 성립된다.

 

 

논리 연산자

연산자 예시 기능
a && b a와 b가 동시에 true일 경우에 true이고 그렇지 않으면 false이다.
a가 false이면 b를 확인하지 않는다.
a || b a, b 중에 true가 존재하면 true이고 전부 false이면 false이다.
a가 true이면 b를 확인하지 않는다.
a & b 비트 논리 연산자에 해당하며, a와 b의 비트가 동일할 경우 true이다.
a | b 비트 논리 연산자에 해당하며, a와 b의 비트가 모두 false 일 때만 false이다. 
a ^ b a와 b가 서로 다를 경우 true이고, 동일하면 false이다.
!a a가 true일 경우 false이고, a가 false일 경우 true이다.
a = b ? c : d b가 true이면 a에 c를 대입하고, b가 false이면 a에 d를 대입한다.

 

 

instanceof

instanceof는 객체가 어떤 클래스로 부터 생성되었는지 판별할 때 사용할 수 있다.

 

String str = "Hello";
Object obj = (Object)str;

System.out.println(obj instanceof String); // true

// 상속관계 확인(클래스)
System.out.println(obj instanceof Object); // true 모든 클래스의 super 클래스는 Object

// 구현관계 확인(인터페이스)
System.out.println(obj instanceof Comparable); // true String은 Comparable 인터페이스를 구현했다.

// 전혀 관계 없는 클래스 확인
System.out.println(obj instanceof Integer); // false

객체의 클래스를 instanceof 키워드로 확인할 클래스가 많아지면 많아질수록 조건문이 불필요하게 많아질 수 있다. 이런 단점을 극복하기 위해 Java 14 preview 버전부터 아래에서 설명할 Switch Expression과 함께 사용하면 간결하게 처리할 수 있다.

instanceof의 패턴매칭을 적용한 Switch Expression 예제는 다음 사이트에서 확인 가능하다.

cr.openjdk.java.net/~briangoetz/amber/pattern-match.html

assignment(=) operator

연산자 종류 예제 기능
= c = a a를 c에 대입한다.
+= a += b a와 b를 더한 후 a에 대입한다. (a = a + b)
-= a -= b a와 b를 뺀 후 a에 대입한다. (a = a - b)
*= a *= b a와 b를 곱한 후 a에 대입한다. (a = a * b)
/= a /= b a와 b를 나눈 후 몫을 a에 대입한다. (a = a / b)
%= a %= b  a와 b를 나눈 후 나머지를 a에 대입한다. (a = a % b)
&= a &= b a와 b를 AND 비트 연산 후 a에 대입한다. (a = a & b)
^= a ^= b a와 b를 XOR 비트 연산 후 a에 대입한다. (a = a ^ b)
|= a |= b a와 b를 OR 비트 연산 후 a에 대입한다. (a = a | b)
<<== a <<== b a와 b만큼 좌측으로 쉬프트 연산을 실행한 후 a에 대입한다. 빈 비트는 0으로 채운다. (a = a << b)
>>= a >>= b a와 b만큼 우측으로 쉬프트 연산을 실행한 후 a에 대입한다. 빈 비트는 부호비트로 채운다. (a = a >> b)
>>>= a >>>= b a와 b만큼 좌측으로 쉬프트 연산을 실행한 후 a에 대입한다.빈 비트는 0으로 채운다. (a = a >>> b)

 

 

화살표(->) 연산자

자바 8 부터 람다식이 추가되었는데 함께 등장한 연산자이다. 람다식을 사용할 때 사용한다.

추상 메서드가 단 하나인 인터페이스를 구현할 때 람다식을 사용할 수 있는데, @Functional 인터페이스가 적용된 인터페이스를 구현할 때 람다식을 사용할 수 있다. 자바 8 이전에는 익명 클래스를 생성하는 방법이나 별도의 클래스를 생성하는 방법으로 구현하였는데 람다식을 사용함으로써 소스가 훨씬 간결해지는 장점이 있다.

 

 

간단한 예제로 Bear라는 인터페이스를 작성한다.

 

@FunctionalInterface
public interface Bear {

    String getName();

    //default method와 static method는 @FunctionalInterface의 조건에 영항을 받지 않는다.
    default String intro() {
        return "곰은 사람을 찢어요..";
    }

    static String print() {
        return "곰";
    }
}

 

 

Bear를 구현하는 Panda 클래스를 작성한다.

public class Panda implements Bear {

    private Bear bear;

    public Panda(Bear bear) {
        this.bear = bear;
    }

    @Override
    public void move() {
        if(bear != null) {
            bear.move(); // 주의 move();를 호출하면 Recursive Call이 되어 무한루프에 빠져 StackOverFlow 발생하므로 주의
        }
    }
}

 

직접 구현한 함수형 인터페이스를 통하여 람다식을 작성하는 예제이다.

자바 API 중에는 대표적으로 Runnable 인터페이스와 Thread 클래스가 있다.

public class MySource {

    public static void main(String[] args) {
        // 자바 8 이전 방식
        Bear panda1 = new Panda(new Bear() {
            @Override
            public void move() {
                System.out.println("뒤뚱뒤뚱1");
            }
        });
        panda1.move();

        // 자바 8 람다식 적용
        Bear panda2 = new Panda(() -> System.out.println("뒤뚱뒤뚱2"));
        panda2.move();
    }
}

 

3항 연산자

3항 연산자의 기본 문법은 다음과 같다.

int num = 10;
String str = (num == 10) ? "OK" : "NO"; // 조건절 ? true일 경우 반환 : false일 경우 반환

char c = "OK".equals(str) ? 'Y' : 'N'; // 참과 거짓에 해당하는 값은 반환하여 대입할 변수와 동일해야 한다.

 

 

3항 연산자가 연속적으로 올 수도 있다. 

boolean isKakaoPay = false;
boolean isPayco = false;
boolean isToss = false;
boolean isNaverPay = false;

// 극단적인 예제이다. 조건이 복잡해지면 조건문이나 enum등을 활용해보는 방법을 생각하자
char c = isKakaoPay ? 'K' : isPayco ? 'P' : isToss ? 'T' : isNaverPay ? 'N' : '-'; 

 

연산자 우선 순위

연산자 종류 연산순서 적용 방향
증감연산자 등 [], (연산식), 변수++, 변수-- 왼쪽
증감연산자 등 +변수, -변수, ++변수, --변수, ~, ! 오른쪽
인스턴스 생성, 캐스팅 new, (자료형) 왼쪽
산술연산자 *, /, % 왼쪽
산술연산자 +, - 왼쪽
비트연산자 <<, >>, >>> 왼쪽
비교연산자 등 <, >, <=, >=, instanceof 왼쪽
비교연산자 ==, != 왼쪽
비트연산자(AND) & 왼쪽
비트연산자(XOR) ^ 왼쪽
비트연산자(OR) | 왼쪽
논리연산자(AND) && 왼쪽
논리연산자(OR) || 왼쪽
삼항연산자 ? : 왼쪽
대입연산자 =, +=, -=, *=, /= %=, &=, ^=, |=, <<==, >>=, >>>= 오른쪽

 

Java 13. switch 연산자

Java 13 버전부터 switch연산자가 추가되었다. (JEP-354)

기존에 자바에서 제공하고 있는 switch문과는 별개의 기능이다.

 

자바에서 기본적으로 제공하는 switch문은 C, C++ 문법을 따른다. 단점으로는 break 문이 난잡하며 실수로 break 문이 필요한 구문에서 호출하지 않을 경우 빠져나가지 못하고 조건문을 체크하다가 default 조건에서 다시 조건이 성립하여 잘못된 처리를 하게될 경우 디버깅이 어려울 수도 있다.

 

switch (day) {
    case MONDAY:
    case FRIDAY:
    case SUNDAY:
        System.out.println(6);
        break;
    case TUESDAY:
        System.out.println(7);
        break;
    case THURSDAY:
    case SATURDAY:
        System.out.println(8);
        break;
    case WEDNESDAY:
        System.out.println(9);
        break;
}

 

이러한 단점을 극복하고자 Java 13에서는 Switch Expression을 추가하였다. 사실 JEP-305를 지원하기 위한 사전 작업이기도 하다.

AMAZON JDK 15 버전을 사용하였다. (JEP-305는 instanceof의 패턴매칭 기능과 관련된 내용이다. 이전까지 객체의 클래스를 판별할 때 비교하고자 하는 클래스를 추가할 때 마다 instanceof  조건문이 추가하여 무분별한 if문으로 가독성이 졌었다. JEP-305에 대해서는 다루지 않겠다.)

 

import static java.util.Calendar.*;

public class MySource {

    public static void main(String[] args) {
        int day = MONDAY;

        int numLetters = switch (day) {
            case MONDAY, FRIDAY, SUNDAY -> 6;
            case TUESDAY                -> 7;
            case THURSDAY, SATURDAY     -> 8;
            case WEDNESDAY              -> 9;
            default -> throw new IllegalStateException("Unexpected value: " + day); // Java12 preview 버전과는 다르게 default 조건이 없을 경우 IDE에서 구문 오류가 발생한다.
        };

        System.out.println("numLetters : " + numLetters);
    }
}

 

 

 

참고 자료

 - 이론 부분(연산자 우선순위): Java 프로그래밍(김희천 저)

 - Switch Expression : openjdk.java.net/jeps/354

 

JEP 354: Switch Expressions (Second Preview)

JEP 354: Switch Expressions (Second Preview) AuthorGavin BiermanOwnerJan LahodaTypeFeatureScopeSEStatusClosed / DeliveredRelease13Componentspecification / languageDiscussionamber dash dev at openjdk dot java dot netEffortSDurationMRelates toJEP 325

openjdk.java.net

 - Pattern Matching for instanceof : openjdk.java.net/jeps/305

 

JEP 305: Pattern Matching for instanceof (Preview)

JEP 305: Pattern Matching for instanceof (Preview) Summary Enhance the Java programming language with pattern matching for the instanceof operator. Pattern matching allows common logic in a program, namely the conditional extraction of components from obje

openjdk.java.net

- 패턴매칭과 Switch Operator를 혼합한 예제 : cr.openjdk.java.net/~briangoetz/amber/pattern-match.html

 

https://cr.openjdk.java.net/~briangoetz/amber/pattern-match.html

Pattern Matching for Java Gavin Bierman and Brian Goetz, September 2018 This document explores a possible direction for supporting pattern matching in the Java Language. This is an exploratory document only and does not constitute a plan for any specific f

cr.openjdk.java.net