슬기로운 개발생활

온라인 자바 스터디 #3 - 연산자

by coco3o
반응형

목표

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

학습할 것

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

산술 연산자

산술 연산자는 사칙 연산자(+, -, *, /), 나머지 연산자(%)로 이루어져 있다. 

산술 연산자는 모두 두개의 피연산자를 취하는 이항 연산자이다.

  • 이항 연산자는 피연산자의 크기가 4 byte보다 작으면 4byte(int형)로 변환한 다음에 연산을 수행한다.
  • 이항 연산자는 연산을 수행하기 전에 피연산자들의 타입을 일치시킨다.

사칙 연산자 - + , -, *, /

사칙연산자의 우선순위는 곱셈(*), 나눗셈(/), 나머지(%) 연산자가 덧셈(+), 뺄셈(-)연산자보다 우선순위가 높다.

1. int형 (4byte)보다 크기가 작은 자료형은 int형으로 형변환 후에 연산을 수행한다.
byte + short  ㅡ> int + int ㅡ>  int

2. 두 개의 피연산자 중 자료형의 표현범위가 큰 쪽에 맞춰서 형변환 된 후 연산을 수행한다.
int + float  ㅡ> float + float  ㅡ>  float

3. 정수형 간의 나눗셈에서 0으로 나누는 것은 금지되어 있다.

나머지 연산자-  %

왼쪽의 피연산자를 오른쪽 피연산자로 나누고 난 나머지 값을 돌려주는 연산자이다.

boolean을 제외하고 모든 기본형 변수에 사용할 수 있다.

public class Example {
	
    public static void main(String[] args) {
    
    	int x = 10;
        int y = 5;
        
        System.out.println(x + y);		// 15
        System.out.println(x - y);		// 5
        System.out.println(x * y);		// 50
        System.out.println(x / y);		// 2
        System.out.println(x % y);		// 5
    }
}

비트 연산자

비트 연산자는 데이터를 비트 단위로 연산한다. 그러므로 0과 1로 표현이 가능한 정수 타입만 비트 연산이 가능하다.
비트 연산자는 기능에 따라 비트 이동연산자, 비트 논리연산자로 구분한다.

 

비트 이동 연산자(shift 연산자) (<<, >>, >>>)
연산식 설명
x << y 정수 x의 각 비트를 y만큼 왼쪽으로 이동시킨다. (빈자리는 0으로 채워진다.)
x >> y 정수 x의 각 비트를 y만큼 오른쪽으로 이동시킨다. (빈자리는 정수 a의 최상위 부호비트와 같은 값으로 채워진다.)
x >>> y 정수 x의 각 비트를 y만큼 오른쪽으로 이동시킨다. (빈자리는 0으로 채워진다.)

 

비트 논리 연산자 (&, |, ^, ~)
연산자 논리 설명
& AND 두 비트 모두 1일 경우에만 결과가 1
| OR 두 비트 중 하나라도 1일 경우에 결과가 1
^ XOR 값이 서로 다를때만 결과가 1 
~ NOT 비트 반전(보수)
비트 연산자의 2진 연산 결과
x y x & y x | y x ^ y x ~ y
1 1 1 1 0 0
1 0 0 1 1 1
0 1 0 1 1 1
0 0 0 0 0 1

관계 연산자

비교 연산자라고도 하며 관계연산자의 결과는 true 혹은 false의 값인 boolean 자료형으로 반환이 된다.

연산자 기능 연산 예
> 왼쪽 항이 크면 true 아니면 false를 반환 num > 10;
< 왼쪽 항이 작으면 true 아니면 faslse를 반환 num < 10;
>= 왼쪽 항이 오른쪽 항보다 크거나 같으면 true 아니면 false를 반환 num >= 10;
<= 왼쪽 항이 오른쪽보다 작거나 같으면 true 아니면 false를 반환 num <= 10;
== 두 개의 항이 같으면 true 아니면 false를 반환 num == 10;
!= 두 개의 항이 다르면 true 아니면 false를 반환 num != 10;

논리 연산자

논리 연산자는 AND(&&), OR(||), NOT(!) 세가지 연산자가 있으며, 관계연산자와 같이 사용되는 경우가 많다.

논리 연산자 역시 연산의 결과가 true 혹은 false로 반환된다.

연산자 기능 연산 예
&&
(논리 곱)
두 항이 모두 true인 경우에만 결과 값이 true 아니면 false를 반환 num =
(10 > 5) && (10 < 4);
||
(논리 합)
두 항 중 하나라도 true면 결과 값은 true 아니면 false를 반환 num =
(10 > 3) || (10 < 4);
!
(부정)
단항 연산자이다. true인 경우엔 false로 바꾸고, false인 경우엔 true로 바꾼다. num =  !(10 > 5);

instanceof

참조변수가 참조하고 있는 인스턴스의 실제 타입을 알아보기 위해 instanceof 연산자를 사용한다.

이 연산자는 부모 변수가 참조하는 객체가 부모객체인지, 자식 객체인지 확인할 수 있다.

주로 조건문에 사용되며, 참조 변수가 instanceof로 형 변환 가능한 타입인지 연산한다.

형 변환이 가능하다면 true를 반환하고, 가능하지 못한다면 false를 반환한다.

instanceof 연산자

참조변수 a가 Object 클래스로 형변환 할 수 있는지  조건문으로 알아봤다.

결과

조건문이 true라면 실행하기 때문에 형 변환이 가능하다는 것을 알았다.

그렇다면 부모 클래스는 어디까지 형 변환을 할 수 있을까?

부모 클래스 참조 변수 instanceof 연산
결과

부모클래스 instanceof 연산시 자식 클래스를 제외하고 true가 나오는 것을 볼 수 있다.

왜 false가 나온 것일까?

부모가 자식이 되려했기 때문에 결과가 false가 나온 것이다.

또, 그렇다면 자식 클래스는 어디까지 형 변환을 할 수 있을까?

자식 클래스 참조 변수 instanceof 연산
결과

자식 클래스에 포함된 범위는 object, 부모, 자신까지 모두 포함되는 것을 볼 수 있다.

부모 클래스에서는 자식 클래스를 instanceof할 수 없지만,

자식 클래스에서는 부모 클래스를 instanceof할 수 있는 것을 알 수 있다.


대입 연산자(assignment operator)

대입 연산자는 변수에 값을 대입할 때 사용하는 이항 연산자이며, 피연산자들의 결합 방향은 오른쪽에서 왼쪽이다.

 

대입 연산자 설명
= 왼쪽의 피연산자에 오른쪽의 피연산자를 대입함
+= 왼쪽의 피연산자에 오른쪽의 피연산자를 더한 후, 그 결과를 왼쪽의 피연산자에 대입
-= 왼쪽의 피연산자에 오른쪽의 피연산자를 뺀 후, 그 결과를 왼쪽의 피연산자에 대입
*= 왼쪽의 피연산자에 오른쪽의 피연산자를 곱한 후, 그 결과를 왼쪽의 피연산자에 대입
/= 왼쪽의 피연산자에 오른쪽의 피연산자를 나눈 후, 그 결과를 왼쪽의 피연산자에 대입
%= 왼쪽의 피연산자에 오른쪽의 피연산자를 나눈 후, 그 나머지를 왼쪽의 피연산자에 대입
&= 왼쪽의 피연산자를 오른쪽의 피연산자와 비트 AND 연산한 후, 그 결과를 왼쪽의 피연산자에 대입
|= 왼쪽의 피연산자를 오른쪽의 피연산자와 비트 OR 연산한 후, 그 결과를 왼쪽의 피연산자에 대입
^= 왼쪽의 피연산자를 오른쪽의 피연산자와 비트 XOR 연산한 후, 그 결과를 왼쪽의 피연산자에 대입
<<= 왼쪽의 피연산자를 오른쪽의 피연산자와 비트 왼쪽 시프트한 후, 그 결과를 왼쪽의 피연산자에 대입
>>= 왼쪽의 피연산자를 오른쪽의 피연산자만큼 부호를 유지하며 오른쪽 시프트한 후, 그 결과를 왼쪽의 피연산자에 대입
>>>= 왼쪽의 피연산자를 오른쪽의 피연산자만큼 부호를 유지하며 오른쪽 시프트한 후, 그 결과를 왼쪽의 피연산자에 대입

예제
결과


화살표 (->) 연산자

화살표 연산자는 Java 8에 포함된 람다 표현식의 한 부분이다.람다식은 함수를 변수처럼 사용할 수 있는 개념이다. JDK8 이전의 자바에는 '메소드'라는 함수 형태가 존재하지만객체(혹은 클래스)를 통해서만 접근이 가능하고, 메소드 그 자체를 변수로 사용하지는 못했다.하지만 람다식 사용부터는 함수를 변수처럼 사용할 수 있기 때문에 파라미터로 다른 메소드의 인자로 전달할 수 있고,리턴값으로 함수를 받을 수도있다.

 

자바 람다식은 사실 완벽한 함수형 프로그래밍방식이라 할 수는 없다. 그 이유는 자바 람다식은 함수형에 대해서 새로 정의한게 아닌 기존에 존재하는 Interface형태와 같이 람다식을 표현하기 때문이다.

 

장점 :

1. 코드의 라인수가 줄어듦

2. 병렬 프로그래밍이 가능

3. 메소드로 행동방식을 전달 가능

4. 의도의 명확성(가독성 Up)

 

단점 :

1. 람다식의 호출을 위해 직접 메소드를 불러야 함

2. 재귀 람다식의 호출이 까다롭다.

3. 클로저가 지원되지 않음.

4. 함수 외부의 값을 변경한다.

 

자세한 내용은 추후에 람다식 공부할 때 알아보자.


3항 연산자

3항 연산자는 조건식과 조건식이 true일 때와 false일 때 반환되는 값, 이 세 가지가 삼항 연산자의 피연산자이다.

3항 연산자의 조건식에는 연산결과가 true 또는 false인 식이 사용되어야 한다.if - else 문과 바꿔 쓸 수 있으며, 코드 간결화가 가능하다.

조건식 ? 식1 : 식2

조건식이 true라면 식1 

조건식이 false라면 식2

 

예제를 하나 보자.

int num = 10;
System.out.println((num > 1) ? "양수" : (num < 0) ? "음수" : 0);

결과는 '양수'이다.

위의 코드를 if - else문으로 바꾸면 아래처럼 코드 라인 수가 늘어나는 것을 볼 수 있다.

int num = 10;

if(num > 1) {
	System.out.println("양수");
}else if(num < 0) {
	System.out.println("음수");
}else {
	System.out.println("0");
}

연산자 우선순위

우선순위 연산자 내용
1 (). [] 괄호 / 대괄호
2 !, ~, ++, -- 부정 / 증감 연산자
3 *, /, % 곱셈, 나눗셈, 나머지 연산자
4 +, - 덧셈, 뺄셈연산자
5 <<, >>, >>> 쉬프트 연산자
6 <, <=, >, >= 관계 연산자
7 ==, !=  
8 & 논리 연산자
9 ^  
10 |  
11 && 논리곱 연산자
12 || 논리합 연산자
13 ? : 조건 연산자
14 =, +=, -=, *=, /=, %=, <<=, >>=, >>>=, &=, ^=, ~= 대입 연산자

 


(optional) Java 13. switch 연산자

Java 12부터는 콜론(:) 대신 화살표(->) 연산자를 사용할 수 있고,

Java 13부터는 break 대신 yield를 사용할 수 있다.

 

기본 switch문

public enum Day { SUNDAY, MONDAY, TUESDAY,
    WEDNESDAY, THURSDAY, FRIDAY, SATURDAY; }

// ...

    int numLetters = 0;
    Day day = Day.WEDNESDAY;
    switch (day) {
        case MONDAY:
        case FRIDAY:
        case SUNDAY:
            numLetters = 6;
            break;
        case TUESDAY:
            numLetters = 7;
            break;
        case THURSDAY:
        case SATURDAY:
            numLetters = 8;
            break;
        case WEDNESDAY:
            numLetters = 9;
            break;
        default:
            throw new IllegalStateException("Invalid day: " + day);
    }
    System.out.println(numLetters);

Java 12 콜론(:) -> 화살표(->)

int numLetters = 0;
Day day = Day.WEDNESDAY;
switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> numLetters = 6;
    case TUESDAY                -> numLetters = 7;
    case THURSDAY, SATURDAY     -> numLetters = 8;
    case WEDNESDAY              -> numLetters = 9;
    default -> throw new IllegalStateException("Invalid day: " + day);
};
System.out.println(numLetters);

Java 13 break -> yield

Day day = Day.WEDNESDAY;
int numLetters = switch (day) {
    case MONDAY:
    case FRIDAY:
    case SUNDAY:
        System.out.println(6);
        yield 6;
    case TUESDAY:
        System.out.println(7);
        yield 7;
    case THURSDAY:
    case SATURDAY:
        System.out.println(8);
        yield 8;
    case WEDNESDAY:
        System.out.println(9);
        yield 9;
    default:
        throw new IllegalStateException("Invalid day: " + day);
};
System.out.println(numLetters);

break 대신 yield를 사용한다면, 주의해야할 점이 있다.

콜론이 있는 구문에서 yield가 빠지게 되면 컴파일 에러가 발생하여 미리 알 수 있기 때문에

화살표(->) 연산자를 사용할 것을 권장한다.

int numLetters = switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> {
        System.out.println(6);
        yield 6;
    }
    case TUESDAY -> {
        System.out.println(7);
        yield 7;
    }
    case THURSDAY, SATURDAY -> {
        System.out.println(8);
        yield 8;
    }
    case WEDNESDAY -> {
        System.out.println(9);
        yield 9;
    }
    default -> {
        throw new IllegalStateException("Invalid day: " + day);
    }
};  

출처 : https://docs.oracle.com/en/java/javase/13/language/switch-expressions.html 

반응형

블로그의 정보

슬기로운 개발생활

coco3o

활동하기