코딩하는 털보

STUDY HALLE - 3주차 본문

Diary/Study Halle

STUDY HALLE - 3주차

이정인 2020. 12. 20. 20:40

STUDY HALLE

3주차 : 연산자


목표

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

학습할 것

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

산술연산자

수학적인 계산에 사용되는 연산자이다.

연산자 의미
+ 더하기
- 빼기
* 곱하기
/ 나누기
% 나머지 값 구하기
public class Test {
  public static void main(String args[]) {
    int a = 7;
    int b = 3;
    System.out.println(a+b); // 7+3=10
    System.out.println(a-b); // 7-3=4
    System.out.println(a*b); // 7*3=21
    System.out.println(a/b); // 7/3 값 2
    System.out.println(a%b); // 7/3 나머지 1

    //계산되는 순서는 수학의 사칙연산과 동일하다.
    System.out.println(a+b*30); // 7+3*30=97
    }
}

'+' 연산자는 문자열과 문자열을 결합할 때도 사용된다.

public class Test {
  public static void main(String args[]) {
    int a = "안녕";
    int b = "하세요";
    System.out.println(a+b); // "안녕하세요"
    }
}

비트연산자

연산자 의미
~ 비트 반전 (1의 보수)
& 비트 단위의 AND, 1&1인 경우에 1, 나머지 0
^ 비트 단위의 XOR, 두 비트가 서로 다른경우 1
<< 왼쪽 shift, 0으로 채우기
>> 오른쪽 shift, 부호 비트로 채우기
>>> 오른쪽 shift, 0으로 채우기

비트 연산자의 사용처

  • 비트켜기 : &00001111, 하위 4bit중 1인 비트만 꺼내기
  • 비트끄기 : |11110000, 하위 4bit중 0인 비트만 0으로 만들기
  • 비트토글 : 모든 비트들을 0은 1로, 1은 0으로 바꾸고 싶을 때
  • shift를 통해 곱셈 나눗셈을 빠르게할 수 있다.
public class Test {
  public static void main(String args[]) {
    int num1 = 0B00001010; //10
    int num2 = 0B00000101; //5

    System.out.println(~num1); //11110101 -11
    System.out.println(num1 & num2); //00000000 0
    System.out.println(num1 | num2); //00001111 15
    System.out.println(num1 ^ num2); //00001111 15
    System.out.println(num2 << 1); //(x2) 00001010 10
    System.out.println(num2 << 2); //(x2^2) 00010100 20
    System.out.println(num2 << 3); //(x2^3) 00010100 40
    System.out.println(num2 >> 2); //(/2^2) 00000001 1

    System.out.println(num2 & 0B00001111); //00000101 5
    System.out.println(num2 | 0B11110000); //11110101 245
  }
}

관계연산자

두 개의 변수나 리터럴을 서로 비교할 때 사용한다.

  • 비교 연산자라고도 한다.

  • 결과가 true/false로 반환 된다.

연산자 의미
A > B A가 B보다 크면 true, 아니면 false
A < B A가 B보다 작으면 true, 아니면 false
A >= B A가 B보다 크거나 같으면 true, 아니면 false
A <= B A가 B보다 작거나 같으면 true, 아니면 false
A == B A와 B가 같으면 true, 아니면 false
A != B A와 B가 다르면 true, 아니면 false

논리연산자

두개의 피연산자의 결과를 비교할 때 사용한다.

  • 결과가 true/false로 반환 된다.
연산자 의미
&& 논리 곱, 두 항 모두 참이어야 true, 아니면 false
! 부정, 항의 논리 결과 변경 (true -> false, false -> true)
public class Test {
  public static void main(String args[]) {
    int a = 10;
    int b = 20;

    System.out.println("a>b = "+(a>b)); //a>b = false
    System.out.println("a<b = "+(a<b)); //a<b = true
    System.out.println("a==b = "+(a==b)); //a==b = false
    System.out.println("a!=b = "+(a!=b)); //a!=b = true

    boolean value = a<b&&a!=b;
    System.out.println(value); //true&&true = true
    value = a<b&&a==b;
    System.out.println(value); //true&&false = false
    value = a<b||a==b;
    System.out.println(value); //true||false = true
    value = a>b||a==b;
    System.out.println(value); //false||false = false
    System.out.println(!value); //!false = true
  }
}

논리 연산자는 단락 회로 평가 방식으로 실행된다.

단락 회로 평가

  • 앞 항 결과만으로 논리 연산자 결과가 나온다면 뒷 항은 평가되지 않음.

  • 프로그램에서 예상하지 못한 결과가 발생할 수 있으므로 유의가 필요하다.

public class Test {
    public static void main(String[] args) {

        int num = 10;
        int i = 2;

        boolean value = ((num=num+10)<10)&&((i=i+2)<10); 
          //앞 항의 결과가 false이므로 value가 결정되어 num은 변경되지만 i는 변경되지 않는다.

          System.out.println(value); //false
        System.out.println(num);  //20
        System.out.println(i);     //2

    }
}

instanceof

instanceof 연산자는 피연산자의 타입을 비교하는 특별한 연산자이다.

    variable instanceof type;
  • 왼쪽 피연산자로 변수를 받는데, 참조 변수만 받을 수 있다.
  • 오른쪽 피연산자로 타입을 받는데, 레퍼런스 타입만 받을 수 있다.
  • 값의 결과로 참조 변수가 해당 타입이거나 그 타입으로 형 변환 할 수 있다면 true, 아니면 false를 반환한다.
public class Test {
  public static void main(String args[]) {
    String a = "yeah";

    System.out.println(a instanceof String); //true
  }
}

주로 조건문에서 업케스팅된 객체가 원래 어떤 타입이었는지를 확인하기 위해 사용된다.

public class Test {

    public static void main(String[] args) {
    Sedan sedan = new Sedan();
    Car car = (Car)sedan; //car는 sedan이 Car로 업캐스팅된 인스턴스.

    if (car instanceof Sedan) { //car는 원래 sedan이었으므로 Sedan으로 형 변환 할 수 있다.
      Sedan new_sedan = (Sedan)car;
      System.out.println("This car is Sedan.");
    } else {
      System.out.println("This car is not Sedan.");
    }
  }
}

class Car {
    String color;
    int door;
}

class Sedan extends Car {
}

assignment(=) operator

대입 연산자('=') : 변수에 리터럴이나 인스턴스 또는 다른 변수의 값을 대입할 때 사용한다.

    int age = 10;

복합 대입 연산자 : 대입 연산자 앞의 연산자의 결과를 변수에 대입할 때 사용한다.

연산자 의미
a += b a에 b를 더한 뒤 결과를 다시 a에 대입
a -= b a에서 b를 뺀 뒤 결과를 다시 a에 대입
a *= b a와 b를 곱한 뒤 결과를 다시 a에 대입
a /= b a를 b로 나눈 값을 다시 a에 대입
a %= b a를 b로 나눈 나머지를 다시 a에 대입
public class Test {

    public static void main(String[] args) {
    int a = 10;

    a += 10;
    System.out.println(a); //10+10 = 20
    a -= 10;
    System.out.println(a); //20-10 = 10
    a *= 10;
    System.out.println(a); //10*10 = 100
    a /= 10;
    System.out.println(a); //100/10 의 값 10
    a %= 3;
    System.out.println(a); //10/3의 나머지 1

  }
}

화살표(->) 연산자

람다식 : 자바 8부터 사용가능한 식별자 없이 실행 가능한 함수 표현식이다.

  • 함수를 보다 간결하게 표현할 수 있다.
  • 함수가 이름을 가질 필요가 없다.
  • 클래스를 생성하지 않고 함수의 호출만으로 기능 수행 (내부적으로 익명 객체 사용)
  • 매개변수의 타입 추론을 사용할 수 있다.
  • 무명 함수는 재사용이 불가능하고 디버깅이 어렵다.
(매개변수) -> {실행문}
InterFace itfc = str -> {System.out.println(str);};
InterFace2 itfc2 = (x,y) -> x+y //구현부가 return 문 하나라면 return, 중괄호 생략 가능
interface StringConcat{
  void makeString(String str1, String str2);
}

public class TestStringConcat {
    public static void main(String[] args) {

        StringConcat concat = (s,v) -> System.out.println(s+" "+v); //함수형 프로그래밍, 람다식 사용
        concat.makeString("hello","world"); //클래스 구현이 필요없고, 메서드 구현을 따로 만들 필요도 없음.
                                            //실제로는 아래처럼 익명 내부클래스로 동작한다.

        StringConcat concat2 = new StringConcat() {
            @Override
            public void makeString(String str1, String str2) {
                System.out.println(str1+" "+str2);
            }
        };
        concat2.makeString("hello","world");
    }
}

람다식은 프로그램내에서 변수처럼 사용할 수도 있다.

interface PrintString{
    void showString(String str);
}

public class TestLambda {
    public static void main(String[] args) {

        PrintString lambdaStr = str -> System.out.println(str); //함수의 구현부가 변수로 대입
        lambdaStr.showString("Test1");

        showMyString(lambdaStr); //매개변수로 활용
        PrintString lambdaStr2 = returnString(); //반환된 구현부를 변수에 대입
        lambdaStr2.showString("Test3");
    }

    public static void showMyString(PrintString p) {
        p.showString("Test2");
    }

    public static PrintString returnString() {
        return str->System.out.println(str+"!!!"); //함수의 구현부를 반환
    }
}

3항 연산자

IF문 대신 사용할 수 있는 연산자.

  • 동일한 IF,ELSE 코드보다 라인수가 줄어든다.
(조건문) ? val1 : val2;
//조건문이 참일 경우 val1을 반환하고 거짓인 경우 val2를 반환한다.
public class Test {

    public static void main(String[] args) {
    int a = 10;
    int b = 30;

    //더 큰 값을 변수에 대입.
    int bigger = (a>b) ? a : b;
    System.out.println(bigger); //더 큰 값인 30이 출력된다.
  }
}

연산자 우선 순위(Operator Precedence)

연산자가 여러개 있을 때 먼저 실행되는 우선순위가 있다.

  • 괄호의 우선순위가 제일 높고, 산술 > 비교 > 논리 > 대입의 순서.
  • 단항 > 이항 > 삼항의 순서.
  • 연산자의 연산 진행방향은 왼쪽에서 오른쪽으로 수행되며, 단항 연산자와 대입 연산자의 경우에는 오른쪽에서 왼쪽으로 수행된다.
Priority Operator Direction
1 [] . () 왼쪽에서 오른쪽
2 a++ a-- 방향 없음
3 ++a --a +,- ! ~ : 단항 연산자 오른쪽에서 왼쪽
4 () new 오른쪽에서 왼쪽
5 * / % 왼쪽에서 오른쪽
6 + - +(문자 결합) 왼쪽에서 오른쪽
7 << >> >>> 왼쪽에서 오른쪽
8 < <= > >= instanceof 방향 없음
9 == != 왼쪽에서 오른쪽
10 & 왼쪽에서 오른쪽
11 ^ 왼쪽에서 오른쪽
12
13 && 왼쪽에서 오른쪽
14
15 ?: 오른쪽에서 왼쪽
16 = += -= *= /= %= &= ^= = <<= >>= >>>=

Switch Expressions

자바 12부터 switch 문을 강화한 Switch Expressions이 등장하였다.

  • Switch Expressions
    • case 병합을 ','(콤마)로 할 수 있다.
    • break으로 값을 반환할 수 있다. (Java 13부터 yield로 대체되었다. )
    • label rules(화살표)로 값을 반환할 수 있다.
    • 현재 preview feature이며, 기본적으로는 disabled이고 사용하려면 추가 설정이 필요하다.
import java.util.Scanner;

public class Test {
    public static void main(String[] args) {

        Scanner scanner = new Scanner(System.in);

        int month = scanner.nextInt();

        int day = switch(month) {
            //case 1: case 5: case 7: case 8: case 10: case 12:
            //case 병합을 나열하는 것도 간편하게 바뀌었다.
            case 1, 5, 7, 8, 10, 12:
                yield 13; //break 대신 yield를 사용하며, 결과를 반환한다.
            case 2: 
                yield 28;
            case 3, 4, 6, 9, 11:
                yield 30;
            default :
                System.out.println("Error");
                yield 0;
        }
        System.out.println(month + "월의 날짜 수는 " + day + "일 입니다.");
    }
}

label rules(화살표)를 사용한 예시

import java.util.Scanner;

public class Test {
    public static void main(String[] args) {

        Scanner scanner = new Scanner(System.in);

        int month = scanner.nextInt();

        int day = switch(month) {
            case 1, 5, 7, 8, 10, 12 -> 13; 
            case 2 -> 28;
            case 3, 4, 6, 9, 11 -> 30;
            default -> {
                System.out.println("Error");
                yield 0;
            }
        }
        System.out.println(month + "월의 날짜 수는 " + day + "일 입니다.");
    }
}

preview feature 를 위한 컴파일 및 실행

javac --enable-preview --release 12 Example.java
java --enable-preview Example
Comments