3주차 과제 (22.10월 17일 ~ 22일)
목표
자바가 제공하는 다양한 연산자를 학습하세요.
학습할 것
- 산술 연산자
- 비트 연산자
- 관계 연산자
- 논리 연산자
- instanceof
- assignment(=) operator
- 화살표(->) 연산자
- 3항 연산자
- 연산자 우선 순위
- (optional) Java 13. switch 연산자
산술 연산자(arithmetic operator)
산술 연산자는 모두 두 개의 피연산자를 가지는 이항 연산자이며, 피연산자들의 결합 방향은 왼쪽에서 오른쪽이다.
사칙 연산자
사칙 연산자 | 설명 |
---|---|
+ | 왼쪽 피연산자에서 오른쪽의 피연산자를 더해준다. |
- | 왼쪽 피연산자에서 오른쪽의 피연산자를 빼준다. |
* | 왼쪽 피연산자에서 오른쪽의 피연산자를 곱해준다. |
/ | 왼쪽 피연산자에서 오른쪽의 피연산자를 나눠준다. |
% | 왼쪽 피연산자를 오른쪽의 피연산자로 나눈 후, 그 나머지를 반환한다. |
public class main {
public static void main(String[] args) {
int num = 11;
int num2 = 2;
System.out.println(num + num2);
System.out.println(num - num2);
System.out.println(num * num2);
System.out.println(num / num2);
System.out.println(num % num2);
}
}
결과 :
13
9
22
5
1
나누기 연산(/
)
int num = 11
이고, int num2 = 2
이다.
원래 계산기로 돌려보면 결과는 5.5가 나와야한다.
테스트 코드를 이용해서 찾아보자
public class testMain {
@Test
void int나누기(){
main T = new main();
assertEquals(T.divide(11,2), 5);
}
}
테스트 실패
Expected :5.0
Actual :5.5
이유는 나누기 연산자의 두 피연산자의 타입이 int이다.
- int타입은 소수점을 저장하지 못한다. 그렇기 때문에 정수만 남기고 소수점은 버려진다.
피연산자 결과 유형, 숫자 승격
- 기본 숫자 유형 (7가지)
- byte
- short
- char
- int
- long
- float
- double
- 숫자 래퍼 유형
- Byte
- Character
- Short
- Integer
- Long
- Float
- Double
➡️피연산자 중 하나가 double(기본)
또는 Double(래퍼)
이면 결과 타입은 double
이다.
➡️피연산자 중 하나가 float(기본)
또는 Float(래퍼)
이면 결과 타입은 float
이다.
➡️피연산자 중 하나가 long
또는 Long(래퍼)
이면 결과 타입은 long
이다.
연산의 결과 유형은 산술 연산이 수행되는 방식과 피연산자가 처리되는 방식을 결정합니다.
- 결과 유형이
double
인 경우- 피연산자가
double
로 승격되고 연산 64비트(double precision binary) IEE 754 부동 소수점 산술을 사용하여 수행된다.
- 피연산자가
- 결과 유형이
float
인 경우- 피연산자가
float
로 승격되고 연산은 32비트(single precision binary) IEE754 부동 소수점 산술을 사용하여 수행된다.
- 피연산자가
- 결과 유형이
long
인 경우- 피연산자가
long
로 승격되고 연산은 64비트 부호있는 2의 보수 이진 정수 산술을 사용하여 연산이 수행된다.
- 피연산자가
- 결과 유형이
int
인 경우- 피연산자가
int
로 승격되고 연산은 32비트 부호있는 2의 보수 이진 정수 연산을 사용하여 수행한다.
- 피연산자가
Promotion(승격) 두 단계
- 피연산자 유형이 래퍼 유형인 경우, 피연산자 값은 해당 프리미티브 유형의 값에 unboxed 됩니다.
- 필요한 경우 기본 유형이 필수 유형으로 승격된다.
int
또는long
으로 정수를 승격하는 것은 손실이 없다.float
또는double
으로 승격하는 것은 손실이 없다.정수
를부동 소수점 값
으로 승격하면 정밀도가 손실될 수 있다. 변환은 IEE 768 “가장 가까운 반올림” 의미 체계를 사용하여 수행된다.
비트 연산자
비트 연산자는 논리 연산자와 비슷하지만, 비트(bit) 단위로 논리 연산을 할 때 사용하는 연산자이다.
비트 단위로 왼쪽이나 오른쪽으로 전체 비트를 이동하거나, 1의 보수를 만들 때도 사용된다.
비트 연산자 | 설명 | |
---|---|---|
& | 대응되는 비트가 모두 1이면 1을 반환함. (비트 AND 연산) | |
대응되는 비트 중에서 하나라도 1이면 1을 반환함. (비트 OR 연산) | ||
^ | 대응되는 비트가 서로 다르면 1을 반환함. (비트 XOR 연산) | |
~ | 비트를 1이면 0으로, 0이면 1로 반전시킴. (비트 NOT 연산, 1의 보수) | |
« | 명시된 수만큼 비트들을 전부 왼쪽으로 이동시킴. (left shift 연산) | |
» | 부호를 유지하면서 지정한 수만큼 비트를 전부 오른쪽으로 이동시킴. (right shift 연산) | |
»> | 지정한 수만큼 비트를 전부 오른쪽으로 이동시키며, 새로운 비트는 전부 0이 됨. |
비트 연산자의 연산결과
x | y | x | y | x & y | x ^ y |
---|---|---|---|---|---|
1 | 1 | 1 | 1 | 0 | |
1 | 0 | 1 | 0 | 1 | |
0 | 1 | 1 | 0 | 1 | |
0 | 0 | 0 | 0 | 0 |
| (OR 연산자)
- 피연산자 중 한쪽이 값이 1이면 1을 결과가 나온다. 그 외에는 0으로 나온다.
&(AND 연산자)
- 피연산자 양 쪽이 모두 1이어야만 1을 결과가 나온다. 그 외에는 0으로 나온다.
^(XOR 연산자)
- 피연산자의 값이 서로 다를 때만 1을 결과가 나온다. 같을 때는 0으로 나온다.
비트연산자 OR( | )는 주로 특정 비트의 값을 변경할 때 사용한다.
- 0xAB의 마지막 4bit를 ‘F’로 변경하는 방법을 보여준다.
비트연산자 AND( & )는 주로 특정 비트의 값을 뽑아낼 때 사용한다.
- 피연산자의 마지막 4bit가 어떤 값인지 알아내는데 사용된다.
비트연산자 XOR( ^ )는 간단한 암호화에 사용된다.
- 비트연산자 XOR( ^ )는 두 피연산자의 비트가 다를 때만 1이 된다. 그리고 같은 값으로 두고 XOR연산을 수행하면 원래의 값으로 돌아오는 특징이 있어서 간단한 암호화에 사용된다.
- 참고
- 2진수를 8자리로 표현하였지만, 사실은 int 타입(4 byte)간의 연산이라 32자리로 표현하는 것이 맞다.
public class main {
public static void main(String[] args) {
int num = 11;
int num2 = 2;
int x = 0xAB; //171
int y = 0xF; //15
System.out.printf("x = %#X \t\t\t\t%s%n", x, toBinaryString(x));
System.out.printf("y = %#X \t\t\t\t%s%n", y, toBinaryString(y));
System.out.printf("%#X | %#X = %#X \t\t%s%n", x, y, x | y, toBinaryString(x | y));
System.out.printf("%#X & %#X = %#X \t\t%s%n", x, y, x & y, toBinaryString(x & y));
System.out.printf("%#X ^ %#X = %#X \t\t%s%n", x, y, x ^ y, toBinaryString(x ^ y));
System.out.printf("%#X ^ %#X ^ %#X = %#X %s%n" , x, y, y, x ^ y ^ y, toBinaryString(x ^ y ^ y));
}
public static String toBinaryString(int x) { // 10진 정수를 2진수로 변환하는 메소드
String zero = "00000000000000000000000000000000";
String tmp = zero + Integer.toBinaryString(x);
return tmp.substring(tmp.length() - 32);
}
}
결과 :
x = 0XAB 00000000000000000000000010101011
y = 0XF 00000000000000000000000000001111
0XAB | 0XF = 0XAF 00000000000000000000000010101111
0XAB & 0XF = 0XB 00000000000000000000000000001011
0XAB ^ 0XF = 0XA4 00000000000000000000000010100100
0XAB ^ 0XF ^ 0XF = 0XAB 00000000000000000000000010101011
비트 전환 연산자 ~
- 음수를 2진수로 표현하는 방법
연산과정
- 10진수를 비트전환연산자(
‘~'
)를 한다. - 연산한 결과는
-11
이다. 이 값을10
의1의 보수
라고 한다. 1의 보수
에1
을 더한다.- 최종적으로
-10
이라는 결과가 나온다. -11은 10의‘1 의 보수’
가 맞다는 것을 확인했다.
쉬프트 연산자 ‘<< >>’
피 연산자의 각 자리(2진수로 표현했을 경우)를 ‘오른쪽(>>)’
또는 ‘왼쪽(<<)’
으로 이동(shift)한다고 해서 ‘쉬프트 연산자(shift operator)’
라고 이름 붙여졌다.
- « 연산자 동작 과정
연산자 동작 과정
➡️10진수가 음수일 때
0으로 채워지지않고 1로 채워지는 이유는 정수의 부호를 유지하기 위해서 오른쪽으로 이동 시 빈자리를 1로 채운다.
➡️10진수가 양수일 때
10진수가 양수일 때는 0으로 채워진다.
관계 연산자 (비교연산자)
비교 연산자는 두 피연산자를 비교하는 데 사용되는 연산자다.
연산 결과는 true
와 false
둘 중의 하나이다.
- 대소비교 연산자
비교연산자 | 연산결과 |
---|---|
> | 좌변 값이 크면, true아니면 false |
< | 좌변 값이 크면, true아니면 false |
≥ | 좌변 값이 크거나 같으면, true아니면 false |
≤ | 좌변 값이 크거나 같으면, true아니면 false |
- 등가비교 연산자
비교연산자 | 연산결과 |
---|---|
== | 두 값이 같으면, true 아니면 false |
≠ | 두 값이 다르면, true 아니면 false |
System.out.printf("10 == 10.0f \t %b%n", 10== 10.0f);
System.out.printf("'0'== 0 \t %b%n", '0' == 0);
System.out.printf("'A'== 65 \t %b%n", 'A' == 65);
System.out.printf("'A' > 'B' \t %b%n", 'A' > 'B');
System.out.printf("'A'+1 != 'B' \t %b%n", 'A'+1 != 'B');
결과 :
10 == 10.0f true
'0'== 0 false
'A'== 65 true
'A' > 'B' false
'A'+1 != 'B' false
논리 연산자
- 논리 연산자는 주어진 논리식을 판단하여, 참(true) 또는 거짓(false)을 결정하는 연산자이다.
논리 연산자 | 설명 | ||
---|---|---|---|
&& | 논리식이 모두 참이면 참을 반환함. (논리 AND 연산) | ||
논리식 중에서 하나라도 참이면 참을 반환함. (논리 OR 연산) | |||
! | 논리식의 결과가 참이면 거짓을, 거짓이면 참을 반환함. (논리 NOT 연산) |
A | B | A && B | A | B | !A | |
---|---|---|---|---|---|---|
true | true | true | true | false | ||
true | false | false | true | false | ||
false | true | false | true | true | ||
false | false | false | false | true |
instanceof
- 참조변수가 참조하고 있는 인스턴스의 실제 타입을 알기 위해 instanceof연산자를 사용한다.
- 형태
객체(object reference variable) instanceof 클래스(class/interface type)
class A {}
public class B extends A{
public static void main(String[] args) {
B b = new B();
System.out.println(b instanceof A);
System.out.println(b instanceof B);
}
}
결과 :
true
true
assignment(=) operator
대입 연산자 | 설명 | |
---|---|---|
= | 왼쪽의 피연산자에 오른쪽의 피연산자를 대입함. | |
+= | 왼쪽의 피연산자에 오른쪽의 피연산자를 더한 후, 그 결괏값을 왼쪽의 피연산자에 대입함. | |
-= | 왼쪽의 피연산자에서 오른쪽의 피연산자를 뺀 후, 그 결괏값을 왼쪽의 피연산자에 대입함. | |
*= | 왼쪽의 피연산자에 오른쪽의 피연산자를 곱한 후, 그 결괏값을 왼쪽의 피연산자에 대입함. | |
/= | 왼쪽의 피연산자를 오른쪽의 피연산자로 나눈 후, 그 결괏값을 왼쪽의 피연산자에 대입함. | |
%= | 왼쪽의 피연산자를 오른쪽의 피연산자로 나눈 후, 그 나머지를 왼쪽의 피연산자에 대입함. | |
&= | 왼쪽의 피연산자를 오른쪽의 피연산자와 비트 AND 연산한 후, 그 결괏값을 왼쪽의 피연산자에 대입함. | |
= | 왼쪽의 피연산자를 오른쪽의 피연산자와 비트 OR 연산한 후, 그 결괏값을 왼쪽의 피연산자에 대입함. | |
^= | 왼쪽의 피연산자를 오른쪽의 피연산자와 비트 XOR 연산한 후, 그 결괏값을 왼쪽의 피연산자에 대입함. | |
«= | 왼쪽의 피연산자를 오른쪽의 피연산자만큼 왼쪽 시프트한 후, 그 결괏값을 왼쪽의 피연산자에 대입함. | |
»= | 왼쪽의 피연산자를 오른쪽의 피연산자만큼 부호를 유지하며 오른쪽 시프트한 후, 그 결괏값을 왼쪽의 피연산자에 대입함. | |
»>= | 왼쪽의 피연산자를 오른쪽의 피연산자만큼 부호에 상관없이 오른쪽 시프트한 후, 그 결괏값을 왼쪽의 피연산자에 대입함. |
객체의 복사
- 얕은 복사
주소 값
을 복사한다는 의미
얕은 복사는 주소 값을 복사하기 때문에 참조하고 실제 값을 같다.
public class ObjectCopy {
private String name;
private int age;
public ObjectCopy(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
- 테스트를 통해서 알아보자.
public class ObjectCopyTest {
@Test
void shallowCopy(){
ObjectCopy original = new ObjectCopy("Dante", 3);
ObjectCopy copy = original; // 얕은 복사
System.out.println(original.getName()); //Dante
copy.setName("DT");
System.out.println(original.getName()); //DT
System.out.println(copy.getName()); // DT
}
}
- 결과
ObjectCopy original = new ObjectCopy("Dante", 3);
ObjectCopy copy = original; // 얕은 복사
original 인스턴스를 생성하면 stack 영역에 참조값이 저장되고 heap 영역에는 실제 값이 저장된다.
얕은 복사를 통해서 객체를 복사했기 때문에 copy 인스턴스는 original 인스턴스가 참조하고 있는 heap영역에 참조 값을 동일하게 참조하고 있다.
set() 메소드로 값을 변경하게 된다면, 동일한 주소를 참조하고 있기 때문에 같이 값이 바뀐다.
copy.setName("DT");
System.out.println(original.getName()); //DT
System.out.println(copy.getName()); // DT
- 그림으로 이해
copy의 객체의 name만 바꿔주었지만 original에 값도 변경되었다는 것을 알 수 있다.
이유는 동일한 주소를 참조하고 있기 때문에 original 객체에도 영향을 주었다.
- 깊은 복사
실제 값
을 복사한다는 의미
- Cloneable 인터페이스 구현
public class ObjectCopy implements Cloneable {
public String name;
public int age;
public ObjectCopy() {
}
public ObjectCopy(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public Object clone() throws CloneNotSupportedException {
return (ObjectCopy)super.clone();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
@Test
void shallowCopy2() throws CloneNotSupportedException{
ObjectCopy original = new ObjectCopy("Dante", 3);
ObjectCopy copy = (ObjectCopy)original.clone();
copy.setName("DT");
System.out.println(original.getName()); // Dante
System.out.println(copy.getName()); // DT
}
- 결과 : 통과
복사 생성자는 테스트부터 만들고 구현하겠다.
- 복사 생성자 테스트
@Test
void shallowCopy3(){
ObjectCopy original = new ObjectCopy("Dante", 3);
ObjectCopy copyConstructor = new ObjectCopy(original);
ObjectCopy copyFactory = ObjectCopy.copy(original);
copyConstructor.setName("DT");
copyFactory.setName("DT2");
System.out.println(original.getName());
System.out.println(original);
System.out.println(copyConstructor.getName());
System.out.println(copyConstructor);
System.out.println(copyFactory.getName());
System.out.println(copyFactory);
}
- 복사생성자
public class ObjectCopy {
private String name;
private int age;
// 복사 생성자
public ObjectCopy(ObjectCopy original){
this.name = original.name;
this.age = original.age;
}
//복사 팩터리
public static ObjectCopy copy(ObjectCopy original){
ObjectCopy copy = new ObjectCopy(original);
copy.name = original.name;
copy.age = original.age;
return copy;
}
public ObjectCopy(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
- 결과
- 그림으로 이해
화살표(->) 연산자
Java 8 부터는 람다 표현식을 사용할 수 있다.
- 메소드
int min(int x, int y) {
return x < y ? x : y;
}
- 람다 표현식
(x, y) -> x < y ? x : y;
자바 8 이전에는 클래스의 선언과 동시에 객체를 생성하므로, 단 하나의 객체만을 생성할 수 있는 클래스를 익명 클래스
라고한다.
따라서 자바에서 람다 표현식은 익명클래스랑 같다고 할 수 있다.
- 익명 클래스
new Object(){
int min(int x, int y){
return x < y ? x : y;
}
}
화살표 연산자
를 알기 위해서 빌드업을 좀 했다. 이제 해보자.
화살표 연산자(→)는 람다표현식 작성하는데 쓰인다.
- 형식
(매개변수목록) -> { 함수 바디}
- 람다 표현식을 사용할 때 유의 사항
- 매개 변수의 타입을 추론할 수 있는 경우에는 타입을 생략할 수 있다.
- 매개 변수가 하나인 경우 괄호()를 생략할 수 있다.
- 함수의 바디가 하나의 명령문으로만 이루어진 경우에는 중괄호({ })를 생략할 수 있다. (이때 세미콜론(;)은 붙이지 않는다.)
- 함수의 바디가 하나의 return 문으로만 이루어진 경우에는 중괄호({ })를 생략할 수 없다.
- return 문 대신 표현식을 사용할 수 있으며, 이때 반환값을 표현식의 결과값이 된다.(이때 세미콜론(;)은 붙이지 않늗다.)
public class Thread1 {
public static void main(String[] args) {
new Thread(new Runnable() {
public void run() {
System.out.println("전통적인 방식의 일회용 스레드 생성");
}
}).start();
new Thread(()->{
System.out.println("람다 표현식을 사용한 일회용 스레드 생성");
}).start();
}
}
3항 연산자
삼항 연산자는 자바에서 유일하게 피연산자를 세 개나 가지는 조건 연산자이다.
- 형식
연산자 우선순위
우선순위 | 연산자 | 설명 | 결합 방향 | ||
---|---|---|---|---|---|
1 | [] | 첨자 연산자 | 왼쪽에서 오른쪽으로 | ||
. | 멤버 연산자 | 왼쪽에서 오른쪽으로 | |||
2 | ++ | 후위 증가 연산자 | 왼쪽에서 오른쪽으로 | ||
– | 후위 감소 연산자 | 왼쪽에서 오른쪽으로 | |||
3 | ! | 논리 NOT 연산자 | 오른쪽에서 왼쪽으로 | ||
~ | 비트 NOT 연산자 | 오른쪽에서 왼쪽으로 | |||
+ | 양의 부호 (단항 연산자) | 오른쪽에서 왼쪽으로 | |||
- | 음의 부호 (단항 연산자) | 오른쪽에서 왼쪽으로 | |||
++ | 전위 증가 연산자 | 오른쪽에서 왼쪽으로 | |||
– | 전위 감소 연산자 | 오른쪽에서 왼쪽으로 | |||
(타입) | 타입 캐스트 연산자 | 오른쪽에서 왼쪽으로 | |||
4 | * | 곱셈 연산자 | 왼쪽에서 오른쪽으로 | ||
/ | 나눗셈 연산자 | 왼쪽에서 오른쪽으로 | |||
% | 나머지 연산자 | 왼쪽에서 오른쪽으로 | |||
5 | + | 덧셈 연산자 (이항 연산자) | 왼쪽에서 오른쪽으로 | ||
- | 뺄셈 연산자 (이항 연산자) | 왼쪽에서 오른쪽으로 | |||
6 | « | 비트 왼쪽 시프트 연산자 | 왼쪽에서 오른쪽으로 | ||
» | 부호 비트를 확장하면서 비트 오른쪽 시프트 | 왼쪽에서 오른쪽으로 | |||
»> | 부호 비트까지 모두 비트 오른쪽 시프트 | 왼쪽에서 오른쪽으로 | |||
7 | < | 관계 연산자(보다 작은) | 왼쪽에서 오른쪽으로 | ||
<= | 관계 연산자(보다 작거나 같은) | 왼쪽에서 오른쪽으로 | |||
> | 관계 연산자(보다 큰) | 왼쪽에서 오른쪽으로 | |||
>= | 관계 연산자(보다 크거나 같은) | 왼쪽에서 오른쪽으로 | |||
instanceof | 인스턴스의 실제 타입 반환 | 왼쪽에서 오른쪽으로 | |||
8 | == | 관계 연산자(와 같은) | 왼쪽에서 오른쪽으로 | ||
!= | 관계 연산자(와 같지 않은) | 왼쪽에서 오른쪽으로 | |||
9 | & | 비트 AND 연산자 | 왼쪽에서 오른쪽으로 | ||
10 | ^ | 비트 XOR 연산자 | 왼쪽에서 오른쪽으로 | ||
11 | 비트 OR 연산자 | 왼쪽에서 오른쪽으로 | |||
12 | && | 논리 AND 연산자 | 왼쪽에서 오른쪽으로 | ||
13 | 논리 OR 연산자 | 왼쪽에서 오른쪽으로 | |||
14 | ? : | 삼항 조건 연산자 | 오른쪽에서 왼쪽으로 | ||
15 | = | 대입 연산자 및 복합 대입 연산자 | |||
(=, +=, -=, *=, /=, %=, «=, »=, »>=, &=, ^=, | =) | 오른쪽에서 왼쪽으로 |
(optional) Java 13. switch 연산자
- 기존의 swich 형식
Java 12에서는 기존의 switch문을 개선했다. 그리고 Java 13에서는 switch의 새로운 기능을 추가시켰다.
switch의 단점에서 어떻게 개선되었는지 알아보자.
1️⃣첫 번째 : 누락된 break문으로 인한 Default Fall through
int itemCode = 1;
switch(itemCode){
case 1 :
System.out.println("노트북");
break;
case 2 :
System.out.println("데스크탑");
break;
case 3 :
System.out.println("핸드폰");
break;
defauolt
System.out.println("알 수 없는 장치");
}
결과 :
노트북
잘 된다.
하지만…
break
문이 없을면 어떻게 될까 ?
int itemCode = 1;
switch(itemCode){
case 1 :
System.out.println("노트북");
// break문 없다면 ?
case 2 :
System.out.println("데스크탑");
break;
}
결과 :
노트북
데스크탑
위와 같이 break문을 실수로 작성하지 못하였을 때의 case 2
로 넘어간다. 즉 다음 case로 넘어간다는 뜻이다.
개발할 때 치명적인 실수가 될 수 있는 요소이다.
2️⃣두 번째 문제점 : 케이스 당 여러 값이 지원되지 않는다.
- 여러 케이스 값에 대해 유사한 처리가 필요한 상황이 있을 수 있다. 기존의 switch는 fall through를 통해서 처리한다.
case 1:
case 2:
case 3:
System.out.println("전자 기기");
이제 업그레이드 된 스위치를 알아보자.
업그레이드 된 Switch
1️⃣케이스 당 여러 값을 지원한다.
- 케이스당 여러 값을 지정하여 코드 구조를 단순화하고 fall through를 사용할 필요가 없다.
switch(itemCode){
case 1, 2, 3 :
System.out.println("전자 기기");
case 4, 5 :
System.out.println("기계 장치");
break;
}
2️⃣ yield
는 값을 반환하는 데 사용된다.
- 새로운 키워드
yield
가 도입되었다. yield
후에 switch는 표현식을 자동으로 종료한다. 따라서 break 필요하지 않다.
int val = switch(code) {
case "x", "y" :
yield 1;
case "z", "w" :
yield 2;
}
3️⃣switch를 표현식으로 사용할 수 있다.
스위치를 표현식으로 사용할 수 있다. 그 이유는 이제 스위치가 입력을 기반으로 값을 반환할 수 있음을 의미한다.
그래서 구문이 조금 바뀌게 되었다.
스위치 블록은 세미콜론으로 구분해야한다.
String text = switch(itemCode){
case 1 :
yield "노트북";
case 2 :
yield "데스크탑";
case 3 :
yield "핸드폰";
default :
throw new IllegalArgumentException(itemCode + "알 수 없는 장치");
}
4️⃣반환 값/예외에 필요
- 가능한 모든 입력 값의 처리를 지정하려면 스위치 표현식이 필요하다.
- 가능한 모든 경우를 제공하거나 기본 사례를 지정한다.. 즉, 입력 값에 관계없이 스위치 표현식은 항상 일부 값을 반환하거나 명시적으로 예외를 throw해야 한다..
String text = switch(itemCode){
case 1 :
yield "노트북";
case 2 :
yield "데스크탑";
case 3 :
yield "핸드폰";
//default :
// throw new IllegalArgumentException(itemCode + "알 수 없는 장치");
}
그러면 가능한 모든 값이 스위치 표현식에 포함되지 않았다는 오류가 발생한다.
5️⃣화살표 전환
- switch에 새로운 구문 화살표(→) 구문이 도입되었다. switch와 함께 표현식 및 명령문으로 사용할 수 있다.
- 화살표(→)의 오른쪽에 올 수 있는 것들
- statement / expression(표현식)
- throw statement
- {} block
defuault fall through
를 피하기 위해 break문이 필요하지 않다.
➡️defuault fall through가 필요하지 않는 경우 화살표(→)를 사용한다.
switch(itemCode){
case 1 -> System.out.println("노트북");
case 2 -> System.out.println("데스크탑");
case 3, 4 -> System.out.println("휴대폰");
}
위 코드처럼 케이스 당 여러 값을 사용할 수 있다.
6️⃣범위(scope)
- 기존의 switch에서 선언된 변수는 switch문의 끝까지 존재한다. 변수가 케이스 수준 범위를 가지도록 하려면 Java13의 향상된 switch에 의해 도입된
{ }
를 사용할 수 있다.
switch(errorCode){
case 101: {
//num 변수는 { } 안에서만 존재한다.
int num = 200;
break;
}
case 300: {
// case 101에 있는 num이랑 다른 num이다. { }범위 안에서만 사용하는 변수
int num = 200;
break;
}
}
3주차 회고
끝났다….엄청 오래걸렸다.. 짧게 걸릴 줄 알았던 연산자
파트는 생각했던 것과 다르게 배우고 정리해야할 것이 너무 많았다.
연산자 하나로도 얼마나 많은걸 배울 수 있는지 알 수 있는 경험이 되었다.
java13 switch 부분은 피드백 받으면서 더 정확히 내용을 정리해야겠다.
참고 :
https://riptutorial.com/java/example/678/the-arithmetic-operators–plus————-
- http://www.tcpschool.com/java/java_operator_bitwise
자바의 정석
- https://www.geeksforgeeks.org/enhancements-for-switch-statement-in-java-13/?ref=gcse