른록노트

[Java] 연산자 본문

Programming/[Java]

[Java] 연산자

른록 2021. 1. 28. 04:46

목표

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

학습할 것

  • 산술 연산자
  • 비트 연산자
  • 관계 연산자
  • 논리 연산자
  • 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. 서울: 로드북
반응형
Comments