(백기선 스터디)
📌 목표
자바가 제공하는 다양한 연산자를 학습하세요.
💡 학습할 것
- 산술 연산자
- 비트 연산자
- 관계 연산자
- 논리 연산자
- instanceof
- assignment(=) operator
- 화살표(->) 연산자
- 3항 연산자
- 연산자 우선순위
- (optional) Java 13. switch 연산자
코드 올릴 때 여기를 통해서 올려볼 예정이다.
colorscripter.com/
💡 바이트코드 빠르게 보는 법(인텔리제이 : view-> show bytecode)을 이용한다. (터미널이랑은 조금 다른 것 같다)
1. 산술 연산자
산술 연산자를 배우기 전에 연산자와 피연산자의 개념에 대해서 알아보자.
- 연산자 : 연산을 수행하는 기호를 의미
- 피연산자 : 연산자를 이용해 연산되는 변수를 의미한다.
x + y라는 식에서 x와 y는 피연산자, +는 연산자를 의미한다.
산술 연산자에는 총 5가지가 있다.
우리가 익히 알고 있는 가감승제(+,-, *, /) 외에도 나머지를 구하는 연산자인 %를 포함해서 5가지이다.
가감승제는 우리가 기본적으로 알고 있으나 %는 익숙하지 않아 알아보도록 하자.
%는 어떤 수를 나누었을 때의 나머지를 계산해주는 연산자이다. 예) 5 % 2 = 1이다.
📢 산술 연산 시의 주의할 점이 몇 가지 있다.
1. 오버플로우 : 연산 후의 결과를 담을 수 있는 타입의 변수를 선언해야 된다. 그렇지 않으면 오버플로우가 발생할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public class Main {
public static void main(String[] args) {
int a = 3000000;
int b = 3000000;
int c = a * b;
System.out.println(c); // overflow 발생
}
}
|
cs |
결과 값은 변환이 되나 쓰레기 값이 나온다.
Overflow를 탐지하는 ArithmeticException 예외처리를 하면 안전하게 사용할 수 있다.
int로 선언했을 때 바이트코드는 아래와 같다.
![](https://blog.kakaocdn.net/dn/bTXQGw/btqOuIqiTiI/BuBdh4EavwJ9jKhludVgnk/img.png)
long으로 선언한다면
1
2
3
4
5
6
7
8
9
10
11
12
|
public class Main {
public static void main(String[] args) {
long a = 300000;
long b = 300000;
long c = a * b;
System.out.println(c);
}
}
|
cs |
바이트코드는 아래와 같다.
둘 차이를 보면
타입이 주석으로 보이는 거랑 long으로 표현된 바이트코드가 더 길어졌다(?) 정도밖에 없는 거 같다.(?)
2. 정확한 계산은 실수 타입(부동소수점)을 사용하지 않는 것이 좋다.
- 라이브 스터디 2회에서도 말했지만 float이나 double보다는 BigDecimal을 사용하자.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
import java.math.BigDecimal;
import java.math.BigInteger;
public class Main {
public static void main(String[] args) {
float number = 0f;
for (int i = 0; i < 10 ; i++) {
number += 0.1f;
}
System.out.println(number); // 1.0000001
BigDecimal number2 = BigDecimal.ZERO;
for (int i = 0; i < 10 ; i++) {
number2 = number2.add(BigDecimal.valueOf(0.1));
}
System.out.println(number2); // 1.0
}
}
|
cs |
float이나 double이 값이 정확하지 않는 이유는 이진 포맷의 가수를 사용하는 부동소수점 타입은 0.1을 정확히 표현할 수 없어 근사치로 처리하기 때문이다. ( 이것이 자바다.(신용권) )
3. 형변환
- 이 부분은 저번 시간에 파악했으므로 생략한다.
4. NaN과 Infinity
일반적으로 0으로 나누면 컴파일은 정상적으로 동작하지만 ArithmeticException이 발생한다.
5 / 0.0 -> Infinity
5 % 0.0 -> NaN
연산 결과가 Infinity인지 NaN인지 확인하려면 Double.isInfinite()와 Double.isNaN()을 이용하면 된다.
5. 문자열 연결 연산자 (+)
문자열을 연결할 때 +연산자를 사용한다.
String str = "Hello" + "study";
2. 비트 연산자
비트 연산자는 데이터를 비트(bit) 단위로 연산한다. 즉 0과 1로 이루어진 피연산자가 대상이 된다.
비트 연산자는 비트 논리 연산자와 비트 이동 연산자로 이루어져 있다.
비트 연산 시 주의할 점은 그 연산 괄가가 int타입이 된다는 것이다.
비트 논리연산자
- AND(논리곱, &) : 두 비트 모두 1일 경우에만 1 반환
- OR(논리합, |) : 두 비트 중 하나만 1이면 1 반환
- XOR(배타적 논리합, ^) : 두 비트 중 하나는 1, 다른 하나가 0일 때 1 반환
- NOT(논리 부정, ~) : 보수
비트 이동연산자
연산식 | 설명 | ||
a | << | b | 정수 a의 각 비트를 b만큼 왼쪽으로 이동(빈자리는 0으로 채워진다.) |
a | >> | b | 정수 a의 각 비트를 b만큼 오른쪽으로 이동(빈자리는 정수 a의 최상위 부호 비트와 같은 값으로 채워진다.) |
a | >>> | b | 정수 a의 각 비트를 b만큼 오른쪽 으로 이동(빈자리는 0으로 채워진다.) |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
public class Main {
public static void main(String[] args) {
byte a = 8;
byte b = 1;
int result; // 연산결과는 int타입으로 반환된다.
// 비트 논리연산
result = a & b;
System.out.println(result);
result = a | b;
System.out.println(result);
result = a ^ b;
System.out.println(result);
result = ~a;
System.out.println(result);
// 비트 이동연산
result = a >> b;
System.out.println(result);
result = a << b;
System.out.println(result);
result = a >>> b;
System.out.println(result);
}
}
|
cs |
3. 관계 연산자
관계 연산자는 비교 연산자라고도 하며 대소 비교 or 동등 비교를 해서 true/false를 반환한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public class Main {
public static void main(String[] args) {
int a = 1;
int b = 2;
int c = 1;
/*대소 비교*/
System.out.println( a > b); // false
System.out.println( a < b); // true
System.out.println( a >= b); // false
System.out.println( a <= b); // true
/*동등 비교*/
System.out.println(a == c); // true
System.out.println(a != c); // false
}
}
|
cs |
4. 논리 연산자
비트 논리 연산자와 거의 동일하다. 기호만 조금 다른 부분이 있으므로 주의하자.
피연산자들의 타입이 boolean이다.
- AND(논리곱, & 또는 &&)
- OR(논리합, | 또는 || )
- XOR(배타적 논리합, ^)
- NOT(논리 부정, !)
5. instanceof
참조 변수가 참조하고 있는 인스턴스 타입이 맞는지 아닌지 boolean으로 반환해 준다.
1
2
3
4
5
6
7
8
9
10
|
public class Rand {
public static void main(String[] args) {
String c = "5";
if(c instanceof String) { // true
System.out.println("String 타입입니다.");
}
}
}
|
Reference
improver.tistory.com/140
6. assignment(=) operator
대입 연산자, 할당 연산자라고 한다.
이 연산자를 통해 메모리에 값을 저장할 수 있다.
구분 | 연산자 | 설명 |
단순 대입 연산자 | = | 우측의 피연산자를 좌측 피연산자에 대입 |
복합 대입 연산자 | += | 우측 피연산자를 더한 후 좌측 피연산자에 대입 |
-= | 우측 피연산자를 뺀 후 좌측 피연산자에 대입 | |
*= | 우측 피연산자를 곱한 후 좌측 피연산자에 대입 | |
/= | 우측 피연산자를 나눈 후 좌측 피연산자에 대입 | |
%= | 우측 피연산자에 대한 나머지값을 좌측 피연산자대입 | |
&= | &연산 후 좌측 피연산자에 대입 | |
|= | |연산 후 좌측 피연산자에 대입 | |
^= | ^연산 후 좌측 피연산자에 대입 | |
<<= | <<연산 후 좌측 피연산자에 대입 | |
>>= | >>연산 후 좌측 피연산자에 대입 | |
>>>= | >>>연산 후 좌측 피연산자에 대입 |
7. 화살표(->) 연산자
화살표 연산자는 자바 8 이후에 도입된 람다식에서 도입된 연산자이다.
람다식은 "(매개변수) -> {실행코드}" 형태로 작성한다.
Runnable runnable = new Runnable() {
public void run() {...}
};
Runnable runnable = () -> {...};
예) 이름이 6자리가 넘으면 예외 발생한다를 ->연산자를 이용해 코딩을 한다면 이렇게 짤 수 있을 거 같다.
public List<String> Names() {
Scanner scanner = new Scanner(System.in);
String str = scanner.nextLine();
String[] name = str.replace(" ", "")
.split(",");
Arrays.stream(name).forEach(s -> {
if (s.length() > 6) {
throw new IllegalArgumentException("예외 발생");
}
});
return Arrays.asList(name);
}
8. 3항 연산자
삼항 연산자는 세 개의 피연산자가 필요하는 연산자이다.
형태
조건식 ? 값1or 연산식1 : 값1 or 연산식1
- 조건식이 true : 값1 or 연산식 1을 반환한다.
- 조건식이 false : 값2 or 연산식 2를 반환한다.
9. 연산자 우선 순위
아래의 순서로 연산자 우선순위를 가진다.
1. 최우선연산자 ( ., [], () )
2. 단항연산자 ( ++,--,!,~,+/- : 부정, bit변환>부호>증감)
3. 산술연산자 ( *,/,%,+,-,shift) < 시프트연산자 ( >>,<<,>>> ) >
4. 비교연산자 ( >,<,>=,<=,==,!= )
5. 비트연산자 ( &,|,,~ )
6. 논리연산자 (&& , || , !)
7. 삼항연산자 (조건식) ? :
8. 대입연산자 =,*=,/=,%=,+=,-=
Reference
programmers.co.kr/learn/courses/5/lessons/116
10. (optional) Java 13. switch 연산자
oracle13 doc참고
docs.oracle.com/en/java/javase/13/language/switch-expressions.html
Java Language Updates
Java SE 12 introduced switch expressions, which (like all expressions) evaluate to a single value, and can be used in statements. It also introduced "arrow case" labels that eliminate the need for break statements to prevent fall through. Based on develope
docs.oracle.com
여기도 좋은듯하다.
Java Switch Statement | Baeldung
A detailed tutorial about the Switch statement in Java and its evolution over time.
www.baeldung.com
아래와 같은 코드가 있다고 하자.
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);
이 코드는 Day의 Letter 수를 return 한다.
복잡한 조건을 분기 처리를 필터링해 variable numLetters에 값을 저장해서 반환하는 것보다.
Day의 길이를 바로 return 하는 것이 좀 더 좋아 보인다. 이것은 switch expression으로 해결 가능하다.
switch expression은 또한 break문을 사용할 필요 없이 밑으로 떨어지는 걸 방지할 수 있다.
switch expression을 통한 코드 재구현
Day day = Day.WEDNESDAY;
System.out.println(
switch (day) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> 7;
case THURSDAY, SATURDAY -> 8;
case WEDNESDAY -> 9;
default -> throw new IllegalStateException("Invalid day: " + day);
}
);
자바 런타임 시에 화살표 왼쪽에 매칭 되는 걸 찾아, 화살표 오른쪽 코드를 실행하며 밑으로 떨어지지 않는다.
자바 13에서 yield라는 표현도 생겼지만 시간 관계상 나중에 알아봐야 할 것 같다.
'Java' 카테고리의 다른 글
4주차 과제: 제어문 (0) | 2020.12.12 |
---|---|
3주차 과제: 연산자(feedback, 피드백) (0) | 2020.11.29 |
2주차 과제: 자바 데이터 타입, 변수 그리고 배열(피드백, feedback) (0) | 2020.11.22 |
2주차 과제: 자바 데이터 타입, 변수 그리고 배열 (0) | 2020.11.18 |
1주차 과제: JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가.(피드백 feedback) (0) | 2020.11.15 |