✔스터디 할래 - 깃헙 페이지
✔이미지 작성 - draw.io
3주차 과제: 연산자
프로그램에서 데이터를 처리하여 결과를 산출하는 것을 연산(Operation)이라고 한다. 연산자는 연산에 사용되는 표시나 기호를 말하며, 연산되는 데이터를 피연산자(operand)라고 한다. 예를 들어, a + b에서 a와 b는 피연산자, +는 연산자라고 할 수 있다.
연산자는 필요로 하는 피연산자의 수에 따라 단항, 이항, 삼항 연산자로 구분된다.
단항 연산자
부호 연산자 (+, -)
ex) +a, -1
증가/감소 연산자 (++, --)
ex) ++x, i--
이항 연산자
ex) a + b , i % 2
삼항 연산자
ex) (number % 2 != 0) ? "홀수" : "짝수"
산술연산자에는 +, -, *, /, %이 존재하며, 피연산자의 수는 이항(2개)이며 산출되는 값으로는 숫자이다. 사용 예시는 아래와 같다.
public static void main(String[]args) {
System.out.println(3 + 2);
System.out.println(3 - 2);
System.out.println(3 * 2);
System.out.println(3 / 2);
System.out.println(3 % 2);
}
출력 결과:
5
1
6
1
1
출력 결과를 보면 +, - , * 는 각각 수학에서 덧셈, 뺄셈, 곱셈의 결과 값을 출력하는 것을 볼 수 있다.
/ 연산자는 나눗셈에서의 몫을 나타내고, % 연산자는 나눗셈에서 나머지를 나타낸다. 따라서 3 / 2에서의 출력 결과 1은 나눗셈의 몫이며 3 % 2에서의 1은 나눗셈의 나머지1을 나타내는 것이다.
비트란 정보의 최소 단위로 0 또는 1의 값을 가질 수 있다.
비트 연산자에는 ~, &, |, ^ 연산자가 있으며 피연산자의 수는 단항, 이항이 올 수 있다. 산출되는 값으로는 숫자 타입과 boolean 타입이며, 비트의 AND, OR, NOT, XOR 연산을 수행한다.
자료를 조사하면서, 비트 연산자에 쉬프트 연산자(>>, <<, >>>)를 같이 포함시켜 정리를 한 게시글이 다수 있는 것으로 보아 같이 묶이는 것 같다.(쉬프트 연산도 결국 비트를 조작하기 때문인가?) 이 글에서도 포함시켜 설명하겠다.
& 비트 AND 연산
AND연산은 두 피연산자가 모두 1일 때만 'SET'되는 연산자이다. 따라서 3과 2를 비트 AND연산을 하게 되면 3(0000_0011)의 첫번째 비트(1)와 2의 첫번째 비트(1)이 'SET'되며 3의 두번째 비트(1)과 2의 두번째 비트(0)의 연산 결과는 0이 되므로 3과 2의 비트 AND 연산 결과는 2가 출력 된다.
| 비트 OR 연산
OR연산은 두 피연산자 중 하나라도 1이면 'SET'되는 연산자이다. 따라서 3과 2를 비트 OR연산을 하게 되면 3(0000_0011)의 첫번째 비트(1)와 2의 첫번째 비트(1)이 'SET'되며 3의 두번째 비트(1)과 2의 두번째 비트(0)의 연산 결과 또한 1이 되므로 3과 2의 비트 OR 연산 결과는 3이 출력 된다.
^ 비트 XOR 연산
XOR(Exclusive-OR)이란 배타적 논리합으로 XOR연산은 두 피연산자 중 하나만 1일 때 'SET'되는 연산자이다. 따라서 3과 2를 비트 XOR연산을 하게 되면 3(0000_0011)의 첫번째 비트(1)와 2의 첫번째 비트(1)이 'RESET'되며 3의 두번째 비트(1)과 2의 두번째 비트(0)의 연산 결과는 1이 되므로 3과 2의 비트 XOR 연산 결과는 1이 출력 된다.
~ 비트 NOT 연산
NOT연산은 비트를 1->0, 0->1로 반전 시키는 연산이다. 예를 들어, 2(0000_0010)의 NOT연산(~)의 결과는(1111_1101)이다. 1111_1101을 어떠한 값인지 확인 하려면 2의 보수를 취해서 양의 정수를 구한 다음 해당 값에서 (-) 부호를 붙인 숫자이다. 따라서 ~2의 2의 보수를 구하기 전에 1의 보수(모든 비트를 반전) 시키고 LSB(Least Significant Bit)를 +1 한 값이 2의 보수이며 2의 보수를 확인한 결과 3인 것을 확인 할 수 있으며 그 결과 (1111_1101)은 -3인 것이다.
AND, OR, XOR, NOT 연산의 실제 출력 결과를 확인하면 다음과 같다.
비트 시프트(shift) 연산자는 지정한 수만큼 모든 비트를 전부 좌우로 이동시키며, Left shift 연산 후 빈 자리는 0으로 채워지고, Right shift 연산 후 빈 자리는 MSB(최상위 부호 비트)의 수로 채워진다.
<< Left Shift 연산
>> Right Shift 연산
>>> Unsigned Right Shift 연산
Right shift 연산은 shift 연산 후 빈 자리를 부호 비트로 채우는 반면 Unsigned Right Shift 연산자는 0으로 채운다.
Shift 연산의 실제 출력 동작 결과는 다음과 같다.
127을 Logic right shift 연산을 하게 되면 오른쪽 피연산자 수 만큼 shift를 수행하며, 오른쪽 피연산자 7일 경우 0을 출력하며, 그 보다 큰 수일 경우 0을 연산의 결과는 0이 되는 것을 확인 할 수 있다.
관계 연산자는 피연산자 사이의 상대적인 크기를 판단하는 두 개의 피연산자를 가지는 이항 연산자이다. 왼쪽의 피연산자와 오른쪽의 피연산자를 비교하여, 어느 쪽이 더 큰지, 작은지, 또는 서로 같은지를 판단한다. 관계 연산자의 종류는 아래와 같다.
초등학교 때 배운 간단한 대수 비교인 만큼 따로 코드 출력 결과는 작성하지 않겠다.
Computer Science에서 참(true)은 1, 거짓(false)로 나타내며 0이 아닌 모든 수를 참으로 표현하기도 한다.
논리 연산의 진리표(truth table)은 다음과 같다.
논리 연산의 동작을 실제 자바 환경에서 테스트 해 보았으며 동작은 진리표와 같다는 것을 확인 할 수 있다.
자바의 instanceof 연산자는 객체 타입을 확인하는데 사용한다. reference 변수가 참조하고 있는 객체의 타입을 알아보기 위해 사용하는 연산자이다. instanceof의 왼쪽에는 reference 변수를, 오른쪽에는 타입(클래스명)이 피연산자가 위치하는 이항 연산자 이며, 연산의 결과로 true 혹은 false를 반환 한다.
instanceof의 사용 예제를 보자.
부모 클래스와 기본 생성자 코드이다.
부모 클래스를 상속받는 자식클래스이다.
instanceof 연산자의 동작을 확인하기 위해 기존 검증 방법인 System.out.println으로 화면 출력 하는 방식이 아닌 Junit으로 검증해보겠다. 웹 서칭 하다 우연히 assertJ의 instanceOf() 사용하는 코드를 본 적이 있는데 생각이 나서 테스트 해보니 instanceof 연산자 동작을 확인 하는 api가 맞는 것 같아 assertJ의 instanceOf()를 사용하여 검증하였다.
또한, 더 자바, 애플리케이션을 테스트하는 다양한 방법 에서 배운 assertAll을 사용하여 모든 테스트가 중간에 실패하더라도 동작하도록 테스트 코드를 작성하였다.
child는 부모클래스와 자기 자신을 참조하고 있고, parent는 자기 자신을 참조하는 것을 확인 할 수 있다.
parent가 자식을 참조하는지 테스트 하는 코드에서 테스트가 실패하는 것을 확인 할 수 있으며, 해당 코드에서는 작성하지 않았지만 모든 Refrence 변수는 Object 타입을 상속하므로 instanceOf의 파라미터로 Object.class를 넘기면 테스트를 통과하며 동작 확인은 독자에게 맡긴다.
대입 연산자는 변수에 값을 대입할 때 사용하는 이항 연산자이며, 다른 연산자를 결합하여 만들 수 있으며 복합 대입 연산자가 있다. 복합 대입 연산자는 아래와 같다.
대입 연산자와 조합하여 사용하는 각각의 연산자 들은 위에서 설명 했으므로 간단한 사용법 정도만 작성하고자 한다.
public static void main(String[]args) {
int a = 3;
int b = 2;
a += b; // a = a + b;
System.out.println("a : " + a);
System.out.println("b : " + b);
}
출력 결과:
a : 5
b : 2
복합 대입 연산자가 사용된 코드인 "a += b" 는 a = a + b와 같은 코드이며, a + b를 수행한 값이 a에 할당 된다. 따라서 3 +2 의 결괏값인 5가 a에 할당되고, b는 원본 값을 유지한다.
자바에서 화살표(->)를 사용하여 람다 표현식(lambda expression)을 사용 할 수 있다. 람다 표현식의 예시는 다음과 같다.
public interace LambdaInterface {
public int sum(int num1, int num2);
}
Main
LambdaInterface lambda = (int num1, int num2) -> {return num1 + num2}; // 매개변수 -> 함수 로직 (+@ 리턴)
int result = lambda.sum(2,3); // result = 5
() -> assertThat(child).isInstanceOf(Object.class) // 유의사항 3번 참조
유의 사항
1. 매개변수의 타입을 추론할 수 있는 경우에는 타입을 생략할 수 있다.
2. 매개변수가 하나인 경우에는 괄호(())를 생략할 수 있다.
3. 함수의 몸체가 하나의 명령문만으로 이루어진 경우에는 중괄호({})를 생략할 수 있다.(이때 세미콜론(;)은 붙이지 않는다)
4. 함수의 몸체가 하나의 return 문으로만 이루어진 경우에는 중괄호({})를 생략할 수 없다.
5. return 문 대신 표현식을 사용할 수 있으며, 이 때 반환값은 표현식의 결괏값이 된다.. (이때 세미콜론(;)은 붙이지 않는다.)
3항 연산자는 자바에서 유일하게 피연산자를 3개나 가지는 조건 연산자이다.
3항 연산자의 문법은 조건식 ? "반환값1" : "반환값2";이며, 조건식이 참일 경우 반환값1을 반환하고, 거짓일 경우 반환값2를 반환한다.
int score = 90;
String grade = score > 80 ? "A" : "F";
score > 80 => 조건식
"A" => 반환값1
"F" => 반환값2
score가 90이므로 조건식을 만족한다. 따라서 반환값은 String 타입의 "A"이며, grade 변수는 "a"이다.
연산자 우선순위란 수식 내에서 여러 연산자가 함께 등장할 때, 어떤 연산자가 먼저 처리되는지 나타내는 순서이다. 초등학생 때 배운 사칙연산에서 곱셈, 나눗셈이 덧셈, 뺄셈보다 먼저 계산되는 것과 같은 것이라 보면 된다.
같은 우선순위를 가질 경우 왼쪽 -> 오른쪽 혹은 오른쪽 -> 왼쪽으로 결합 순서를 가진다.
연산자의 우선순위는 다음과 같다.
우선순위의 숫자가 작은 것이 우선순위가 높다.
switch 표현식은 2017년 12월 JEP 325에 제안이 되었으며 2018년 8월 출간 예정인 JDK 12에 출시 될 목표를 갖고 있었다.
새로운 switch 연산은 화살표(->) 라벨을 사용 할 수 있는데, 예를 들어 아래와 같이 사용이 가능하다.
static void howMany(int number) {
switch (number) {
case 1 -> System.out.println("1");
case 2 -> System.out.println("2");
default -> System.out.println("default");
}
}
homany(1);
homany(2);
homany(3);
출력 결과:
1
2
default
java12
String message = switch(errorCode) {
case 404:
break "Not found!";
default:
throw new IllegalArgumentException("Unexpected value: " + errorCode);
}
java13
String message = switch(errorCode) {
case 404:
yield "Not found!";
default:
throw new IllegalArgumentException("Unexpected value: " + errorCode);
}
자바 12에서는 break문을 사용하였지만, 자바 13에서는 break 대신 yield를 사용한다.
yield문을 쓸 경우 break를 섞어 쓰는 것이 불가능하다.
이것이 자바다(신용권 저, 한빛미디어)
연산자
instanceof
lambda
연산자 우선순위
switch 연산자
openjdk switch 연산자 설명