1HOON
논리적 코딩
1HOON
전체 방문자
오늘
어제
  • HOME (187)
    • ☕️ JAVA (28)
      • WhiteShip Java LIVE Study (6)
      • Effective JAVA (10)
    • 🔮 KOTLIN (4)
    • 🌱 SPRING (51)
      • 스프링 인 액션 (22)
      • JPA (18)
    • ☕️ JAVASCRIPT (6)
    • 📃 DATABASE (40)
      • ORACLE (37)
      • MSSQL (2)
    • 🐧 LINUX (4)
    • 🐳 DOCKER (5)
    • 🐙 KUBERNETES (4)
    • 🏗️ ARCHITECTURE (8)
    • 📦 ETC (27)
      • TOY PROJECT (5)
      • RECRUIT (1)
      • 그냥 쓰고 싶어서요 (14)
      • TIL (1)
    • 🤿 DEEP DIVE (1)
    • 🚽 Deprecated (9)
      • PYTHON (3)
      • AWS (2)
      • HTTP 완벽가이드 (3)
      • WEB (1)

블로그 메뉴

  • 홈
  • 방명록
  • 관리

인기 글

최근 글

티스토리

hELLO · Designed By 정상우.
1HOON

논리적 코딩

[WhiteShip Java LIVE Study] 3주차 : 연산자
☕️ JAVA/WhiteShip Java LIVE Study

[WhiteShip Java LIVE Study] 3주차 : 연산자

2020. 11. 30. 22:01

목표

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

학습할 것

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

연산자


연산자는 '연산을 수행하는 기호'를 말한다.  연산자가 연산을 수행하려면 반드시 연산의 대상이 있어야 하는데, 그것을 '피연산자'라고 한다.

  • 연산자(operator) : 연산을 수행하는 기호(+, -, *, / 등)
  • 피연산자(operand) : 연산자의 작업 대상(변수, 상수, 리터럴, 수식 등)

 

연산자의 종류는 아래와 같다.

종류 연산자 설명
산술 연산자 +  -  *  /  %  <<  >> 사칙 연산과 나머지 연산(%)
관계(비교) 연산자 >  <  >=  <=  ==  != 크고 작음과 같고 다름을 비교
논리 연산자 &&  ||  !  &  |  ^  ~ 그리고(AND)와 또는(OR)으로 조건을 연결
대입 연산자 = 우변의 값을 좌변에 저장
기타 (type) ?: instance of 형변환 연산자, 삼항 연산자, instance of 연산자

 

 

산술 연산자


산술 연산자에는 사칙 연산자와 나머지 연산자가 있다.

 

산술 연산자

  • 덧셈(+), 뺄셈(-), 곱셈(*), 나눗셈(/)

각 산술 연산자를 사용해 아래 코드를 작성해 실행시켜보자.

public class Operator
{
	public static void main(String[] agrs)
    {
    	int a = 10;
        int b = 3;
        
        // 덧셈
        System.out.printf("a + b = %d%n", a + b);
        
        // 뺄셈
        System.out.printf("a - b = %d%n", a - b);
        
        // 곱셈
        System.out.printf("a * b = %d%n", a * b);
        
        // 나눗셈
        System.out.printf("a / b = %d%n", a / b);
    }
}

위 코드를 실행시키면 각각 아래 결과가 나온다.

a + b = 13
a - b = 7
a * b = 30
a / b = 3

Java 연산자를 이미 알고 있는 사람은 눈치챘겠지만, 나눗셈 연산자의 경우 우리가 수학적으로 생각하는 나눗셈 결과값이 아닌 다른 값이 반환된다.

변수 a와 b가 정수형 자료형(int)이기 때문에, 나눗셈 연산 이후 정수부 외 소수점 이하는 버려지기 때문이다. 이 때 중요한 것은 소수점 이하가 버려질때 반올림이 아니라 버림으로 처리된다는 것이다.

올바른 연산을 하기 위해서는 두 피연산자(a, b) 중 하나를 실수형으로 형변환 해주면된다.

public class Operator
{
	public static void main(String[] args)
    {
    	int a = 10;
        int b = 3;
        
        System.out.printf("a / b = %f", a / (float) b);
    }
}
a / b = 3.333333

 

그리고 피연산자가 정수형인 경우 나누는 수로 0을 사용할 수 없다. 0으로 정수형을 나누게되면 컴파일시에는 문제가 없으나, 런타임 상황에서 ArithmeticException이 발생한다.

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

        System.out.printf("a / b = %f", a / b);
    }
}
Exception in thread "main" java.lang.ArithmeticException: / by zero
	at main.Operator.main(Operator.java:10)

단, 0을 float나 double 로 형변환해 나누면 ArithmeticException은 피할 수 있으나 결과값은 Infinity(무한)이 반환된다.

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

        System.out.printf("a / b = %f", a / (float) b);
    }
}
a / b = Infinity

 

이렇듯, 산술 연산자의 경우 우리가 당연시 여기는대로 연산이 수행된다. 하지만 그렇지 않은 경우도 있는데, 이는 자료형에 의해 발생한다.

public class Operator
{
    public static void main(String[] args)
    {
        byte a = 10;
        byte b = 20;
        byte c = a + b;

        System.out.printf("a + b = %d", c);
    }
}

위 코드를 작성하면 byte c = a + b; 라인에서 컴파일 오류가 발생하는데, 이유는 아래와 같다.

  1. a와 b는 모두 int 형보다 작은 byte 형 변수이다.
  2. + 연산자는 이 두 변수를 int형으로 변환해 연산을 수행한다.
  3. 때문에, 결과값은 byte가 아닌 int형 자료형이다.
  4. 그런데 이 결과값을 byte형 변수에 형변환 없이 넣으려 했기 때문에 컴파일 오류가 발생한다.

 

자료형에 의한 문제는 더있다.

public class Operator
{
    public static void main(String[] args)
    {
        byte a = 10;
        byte b = 30;
        byte c = (byte)(a * b);

        System.out.printf("a * b = %d", c);
    }
}

위 코드를 수행하면 어떤 결과가 나올까? 300? 그렇지 않다.

a * b = 44

자료형을 제외하고 생각하면 300이 맞지만, 위 코드에서는 아래의 순서대로 동작한다.

  1. byte형 a 와 b가 곱셈 연산을 수행한다.
  2. 이 과전에서 자료형이 int형으로 바뀌고 결과값은 300이 된다.
  3. 결과값 300을 byte형 변수 c에 담기 위해 byte 형으로 형변환을 수행한다.
  4. 결과값이 byte 자료형의 최대 값 127을 초과하므로 오버플로우가 발생하고, 이로 인해 c에는 44가 담긴다.

이러한 값 손실 문제를 예방하기 위해서는 연산 시 충분히 큰 자료형을 사용하도록 해야한다.

 

 

나머지 연산자

나머지 연산자는 나눗셈 연산 이후 나머지 값을 결과로 반환하는 연산자이다. 나눗셈과 동일하게 나누는 수를 0으로 사용할 수 없고, 피연산자로 정수만 허용한다.

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

        System.out.printf("a / b = %f%n", a / (float) b);
        System.out.printf("a %% b = %d%n", a % b);
    }
}
a / b = 3.333333
a % b = 1

 

 

비트 연산자


비트 연산자는 데이터를 bit 단위로 논리 연산하는 연산자이다. 때문에 실수형은 허용하지 않고 정수형만 연산이 가능하다.

 

  • | (OR 연산자)
    피연산자 중 한 쪽의 값이 1이면, 1을 결과로 얻는다. 그 외에는 0을 결과로 얻는다.
  • & (AND 연산자)
    피연산자 양 쪽이 모두 1이어야만 1을 결과로 얻는다. 그 외에는 0을 결과로 얻는다.
  • ^ (XOR 연산자)
    피연산자의 값이 서로 다를 때만 1을 결과로 얻는다. 같을 때는 0을 얻는다.

코드로 간단히 살펴보자.

public class Operator
{
    public static void main(String[] args)
    {
        int a = 1;
        int b = 0;

        // OR 연산
        System.out.printf("a | b = %d%n", a | b);

        // AND 연산
        System.out.printf("a & b = %d%n", a & b);

        // XOR 연산
        System.out.printf("a ^ b = %d%n", a ^ b);
    }
}
a | b = 1
a & b = 0
a ^ b = 1

 

이 비트 연산자를 활용하는 코딩 테스트도 있는데, 간단하게 하나 풀어보자.

1~10 범위의 정수형 값이 5개 담겨져있는 배열에는 한 개의 요소를 제외한 모든 요소가 중복된 값이다.
이 때 중복되지 않는 값을 찾아라.

이 문제는 위의 비트 연산자를 이용해 간단히 해결할 수 있다.

public class Operator
{
    public static void main(String[] args)
    {
        int[] intArr = {1, 2, 3, 1, 2};
        int result = 0;
        for (int a : intArr)
        {
            result = result ^ a;
        }

        System.out.printf("중복되지 않은 값은 %d 입니다.", result);
    }
}
중복되지 않은 값은 3 입니다.

어떻게 이런 결과를 도출했을까? 총 5 번의 연산을 하나씩 살펴보자

 

 

 

관계 연산자


관계 연산자는 비교 연산자라고도 하며, 두 피연산자를 비교하는데 사용한다. 연산 결과는 반드시 boolean 자료형의 true / false 둘 중 하나이다.

  • > : 좌변 값이 크면 true, 작으면 false
  • < : 좌변 값이 작으면 true, 크면 false
  • >= : 좌변 값이 크거나 같으면 true, 그외에는 false
  • <= : 좌변 값이 작거나 같으면 true, 그외에는 false
  • == : 좌변과 우변의 값이 같으면 true, 다르면 false
  • != : 좌변과 우변의 값이 다르면 true, 같으면 false
public class Operator
{
	public static void main(String[] args)
    {
    	int a = 10;
        int b = 3;
        
        System.out.printf("a > b : %b%n", a > b);
        
        System.out.printf("a < b : %b%n", a < b);
        
        System.out.printf("a >= b : %b%n", a >= b);
        
        System.out.printf("a <= b : %b%n", a <= b);
        
        System.out.printf("a == b : %b%n", a == b);
        
        System.out.printf("a != b : %b%n", a != b);
    }
}
a > b : true
a < b : false
a >= b : true
a <= b : false
a == b : false
a != b : true

 

 

논리 연산자


논리 연산자는 둘 이상의 조건을 AND 또는 OR 로 연결해 하나의 식을 표현할 수 있게 해준다.

  • && : AND 결합. 피연산자 양쪽 모두 true이어야 true를 결과로 받는다.
  • || : OR 결합. 피연산자 중 어느 한 쪽만 true이면 true를 결과로 받는다.
  • ! : 단항 연산자로, 피연산자의 값의 반대 값을 결과로 받는다.
public class Operator
{
	public static void main(String[] args)
    {
    	int a = 10;
        int b = 3;
        
        // AND 결합
        System.out.printf("a > 7 && b < 1 ==> %b%n"), a > 7 && b < 1);
        
        // OR 결합
        System.out.printf("a > 7 || b < 1 ==> %b%n", a > 7 || b < 1);
        
        // ! 연산자
        System.out.printf("!(a > 7) ==> %b%n", !(a > 7));
    }
}
a > 7 && b < 1 ==> false
a > 7 || b < 1 ==> true
!(a > 7) ==> false

 

 

instanceof


변수가 참조하고있는 객체의 실제 타입을 확인하기 위해 사용하는 연산자이다. 연산자의 좌변에는 변수를, 우변에는 타입을 위치한다.

 

public class Operator
{
    public static void main(String[] args)
    {
        CustomClass variable = new CustomClass();
        System.out.printf("variable instance of CustomClass : %b", variable instanceof CustomClass);
    }

    public static class CustomClass
    {
        public CustomClass ()
        {
        }
    }
}
variable instance of CustomClass : true

 

만약, 변수의 타입 클래스가 다른 클래스를 상속받는 클래스일 경우, 상위 클래스를 대상으로 instanceof 연산을 수행했을 때도 true가 반환된다.

public class Operator
{
    public static void main(String[] args)
    {
        Bar bar = new Bar();
        System.out.printf("bar instance of Bar : %b%n", bar instanceof Bar);
        System.out.printf("bar instance of Foo : %b%n", bar instanceof Foo);
    }

    public static class Foo
    {
        public Foo () {}
    }

    public static class Bar extends Foo
    {
        public Bar () {}
    }
}
bar instance of Bar : true
bar instance of Foo : true

 

마찬가지로, 인터페이스를 구현하는 클래스의 경우, 인터페이스를 대상으로 instanceof 연산을 수행했을 때도 true가 반환된다.

public class Operator
{
    public static void main(String[] args)
    {
        Bar bar = new Bar();
        System.out.printf("bar instance of Bar : %b%n", bar instanceof Bar);
        System.out.printf("bar instance of Foo : %b%n", bar instanceof Foo);
    }

    public interface Foo
    {
    }

    public static class Bar implements Foo
    {
        public Bar () {}
    }
}
bar instance of Bar : true
bar instance of Foo : true

 

 

assignment(=) operator


대입 연산자는 변수와 같은 저장공간에 값 또는 연산 결과를 저장하는데 사용된다. 대입 연산자는 연산자들 중에서 우선순위가 가장 낮기 때문에 식에서 제일 나중에 수행되고 저장된 값을 연산 결과로 반환한다.

 

아래 코드를 수행하면 간단히 확인할 수 있다.

public class Operator
{
    public static void main(String[] args)
    {
        int x, y;
        System.out.println(x=y=3);
        System.out.println(x);
        System.out.println(y);
    }
}
3
3
3

 

그리고, 앞서 설명한 것과 같이 값 또는 연산 결과를 저장하는데 사용되므로, 좌변에는 리터럴이나 상수 값이 위치할 수 없다.

 

 

화살표(->) 연산자


Java 8에서 람다가 도입되면서 사용하는 연산자이다. 자세한 내용은 나중에... 람다 부분에서 다루자...

public class Operator
{
    public static void main(String[] args)
    {
        Bar bar = new Bar();
        bar.doSomething("test");
    }

    @FunctionalInterface
    public interface Foo
    {
        String doSomething(String s);
    }

    public static class Bar implements Foo
    {
        @Override
        public String doSomething(String s) {
            return "Bar ::: " + s;
        }

        public Bar(){}
    }
}

위 코드는 익명 클래스를 활용해 아래와 같이 줄일 수 있다.

public class Operator
{
    public static void main(String[] args)
    {
        Foo foo = new Foo() {
            @Override
            public String doSomething(String s) {
                return "anonymous class " + s;
            }
        };

        foo.doSomething("test");
    }

    @FunctionalInterface
    public interface Foo
    {
        String doSomething(String s);
    }
}

그리고 람다를 이용해 더 줄일 수 있다!

public class Operator
{
    public static void main(String[] args)
    {
        Foo foo = (s) -> "lambda " + s;
        foo.doSomething("test");
    }

    @FunctionalInterface
    public interface Foo
    {
        String doSomething(String s);
    }
}

 

 

3항 연산자


삼항 연산자는 3개의 피연산자를 필요로하는 연산자이다.

조건식 ? 식1 : 식2

구조로 되어있는데, 조건식이 참이면 식1이, 조건식이 거짓이면 식2이 연산결과가 된다.

public class Operator
{
    public static void main(String[] args)
    {
        int a = 10;
        int b = 3;
        String result = (a > b)? "참" : "거짓";

        System.out.printf("(a > b)? 참 : 거짓 ==> %s", result);
    }
}
(a > b)? 참 : 거짓 ==> 참

 

 

연산자 우선순위


단항 연산자 > 이항 연산자(곱셉,나눗셈 > 덧셈,뺄셈) > 비교 연산자 > 논리 연산자 > 삼항 연산자 > 대입 연산자 > 람다 표현식

반응형
저작자표시 비영리 변경금지 (새창열림)

'☕️ JAVA > WhiteShip Java LIVE Study' 카테고리의 다른 글

[WhiteShip Java LIVE Study] 6주차 : 상속  (0) 2021.02.17
[WhiteShip Java LIVE Study] 5주차 : 클래스  (2) 2020.12.25
[WhiteShip Java LIVE Study] 4주차 : 제어문  (0) 2020.12.11
[WhiteShip Java LIVE Study] 2주차 : 자바 데이터 타입, 변수 그리고 배열  (0) 2020.11.20
[WhiteShip Java LIVE Study] 1주차 : JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가  (0) 2020.11.15
    '☕️ JAVA/WhiteShip Java LIVE Study' 카테고리의 다른 글
    • [WhiteShip Java LIVE Study] 5주차 : 클래스
    • [WhiteShip Java LIVE Study] 4주차 : 제어문
    • [WhiteShip Java LIVE Study] 2주차 : 자바 데이터 타입, 변수 그리고 배열
    • [WhiteShip Java LIVE Study] 1주차 : JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가
    1HOON
    1HOON

    티스토리툴바