본문 바로가기

WhiteShip Java Study : 자바 처음부터 멀리까지

연산자

선장님과 함께하는 자바 스터디입니다.

자바 스터디 Github

github.com/whiteship/live-study

 

whiteship/live-study

온라인 스터디. Contribute to whiteship/live-study development by creating an account on GitHub.

github.com

나의 Github

github.com/cmg1411/whiteShip_live_study

 

cmg1411/whiteShip_live_study

✍ 자바 스터디할래. Contribute to cmg1411/whiteShip_live_study development by creating an account on GitHub.

github.com

 

 

산술 연산자

산술 연산자는 계산하는 연산자이다.

프로그래밍에 쓰이는 산술 연산자는 크게 다섯가지가 있다.

  • 더하기
public class plus {

    public static void main(String[] args) {
        int a = 1;
        int b = 3;
        System.out.println(a + b);

        double c = 3.5;
        int d = 5;
        System.out.println(c + d);

        char e = 'a';
        double f = 1.5;
        System.out.println(e + f);
    }
}

각 출력 결과는 어떻게 나올까.

첫번째는 자명하다. 4.

두번째 : int 가 더 큰 자료형인 double 로 자동으로 타입 프로모션되었다.

세번째 : a 는 아스키코드값으로 97 이다. 산술 연산은 기본적으로 숫자이기 때문에 문자형은 아스키코드 값으로 계산하게 된다. 이후 두번째와 같이 타입 프로모션되어 97.0 + 1.5 = 98.5 가 나온 것이다.

 

  • 빼기, 곱하기
public class minus {

    public static void main(String[] args) {
        int a = 5;
        int b = 10;
        System.out.println(a - b); // -5
        System.out.println(a * b); // 50

        double c = 7.5;
        int d = 5;
        System.out.println(c - d); // 2.5
        System.out.println(c * d); // 37.5

        char e = 'a';
        double f = 1.5;
        System.out.println(e - f); // 95.5
        System.out.println(e * f); // 145.5
    }
}

빼기와 곱하기는 더하기와 같은 방식으로 계산하게 된다.

 

  • 나누기
  • 프로그래밍에서 나누기는 실세계의 나누기보다는, 몫을 구하는 계산으로 보는 것이 더 알맞다.
  • 나누기는 조심해야 할 점이 있다.
  • 피연산자의 자료형이 다를 때에는 범위가 큰 쪽으로 묵시적 타입 프로모션된다.
  • 정수끼리의 나눗셈에서 결과는 정수여야 하기 떄문에, 소숫점 아래 부분은 잘라내고 정수형으로 묵시적 타입 캐스팅된다.
public class divide {
    public static void main(String[] args) {
        int a = 10;
        int b = 3;
        System.out.println(a / b); // 3

        double c = 1.5;
        int d = 5;
        System.out.println(c / d); // 0.3
        System.out.println(d / c); // 3.333333..
    }
}

 

  • 나머지
  • 나머지연산자의 기호는 % 이다.
  • 나누기가 몫을 구했다면, 나눗셈의 나머지는 % 연산인 것이다.
public class moduler {
    public static void main(String[] args) {
        int a = 10;
        int b = 3;
        System.out.println(a % b); // 1
        System.out.println(b % a); // 3

        int c = 10;
        double d = 57.5;
        System.out.println(d % c); // 7.5
    }
}
  • 나머지 연산도 다른 산술 연산자처럼 분배법칙이 적용되는데, 특이하게 적용된다.
(A + B) % C = ((A%C) + (B%c)) % C // 더하기, 곱하기 성립
(A - B) % C = ((A%C) - (B%C) + C) % C

나누기는 성립하지 않음

나머지값은 논리상 나눠지는 값보다 크면 안된다. 따라서 분배법칙이 들어가도 최종적으로 % C 가 들어간다.

그리고 빼기는, 분배법칙 내부의 결과가 음수가 나올 수 있으므로 +C 를 해준다. 어짜피 뒤에서 %C 를 해주기 떄문에 결과에 상관없는 연산이다.

 

 

비트연산자

public class bitCal {

    public static void main(String[] args) {
        Integer a = 12; // 0000 0000 0000 0000 0000 0000 0000 1100
        Integer b = 27; // 0000 0000 0000 0000 0000 0000 0001 1011
        Integer c = -10; // 1111 1111 1111 1111 1111 1111 1111 0110

        System.out.println(Integer.toBinaryString(a & b));
        // 0000 0000 0000 0000 0000 0000 0000 1100
        // 0000 0000 0000 0000 0000 0000 0001 1011
        // ----------------------------------------
        // 0000 0000 0000 0000 0000 0000 0000 1000
        
        System.out.println(Integer.toBinaryString(a | b));
        // 0000 0000 0000 0000 0000 0000 0000 1100
        // 0000 0000 0000 0000 0000 0000 0001 1011
        // ----------------------------------------
        // 0000 0000 0000 0000 0000 0000 0001 1111
        
        System.out.println(Integer.toBinaryString(a ^ b));
        // 0000 0000 0000 1100
        // 0000 0000 0001 1011
        // ----------------------------------------
        // 0000 0000 0000 0000 0000 0000 0001 0111
        
        System.out.println(Integer.toBinaryString(~a));
        // not 연산은 모든 비트를 반전시킨다. 이진수로는 아래와 같은결과가 나온다.
        // 1111 1111 1111 1111 1111 1111 1111 0011
        // MSB 가 1이므로 이 수는 음수이고, 음수를 10진수로 계산하려면 2의 보수를 취한다.
        // 1의 보수 = 0000 0000 0000 0000 0000 0000 0000 1100
        // + 1    = 0000 0000 0000 0000 0000 0000 0000 1101
        // = 13 의 음수는 -13
        
        System.out.println(Integer.toBinaryString(a << 2));
        // 0000 0000 0000 0000 0000 0000 0000 1100 왼쪽으로 2 비트 이동
        // ----------------------------------------
        // 0000 0000 0000 0000 0000 0000 0011 0000
        
        System.out.println(Integer.toBinaryString(a >> 3));
        // 1
        // 양수이므로 0으로 채워진다.
        
        System.out.println(Integer.toBinaryString(c >> 3));
        // 1111 1111 1111 1111 1111 1111 1111 1110
        // 음수이므로 1로 채워진다.
        
        System.out.println(Integer.toBinaryString(a >>> 3));
        // 1

        System.out.println(Integer.toBinaryString(c >>> 3));
        // 0001 1111 1111 1111 1111 1111 1111 1110
    }
}

 

 

관계연산자

 

 

논리연산자

  • 논리 연산자는 비트 연산자와 비슷하게 생겼다.
  • &&, || 처럼 두개가 들어간다.
  • 가장 큰 차이는 비트연산자는 말 그대로 비트를 대상으로 하는 연산이고,
  • 논리 연산자는 피연산자가 boolean 반환값을 가지는 조건식이라는 것이다.

 

 

instanceOf

  • 참조 변수가 참조하고 있는 인스턴스의 실제 타입인지 여부 boolean 을 반환
  • 한마디로, 어떤 클래스(or인터페이스) 로 만들어진 인스턴스인지 확인하는 연산자.
public class InstacneOf {
    static class A {}
    static class B extends A {}

    interface C {}
    static class D implements C {}

    public static void main(String[] args) {
        A a = new A();
        B b = new B();
        D d = new D();
        System.out.println(a instanceof B); // false
        System.out.println(a instanceof A); // true
        System.out.println(b instanceof A); // true, B 클래스는 A를 상속받았으므로 true
        System.out.println(d instanceof D); // true
        System.out.println(d instanceof C); // true
    }
}

 

 

 

대입연산자

  • 이항 연산자로, 왼쪽 피연산자에 오른쪽 피연산자를 대입하는 역할을 한다.

 

 

 

화살표(->) 연산자

  • 화살표 연산자는 Java 8 버전에서 함수형 프로그래밍이 도입되면서, 람다 표현식을 위해 만들어졌다.
  • 람다 표현식은 익명 함수를 간단하게 표현한 식이다.
  • 좌항에는 매개변수를 넣고, 우항에는 실행할 메서드를 기술한다.
  • 메서드 부분은 더 간단하게 메서드레퍼런스라는 방식을 사용할 수 있다.
함수형 인터페이스와 람다는 주제와 조금 벗어나지만 간단히 설명하자면,
인터페이스에 추상메서드 하나만 정의되어있는 형태를 함수형 인터페이스라고 하며,
이 인터페이스를 구현할 때 익명 클래스를 이용하여 그 하나의 함수만 오버라이딩하여 사용할 수 있다.
그런데 그 익명클래스는 너무 길기 때문에, 람다식이라는 방식을 이용하여 인터페이스를 구현하고 그 유일한 함수를 실행한다.
추상 메서드가 하나이기 때문에 람다식으로 자바가 추론이 가능하며, 하나이기 때문에 그 함수가 인터페이스를 정의한다.
public class Lambda {

    public static void main(String[] args) {
        FunctionalInterface f = new FunctionalInterface() {
            @Override
            public int add(int a, int b) {
                return a + b;
            }
        };

        int result = f.add(1, 2);
        System.out.println(result); // 3

        FunctionalInterface f2 = (a,b) -> a + b + b;
        System.out.println(f2.add(1, 2)); // 5
    }
}
public interface FunctionalInterface {
    int add(int a, int b);
}

 

 

 

3항 연산자

  • 3항연산자는 다음과 같이 3개의 항과 2개의 연산자를 사용한다.
(조건식) ? (조건식이 참일때 실행될 구문) : (조건식이 거짓일때 실행될 구문)
  • if 를 이용해야 할 것 같은 조건처리를 간단하게 해결할 수 있다.

 

 

연산자 우선순위

  • 외우면 좋고,
  • 헷갈린다면 괄호를 꾸준히 쓰자.

 

 

switch 연산자

  • Java 13 버전에는 switch 라는 연산자가 새로 나왔다.
  • 기존에 우리가 알던 분기문에 쓰이는 switch 랑은 다른 점이 있다.
  • 아래를 보자.

Java 8 document
java 13 document

  • 보듯이 switch statement 에서 switch Expression 으로 바뀌었다.
  • 기존의 switch 는 분기처리를 위해 사용하던 구문이었지만
  • 자바 13 의 switch 는 분기에 따라 반환값을 가질 수 있는 표현이 되었다는 말이다.
public class Switch {
    public static void main(String[] args) {
        char choice = 'a';

        int result = switch(choice) {
            case 'a' -> 1;
            case 'b' -> 2;
            default -> throw new IllegalStateException("Unexpected value: " + choice);
        };

        System.out.println(result);
    }
}

결과는 1이 나온다.

switch Expression 의 결과로 1이 반환된 것이다.

 

Java 10 에서 나온 var 타입추론을 이용하면, 여러 상황에 맞는 여러 자료형을 반환할 수 있다.

public class Switch {
    public static void main(String[] args) {
        char choice = 'b';

        var result = switch(choice) {
            case 'a' -> 1;
            case 'b' -> "hi";
            default -> throw new IllegalStateException("Unexpected value: " + choice);
        };

        System.out.println(result);
    }
}

콘솔에는 hi 가 찍힌다.

 

마지막으로 yield 키워드가 있는데, 위와같이 람다식을 쓰면 각 분기에서 한가지 처리를 한다.

여러 처리를 하기 위해 원래처럼 : 연산자를 쓴다면, yield 키워드를 통해 반환할 값을 명시할 수 있다.

 

    public static void main(String[] args) {
        char choice = 'b';

        var result = switch(choice) {
            case 'a':
                System.out.println("It is a.");
                yield 1;
            case 'b' :
                System.out.println("It is b.");
                yield "22";
            default :
                throw new IllegalStateException("Unexpected value: " + choice);
        };

        System.out.println(result);
    }

 

java 13 switch 문서

docs.oracle.com/en/java/javase/13/language/switch-expressions.html