[자바 스터디 3주차] 연산자

github.com/whiteship/live-study/issues/3

 

3주차 과제: 연산자 · Issue #3 · whiteship/live-study

목표 자바가 제공하는 다양한 연산자를 학습하세요. 학습할 것 산술 연산자 비트 연산자 관계 연산자 논리 연산자 instanceof assignment(=) operator 화살표(->) 연산자 3항 연산자 연산자 우선 순위 (option

github.com

목표

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

학습할 것

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

 

용어정리

연산(operations) : 프로그램에서 데이터를 처리하여 결과를 산출하는 것

연산자(operator) : 연산에서 사용되는 표시나 기호

피연산자(operand) : 연산의 대상이 되는 데이터

연산식(expression) : 연산자와 피연산자로 연산의 과정을 기술한 것

산술 연산자

산술연산은 더하기(+), 빼기(-), 곱하기(*), 나누기(/)와 나머지 연산(%)이 있다. 나머지 연산을 제외한 사칙연산은 자주 사용해서 어렵지 않을 것이고  몇가지 주의사항만 지키면 된다.

 

사칙연산자

사칙연산의 우선순위는 (곱셉,나눗셈) > (덧셈,뺄셈)이다.  

    public static void main(String[] args) {
        int a = 10;
        int b = 4;
        System.out.printf("%d + %d = %d%n", a, b, a + b);
        System.out.printf("%d - %d = %d%n", a, b, a - b);
        System.out.printf("%d * %d = %d%n", a, b, a * b);
        System.out.printf("%d / %d = %d%n", a, b, a / b); //(1)
        System.out.printf("%d / %f = %f%n", a, (float)b, a / (float)b); //(1)
    }

여기서 눈여겨 볼것은 (1)번이다. 나누기 연산자 사용시 두 피연산자가 모두 int타입인 경우, 연산결과 역시 int가 나온다. 실제 결과는 2.5지만 int는 정수형이기 때문에 소수점을 저장하지 못한다. 특히, 반올림이 아닌 버림이 된다는 것에 주의하자.

 

올바른 연산결과 2.5를 얻기 위해선 한 쪽을 실수형으로 변환해야 한다. 그럼앞서 배운 타입 프로모션(자동형변환)에 의해 한쪽도 실수형으로 변환되어 실수형의 값을 얻을 수 있다. 범위가 넓은쪽으로 일치되기 때문에 int가 float으로 변환된다.

int  float     float   float    float
10 / 4.0f  ->  10.0f / 4.0f  -> 2.5f

 

피연산자가 정수형인 경우, 나누는 수로 0을 사용할 수 없다. 0으로 나누면, 컴파일은 정상적으로 되지만, 실행 시 오류가 발생한다. 밑의 예시는 컴파일은 되지만 실행시 에러가 발생한다.

System.out.println(3 / 0);   //실행하면, 오류(Arithmeticexception) 발생!!!
System.out.println(3 / 0.0); //Infinity(무한대)가 출력
System.out.println(100 % 0); //NaN(Not a Number) 출력

 

    public static void main(String[] args) {
        byte a = 10;
        byte b = 30;
        byte c = (byte)(a * b); //(1)
        System.out.println(c);
    }

위 코드의 1번에서 a * b = 300 이지만 byte형(~128 ~ 127)으로 변환하여 저장하면 데이터의 손실이 발생하므로 값이 바뀌어 44가 byte형 변수 c에 저장된다. 

 

 

https://catsbi.oopy.io/c750e102-a202-4b70-b679-71c2fb24188a

byte -> int형 변환은 작은 타입(2진수 8자리)에서 큰 타입(2진수 32자리)으로 변환하는 것이기 때문에 자료 손실이 일어나지 않는다. 원래 8자리는 그대로 유지하고 나머지는 모두 0으로 채우면 된다. 만약 음수인 경우 0대신 1로 채운다.

 

그러나 int형 -> byte형으로 변환하는 경우 두가의 경우의 수가 있다.

 

(공통) 상위 24자리를 잘라낸다

(1) int형 타입이지만 byte형 범위에 포함되는 수일경우

  •  원래 값 유지가 가능하다.

(2) int형 타입지만 byte형 범위에 포함되지 않을 경우

  • 원래의 값이 유지되지 않고 byte형의 범위 중 한 값을 가지게 된다.


    public static void main(String[] args) {
        int a = 1_000_000; //1,000,000 1백만
        int b = 2_000_000; //2.000,000 2백만
        
        long c = a * b;    //a * b = 2,000,000,000,000 ?
    }

a * b의 값이 long 타입의 범위에 해당하여 정상적인 값이 나오길 기대하지만 전혀 다른 값이 나온다.

 

그 이유는, int 타입 * int 타입의 결과가 이미 int타입으로 오버플로우가 발생했기 때문이다.

올바른 결과를 얻기 위해선 a와 b 둘중 하나를 long타입으로 명시적 캐스팅을 해줘야 한다.

    public static void main(String[] args) {
        int a = 1_000_000; //1,000,000 1백만
        int b = 2_000_000; //2.000,000 2백만

        long c = (long)a * b; // 명시적 캐스팅
    }

https://delirussum.tistory.com/91

사칙연산의 피연산자로 숫자뿐만 아니라 문자도 가능하다. 문자도 실제로 해당 문자의 유니코드로 바뀌어 저장되므로 문자간의 사칙연산은 정수간의 연산과 동일하다.

'2' - '0' -> 50  - 48 -> 2
'd' - 'a' -> 100 - 97 -> 3

char c1 = 'a'; //c1에는 'a'의 코드값인 97이 저장
        
int i = c1 + 1; // 'a' + 1 -> 97 + 1 -> 9
char c3 = (char)(c1 + 1); //(1)
c1++; //(2)

(1)번의 c1 + 1에서 c1이 char형이므로 int형으로 변환한 후 덧셈연산을 수행하게 된다. c1에 저장되어 있는 코드값은 97이기 때문에 97 + 1 -> 98이 된다. 결과값은 결국 int형 변수이기 때문에 이를 char형 변수에 담기 위해 char형으로 형변환을 하였다.

 

(2)번은 c1에 저장되어 있는 값을 1 증가시키므로 98이 저장되며 문자는 'b'가 된다.


char c1 = 'a';
//char c2 = c1 + 1; //(1) 컴파일 에러
char c2 = 'a' + 1; //(2) 컴파일 에러 X

 

이항 연산자는 int보다 작은 타입의 피연산자를 int로 자동 형변환해준다. 그래서 (1)번은 c1 + 1 을 char로 형변환을 해주지 않았기 때문에 컴파일 에러가 발생하는것이 맞다. 하지만 (2)번이 컴파일 에러가 나지 않고 정상적으로 실행 되는 이유는 'a' + 1이 리터럴간의 연산이기 때문이다. 

상수 또는 리터럴 간의 연산은 실행과정동안 변하는 값이 아니기 때문에 , 컴파일 시에 컴파일러가 계산한 결과로 대체한다.

 


나머지 연산자 %

나머지 연산자는 왼쪽의 피연산자를 오른쪽의 피연산자로 나누고 남은 나머지 값을 결과로 반환하는 연산자이다. 나눗셈처럼 나누는 수로 0을 사용할 수 없다.

System.out.println(-10%8);  //-2
System.out.println(10%-8);  // 2
System.out.println(-10%-8); //-2

나머지 연산자(%)는 나누는 수로 음수도 허용한다. 그러나 부호는 무시되므로 결과는 음수의 절대값으로 나눈 나머지와 결과가 같다. 쉽게 생각하면 모든 피연산자의 마이너스를 무시하고 나온 결과값에 왼쪽 피연산자의 부호를 붙이면 된다.

 

비트 연산자

비트연산시 진리표를 작성하기도 하는데 

진리표란 모든 입출력 경우에 대한 참거짓 결과를 논리값으로 표현한 표이다.

 

비트 연산자는 데이터를 비트 단위로 연산하므로 0과 1로 표현이 가능한 정수 타입만 비트연산이 가능하다.

public class Main {
    public static void main(String[] args){
        System.out.println("15 & 25 = " + (15 & 25));
        System.out.println("15 Binary = " +    String.format("%08d", Integer.parseInt(Integer.toBinaryString(15).toString())));
        System.out.println("25 Binary = " +    String.format("%08d", Integer.parseInt(Integer.toBinaryString(25).toString())));
        System.out.println("15 & 25 Binary = " +    String.format("%08d", Integer.parseInt(Integer.toBinaryString(15 & 25).toString())));
        System.out.println();

        System.out.println("15 | 25 = " + (15 | 25));
        System.out.println("15 Binary = " +    String.format("%08d", Integer.parseInt(Integer.toBinaryString(15).toString())));
        System.out.println("25 Binary = " +    String.format("%08d", Integer.parseInt(Integer.toBinaryString(25).toString())));
        System.out.println("15 | 25 Binary = " +    String.format("%08d", Integer.parseInt(Integer.toBinaryString(15 | 25).toString())));
        System.out.println();

        System.out.println("15 ^ 25 = " + (15 ^ 25));
        System.out.println("15 Binary = " +    String.format("%08d", Integer.parseInt(Integer.toBinaryString(15).toString())));
        System.out.println("25 Binary = " +    String.format("%08d", Integer.parseInt(Integer.toBinaryString(25).toString())));
        System.out.println("15 ^ 25 Binary = " +    String.format("%08d", Integer.parseInt(Integer.toBinaryString(15 ^ 25).toString())));
        System.out.println();

        System.out.println("~25 = " + (~25));
        System.out.println("25 Binary = " +    String.format("%08d", Integer.parseInt(Integer.toBinaryString(25).toString())));
        System.out.println("~25 Binary = " +    Integer.toBinaryString(~25));

        System.out.println();
        System.out.println();

        System.out.println("2 << 3 = " + (2<<3));
        System.out.println("2 Binary = " +    String.format("%08d", Integer.parseInt(Integer.toBinaryString(2).toString())));
        System.out.println("2 << 3 Binary = " +    String.format("%08d", Integer.parseInt(Integer.toBinaryString(2 << 3).toString())));
        System.out.println();

        System.out.println("16 >> 3 = " + (16 >> 3));
        System.out.println("16 Binary = " +    String.format("%08d", Integer.parseInt(Integer.toBinaryString(16).toString())));
        System.out.println("16 >> 3 Binary = " +    String.format("%08d", Integer.parseInt(Integer.toBinaryString(16 >> 3).toString())));
        System.out.println();

        System.out.println("-16 >> 3 = " + (-16 >> 3));
        System.out.println("-16 Binary = " +    Integer.toBinaryString(-16).toString());
        System.out.println("-16 >> 3 Binary = " +    Integer.toBinaryString(-16 >> 3).toString());
        System.out.println();

        System.out.println("-16 >>> 3 = " + (-16 >>> 3));
        System.out.println("-16 Binary = " +    Integer.toBinaryString(-16).toString());
        System.out.println("-16 >>> 3 Binary = " +    Integer.toBinaryString(-16 >>> 3).toString());
    }
}

 

결과

15 & 25 = 9
15 Binary = 00001111
25 Binary = 00011001
15 & 25 Binary = 00001001

15 | 25 = 31
15 Binary = 00001111
25 Binary = 00011001
15 | 25 Binary = 00011111

15 ^ 25 = 22
15 Binary = 00001111
25 Binary = 00011001
15 ^ 25 Binary = 00010110

~25 = -26
25 Binary = 00011001
~25 Binary = 11111111111111111111111111100110


2 << 3 = 16
2 Binary = 00000010
2 << 3 Binary = 00010000

16 >> 3 = 2
16 Binary = 00010000
16 >> 3 Binary = 00000010

-16 >> 3 = -2
-16 Binary = 11111111111111111111111111110000
-16 >> 3 Binary = 11111111111111111111111111111110

-16 >>> 3 = 536870910
-16 Binary = 11111111111111111111111111110000
-16 >>> 3 Binary = 11111111111111111111111111110

BUILD SUCCESSFUL in 4s
3 actionable tasks: 2 executed, 1 up-to-date
오전 10:22:44: Task execution finished 'Main.main()'.

 

2진수 n자리를 왼쪽으로 이동하면 피연산자를 2^n으로 곱한 결과를, 오른쪽으로 이동하면 피연산자를 2^n으로 나눈 결과를 얻는다.

x<<n은 x * 2^n의 결과와 같다.
x>>n은 x / 2^n의 결과와 같다.

 

 

 

※추가 공부

비트 전환 연산자인 '~'에 의해 비트 전환이 되고 나면, 부호있는 타입의 피 연산자는 부호가 반대로 변경된다. 즉, 피연산자의 '1의 보수'를 얻을 수 있다. 그래서 비트 전환 연산자를 1의 보수 연산자라고도 한다.

비트전환 연산자는 피연산자의 타입이 int보다 작으면 int로 자동 형변환 후에 연산을 시행한다.

 

https://yadon079.github.io/2020/java%20study%20halle/week-03

1의 보수와 2의보수

 

컴퓨터는 N개의 비트를 이용해 2^N개의 정수만 표현한다. 그럼 보수란 무엇일까?

보수란, '두 수의 합이 진법의 밑수가 되게 하는 수'를 의미한다.

Ex)

10진수 410의 보수는 6

4 + 6 = 10

10진수 210의 보수는 8

2 + 8 = 10

 

보수는 컴퓨터에서 음의 정수를 표현하기 위해 고안된 것이다. 컴퓨터 내부에서는 사칙연산 수행 시 덧셈을 담당하는 가산기(Adder)만 이용하기 때문에 뺄셈은 덧셈으로 형식을 변환하여 계산해야 한다.

컴퓨터 내부에서는 A - B를 계산할 때 B의 보수(-B)를 구한 다음 A + (-B)로 계산한다.

 

1의 보수 : 각 자릿수의 값이 모두 1인 수에서 주어진 2진수를 빼면 1의 보수를 얻는다.( 1->0, 0->1로 변환하는것)

Ex)

2진수 1010의 1의 보수

 1111

-1010

 -----

 0101

 

2의 보수 : 1의 보수에 1을 더한 값

Ex)

2진수 1010의 2의 보수

1010 -> 0101 변환

 0101

+    1

 -----

 0110

 

 

 

※ 보너스

int start = 0;
int end = 0;

int mid = (start + end) / 2;
=> 문제있는 코드
=> (start + end)부분에 오버플로우 발생할 수도 있음
=> start와 end의 합산이 int의 제한범위인 21억보다 높을 떄 오버플로우 발생

방법1. 쉬운방법(이거사용추천)
int mid = start + (end - start) / 2;
//낮은값이 start 
//코딩테스트때 활용 추천
//이렇게 사용하는 방법에 대해 설명할줄 알아야 함

방법2. 간지용 방법
int mid = (start + end) >>> 1;
//비트를 오른쪽을 옮기면 2로 나누는거니까 나누기 2할려면 1칸만 옮기면 됨
//>>>는 빈칸을 0으로 채우기 때문에 양수에서만 되는 방법(인덱스의 중간값 구할때)

 

관계 연산자

관계 연산자는 좌항과 우항의 피연산자의 값을 비교하여 결과를 true 또는 false로 나타내는 연산자라고 한다.

 

 

 

논리 연산자

※ &&와 | | 사용시 단락 회로 평가가 이루어진다.

단락회로평가는 모든 피연산자와 연산자를 평가하지 않고서도 식의 결과가 결정되는 것을 의미한다.

int a = -2;
int b = 9;
(a>=0) && (b<10) //1. false && 계산X => false
(a<=0) || (b>5) //2. true || 계산X => true 

 

1.

&&는 좌항과 우항 둘다 true이여야만 true가 나온다.

a>=0이 false이기 때문에 우항을 계산하지 않아도 무조껀 false결과값이 나오기 때문에

우항을 계산하지 않는다.

 

2.

||는 한쪽만 true여도 반드시 true가 나온다.

a<=0이 true 이기 때문에 우항을 계산하지 않아도 무조껀 true결과값이 나오기 때문에

우항을 계산하지 않는다.

 

instanceof

instanceof란 좌항과 우항의 참조변수 타입이 같은지 확인하는 연산자이다.

좌측에는 참조변수가, 우측에는 타입(클래스명)이 피연산자로 위치한다.

부모-자식관계에 따라 참조변수가 검사한 타입으로 형변환이 가능하면 true를, 불가능하면 false를 반환한다. 주로, 상속관계에서 부모객체인지 자식객체인지 확인하는데 사용한다.

 

조상타입의 참조변수로 자손타입의 인스턴스를 참조할 수 있기 때문에, 참조변수의 타입과 인스턴스의 타입이 항상 일치하지는 않는다. 조상타입의 참조변수로는 실제 인스턴스의 멤버들을 모두 사용할 수 없기 때문에, 실제 인스턴스와 같은 타입의 참조변수로 형변환을 해야만 인스턴스의 모든 멤버들을 사용할 수 있다.

 

public class InstanceofExam{
  public static void main(String[] args){
  	A a = new A();
    B b = new B();
    
    //객체 a는 자기 자신의 객체이기 때문에 형변환 가능
    System.out.println(a instanceof A); //true
    
    //객체 b는 자식객체이기 때문에 A로 형변환 가능
    System.out.println(b instanceof A); //true
    
    //객체 a는 B의 부모객체이기 때문에 형변환 불가능
    System.out.println(a instanceof B); //true
    
    //객체 b는 자기 자신의 객체이기 때문에 형변환 가능
    System.out.println(b instanceof B); //true
  }

}

class A{
}

class B extends A{
}

 

assignment(=) operator

대입 연산자는 변수와 같은 저장공간에 값 또는 수식의 연산결과를 저장하는데 사용된다. 이 연산자는 오른쪽 피연산자의 값(식이라면 평가값)을 왼쪽 피연산자에 저장한다. 그리고 저장된 값을 연산결과로 반환한다.

 

대입 연산자는 연산자들 중에서 가장 낮은 우선순위를 가지고 있기 때문에 식에서 가장 마지막에 수행된다. 또한 연산 진행 방향이 오른쪽에서 왼쪽이기 때문에 x = y = 3;을 시행하면 y = 3이 먼저 수행되고 x = y가 수행된다.

 

lvalue와 rvalue

대입 연산자의 왼쪽 피연산자를 'lvale(left value)'라 하고, 오른쪽 피연산자를 'rvalue(right value)'라고 한다.

대입 연산자의 rvalue는 변수 뿐만 아니라 식이나 상수 등이 모두 가능한 반면에 lvalue는 반드시 변수처럼 값을 변경할 수 있는 것이어야 한다.

int i = 0;
1 = i + 1; //에러. lvalue가 값을 저장할 수 있는 공간이 아니다.
i + 1 = i; //에러. lvalue의 연산결과가 리터럴이다.(i + 1 -> 0 + 1 -> 1)

final int MAX = 1;
MAX = 10; //에러. 상수(MAX)에 새로운 값을 저장할 수 없다.

변수 앞에 키워드 final을 붙이면 상수가 된다. 상수는 반드시 선언과 동시에 값을 저장해야하며, 한 번 저장된 값을 바꿀 수 없다.

 

 

복합대입연산자

int x = 3;
int y = 9;

x += 4; // x = x + 4
y -= 5; // y = y - 5

System.out.println("x값 : " + x);
System.out.println("y값 : " + y);

복합대입연산자를 이용해서 코드의 가독성을 높힐 수 있다.

+=, -= 말고도 *=, /=, %/, &/, |/, ^/ 가 있다.

 

전위연산자, 후위연산자

int x = 3;
int y = 6;
int z = (++x) + (y--);

System.out.println("x값 : " + x); //4
System.out.println("y값 : " + y); //5
System.out.println("z값 : " + z); //10

x는 전위연산자로 3에서 4으로 증가됬고, y는 x와 더하는 작업을 마친뒤 감소된다.

 

화살표(->) 연산자

화살표 연산자는 Java1.8에서 람다식이 나오면서 등장하였다. 람다식의 도잎으로 인해 자바는 객체지향언어인 동시에 함수형 언어가 되었다.

 

람다식은 메서드를 하나의 '식(expression)'으로 표현한 것이다. 함수를 간략하면서도 명확한 식으로 표현할 수 있게 해준다.

메서드를 람다식으로 표현하면 메서드의 이름과 반환 값이 없어지므로, 람다식을 '익명 함수'라고도 한다.

 

int[] arr = new int[5];
Arrays.setAll(arr, (i) -> (int)(Math.random() * %) + 1);

위 코드에서 () -> (int)(Math.random() * 5) + 1이 람다식이다. 이 람다식을 메서드로 표현하면 다음과 같다.

int method() {
	return (int)(Math.random() * 5) + 1;
}

모든 메서드는 클래스에 포함되어야 하므로 클래스를 생성하고, 객체도 생성해야만 메서드를 호출할 수 있다. 그러나 람다식은 이 모든 과정없이 람다식 자체만으로도 메서드의 역할을 대신할 수 있다.

람다식은 메서드의 매개변수로 전달되어지는 것이 가능하고, 메서드의 결과로 반환될 수도 있따. 람다식으로 인해 메서드를 변수처럼 다루는 것이 가능해진 것이다.

 

 

 

람다식 사용법

 

반환타입 메서드이름(매개변수 선언) {
	실행문
}

위와 같은 형태에서 아래와 같이 바뀌는 것이다.

(매개변수 선언) -> { 실행문 }

 

 

(매개변수 선언)은 오른쪽 중괄호 { } 블럭을 실행하기 위해 필요한 값을 제공한다. 

즉, 여기서 -> 기호는 매개변수를 이용해서 중괄호{ } 내부를 실행한다는 의미이다.

 

예를 들어 max메소드가 있으면

int max(int a, int b){
	return a > b ? a : b;
}

람다식으로 아래와같이 바뀐다.

(int a, int b) -> {
	return a > b ? a : b
}

반환값이 있는 메서드의 경우, return문 대신 '식(expression)'으로 대신 할 수 있다. 식의 연산결과가 자동적으로 반환값이 되는데 이 때 '문장(statement)'이 아닌 '식'이므로 끝에 ;를 붙이지 않는다.

(int a, int b) -> a > b ? a : b

람다식에 선언된 매개변수의 타입은 추론이 가능한 경우 생략할 수 있는데, 두 매개변수 중 어느 하나의 타입만 생략하는 것은 허용되지 않는다. 대부분의 경우 생략이 가능하고 람다식에 반환타입이 없는 이유는 항상 추론이 가능하기 때문이다.

(a,b) -> a > b ? a : b

선언된 매개변수가 하나뿐인 경우에는 괄호()를 생략할 수 있다. 하지만 매개변수의 타입이 있으면 생략할 수 없다.

a     -> a * a // OK.
int a -> a * a //에러.

또한 괄호{}안의 문장이 하나인 경우 괄호{}를 생략할 수 있다. 이 때 문장의 끝에 ;를 붙이지 않아야 한다. 그러나 괄호{}안의 문장이 return문일 경우 생략할 수 없다.

(String number, int i) -> {
	System.out.println(number + ":" + i);
}

//괄호 { } 생략
(String nuber, int i) -> System.out.println(number + ":" + i) //OK.

int roll(){
	return (int)(Math.random() * 2);
}
//괄호 { } 생략
() -> return (int)(Math.random() * 2) //에러. return문이기 때문에 생략 불가.

 

예제

@FunctionalInterface
interface Say{
	int someting(int a, int b);
}

class Person{
	public void hi(Say line){
    	int number = line.someting(3,4);
    }
}

@FunctionalInterface 어노테이션을 선언하면 인터페이스에는 추상 메소드 하나만 정의할 수 있다.

 

람다식 X

Person rin = new Person();
rin.hi(new Say() {
	public int someting(int a, int b) {
    	return 7;
    }
});

 

람다식 O

Person rin = new Person();
rin.hi((a,b) -> {
	return 7;
});

@FunctionalInterface에 의해 메소드가 하나만 정의되었기 때문에 something()이라는 메소드사용을 알기 때문에 생략이 가능하다.

 

3항 연산자

if(){
	...
}else if(){
	...
}

삼항 연산자를 모를 때 if - else if문을 많이 사용하였다. 하지만 삼항연산자를 쓰면 코드수를 확실히 줄일 수 있다.

 

삼항연산자는 (조건문) ? 참 : 거짓의 문법을 가진다. 

 

int a;
if(5<4) {
  a = 50;
}else {
  a = 40;
}
System.out.println(a); //결과 = 40

//삼항연산자
int b = (5 < 4) ? 50 : 40;
System.out.println(b); //결과 = 40

if - else문을 사용할시와 삼항연산자를 사용할시 라인수를 비교하면 확실히 줄은 것을 알 수 있다.

그러나 코드의 라인수를 줄였을뿐 컴파일 속도에는 영향이 없다. 또한, 삼항연산자를 중복처리하여 사용할 경우 가독성이 좋지 않을 수 있으므로 지양하고있다.

 

(조건1) ? (조건2 ? 조건2-참 : 조건2-거짓) : 조건1-거짓;

=> 두개만 중첩해서 써도 가독성이 떨어지는 것을 알 수 있다.

 

연산자 우선 순위

 

(optional) Java 13. switch 연산자

Java12에서 Switch문이 확장되었다.

 

기존 switch문

        String time;
        switch(weekday){
            case MONDAY:
            case FRIDAY:
                time = "";
                break;
            case TUESDAY:
            case THURSDAY:
                time = "";
                break;
            default:
                time = "휴일"
        }

 

확장된 switch문

1.복수의 case

        String time;
        switch(weekday){
            case MONDAY, FRIDAY:
                time = "";
                break;
            case TUESDAY, THURSDAY:
                time = "";
                break;
            default:
                time = "휴일"
        }

 

2.지시자(->) 문법

        String time;

        switch(weekday){
            case MONDAY, FRIDAY -> time = "";
            case TUESDAY, THURSDAY -> time = "";
            default -> time = "휴일";
        }

 

3.블럭 사용

        String time;

        switch(weekday){
            case MONDAY, FRIDAY -> {
                var endTime = getEndTime();
                time = "";
            }
            case TUESDAY, THURSDAY -> time = "";
            default -> time = "휴일";
        }

 

4.switch 식

지시자 문법에 블록을 사용하지 않는 경우나 지시자 문법에 블록을 사용한 경우 break로 값을 반환한다.

        String time = switch(weekday){
            case MONDAY, FRIDAY -> {
                var endTime = getEndTime();
                break "";
            }
            case TUESDAY, THURSDAY -> "";
            default -> "휴일";
        }

 

Java13에서는 yield키워드를 이용하여 산출값을 반환할수 있다.

public class JEP354
	public static void main(String[] args){
    	System.out.println(getValueViaYield("a")); //결과 : 1
        System.out.println(getValueViaYield("c")); //결과 : 2
        System.out.println(getValueViaYield("e")); //결과 : 3
        System.out.println(getValueViaYield("z")); //결과 : -1
    }
    
    private static int getValueViaYield(String mode){
    	int result = switch(mode) {
        	case "a", "b":
            	yield 1;
            case "c":
            	yield 2;
            case "d", "e", "f":
                yield3;
            default
                yield -1;
        };
        return result;
    }
    
    

※ 기존에 존재하는 switch문은 그대로 있고 여기서 switch 연산자가 추가된거다. 헷갈리지 말자

 

라이브 피드백

1. 12/5일 휴방, 12/12 방송 시작

 

2. 댓글 단기준은 흠칫 놀랜 사람들 한테만 담

+ 가끔 성의없는글

 

3. 적어도 thumb이외 하트 등의 이모티콘이 있는건 보면 좋다

 

4. 4주차부터는 코딩과제, 테스트코드 반드시 작성

 

5.참여율 80% -> 70% 조절할 수도 있음

 

6.자동동기화를 할려면 서버가 있어야됨 -> 현재 깃허브 대시보드

 

※ Github action이란?

GitHub에서 제공하는 워크플로우(Workflow) 자동화 도구다. 워크플로우라는 단어가 의미하듯 테스트, 빌드, 배포 뿐 아니라 다양한 작업을 만들어서 자동으로 실행하게 할 수 있다. PR에 특정 코멘트를 남기면 자동으로 머지를 하게 만들 수 있고, 데이터를 수집하는 데에 이용할 수도 있다. 누구는 부동산 정보를 수집하기도 하더라.

 

ahnheejong.name/articles/receive-new-room-notification-mails-using-github-action/

 

GitHub Action을 사용해 새로 올라온 전월세 방 목록 받아보기

부동산 앱에 새로 올라오는 방을 매번 직접 체크하는 대신 편하게 받아볼 수 없을까?

ahnheejong.name

7. 4주차 과제

1번과제 깃허브 대시보드는 문자열로 테이블만드는걸 해야됨

난이도가 전체적으로 올라간것 같지만 해보면 별건아님(백기선님 왈)

 

조영호님 책이 객체지향개념잡기 좋음

 

서술책이 아닌 코드가 많은 책으로 객체지향 공부하고 싶으면 디자인패턴, 리팩토링, 클린 아키텍처 책 보면됨

 

실무에서 테스트코드 작성하는 팀은 드물다 

 

8. 보너스 문제

/*
numbers 라는 배열이 있다.
해당 배열에 들어있는 숫자들은 오직 한 숫자를 제외하고는 모두 두번씩 들어있다.
오직 한번만 등장하는 숫자를 찾는 코드를 작성해라
*/

해결방법
1.for문2번 : 시간복잡도 안좋음
2.HashSet : Set인터페이스의 구현 클래스, 중복을 자동으로 제거해줌
3.XOR : 원하는 답
※비교하는 숫자라 다르면1, 같으면 0
/*
 xor
 5 ^ 0 = 5 
 101
 000
 ---
 101
 5 ^ 5 = 0
 101
 101
 ---
 000
*/

public class Main{
	public static void main(String[] args){
    	Main main = new Main();
        main.solution(new int[]{5, 2, 4, 7, 5, 2, 4})
    }
    
  
    //비트연산으로 계산해야함
    //xor은 순서에 상관없음
    //result가 0이니까 0 ^ 5 ^ 2 ^ 4 ^ 7 ^ 5 ^ 2 ^ 4를 비트로 계산해도 7이나옴
    //Ex) 위 예제에서 5는 5끼리 2는 2끼리 4는 4끼리 계산하면 0이나옴
    //    0이랑 남은 숫자 7이랑 하면 7이나옴
    private static int solution(int[] numbers){
    	int result = 0;
        for(int number : numbers){
        	result ^= number;
		}
        return result;
    }
}

※ 인텔리제이 단축키
1.iter는 인덱스 없는 for문
2.itar는 인덱스 있는 for문

 

9.기타

  • 4주차까지 학습하면 코딩할 재료는 다 갖춘것

  • 이다음부터는 개념적인 것이 많음

  • 콜렉션은 공부해야됨

  • 현재 만드는 강의가 있는데 비밀 / 스프링 배치강의도 생각중, 당장은 아님

 

출처

ndb796.tistory.com/4