선장님과 함께하는 자바 스터디입니다.
자바 스터디 Github
github.com/whiteship/live-study
나의 Github
github.com/cmg1411/whiteShip_live_study
산술 연산자
산술 연산자는 계산하는 연산자이다.
프로그래밍에 쓰이는 산술 연산자는 크게 다섯가지가 있다.
- 더하기
public class plus {
public static void main(String[] args) {
int a = 1;
int b = 3;
System.out.println(a + b);
double c = 3.5;
int d = 5;
System.out.println(c + d);
char e = 'a';
double f = 1.5;
System.out.println(e + f);
}
}
각 출력 결과는 어떻게 나올까.
첫번째는 자명하다. 4.
두번째 : int 가 더 큰 자료형인 double 로 자동으로 타입 프로모션되었다.
세번째 : a 는 아스키코드값으로 97 이다. 산술 연산은 기본적으로 숫자이기 때문에 문자형은 아스키코드 값으로 계산하게 된다. 이후 두번째와 같이 타입 프로모션되어 97.0 + 1.5 = 98.5 가 나온 것이다.
- 빼기, 곱하기
public class minus {
public static void main(String[] args) {
int a = 5;
int b = 10;
System.out.println(a - b); // -5
System.out.println(a * b); // 50
double c = 7.5;
int d = 5;
System.out.println(c - d); // 2.5
System.out.println(c * d); // 37.5
char e = 'a';
double f = 1.5;
System.out.println(e - f); // 95.5
System.out.println(e * f); // 145.5
}
}
빼기와 곱하기는 더하기와 같은 방식으로 계산하게 된다.
- 나누기
- 프로그래밍에서 나누기는 실세계의 나누기보다는, 몫을 구하는 계산으로 보는 것이 더 알맞다.
- 나누기는 조심해야 할 점이 있다.
- 피연산자의 자료형이 다를 때에는 범위가 큰 쪽으로 묵시적 타입 프로모션된다.
- 정수끼리의 나눗셈에서 결과는 정수여야 하기 떄문에, 소숫점 아래 부분은 잘라내고 정수형으로 묵시적 타입 캐스팅된다.
public class divide {
public static void main(String[] args) {
int a = 10;
int b = 3;
System.out.println(a / b); // 3
double c = 1.5;
int d = 5;
System.out.println(c / d); // 0.3
System.out.println(d / c); // 3.333333..
}
}
- 나머지
- 나머지연산자의 기호는 % 이다.
- 나누기가 몫을 구했다면, 나눗셈의 나머지는 % 연산인 것이다.
public class moduler {
public static void main(String[] args) {
int a = 10;
int b = 3;
System.out.println(a % b); // 1
System.out.println(b % a); // 3
int c = 10;
double d = 57.5;
System.out.println(d % c); // 7.5
}
}
- 나머지 연산도 다른 산술 연산자처럼 분배법칙이 적용되는데, 특이하게 적용된다.
(A + B) % C = ((A%C) + (B%c)) % C // 더하기, 곱하기 성립
(A - B) % C = ((A%C) - (B%C) + C) % C
나누기는 성립하지 않음
나머지값은 논리상 나눠지는 값보다 크면 안된다. 따라서 분배법칙이 들어가도 최종적으로 % C 가 들어간다.
그리고 빼기는, 분배법칙 내부의 결과가 음수가 나올 수 있으므로 +C 를 해준다. 어짜피 뒤에서 %C 를 해주기 떄문에 결과에 상관없는 연산이다.
비트연산자
public class bitCal {
public static void main(String[] args) {
Integer a = 12; // 0000 0000 0000 0000 0000 0000 0000 1100
Integer b = 27; // 0000 0000 0000 0000 0000 0000 0001 1011
Integer c = -10; // 1111 1111 1111 1111 1111 1111 1111 0110
System.out.println(Integer.toBinaryString(a & b));
// 0000 0000 0000 0000 0000 0000 0000 1100
// 0000 0000 0000 0000 0000 0000 0001 1011
// ----------------------------------------
// 0000 0000 0000 0000 0000 0000 0000 1000
System.out.println(Integer.toBinaryString(a | b));
// 0000 0000 0000 0000 0000 0000 0000 1100
// 0000 0000 0000 0000 0000 0000 0001 1011
// ----------------------------------------
// 0000 0000 0000 0000 0000 0000 0001 1111
System.out.println(Integer.toBinaryString(a ^ b));
// 0000 0000 0000 1100
// 0000 0000 0001 1011
// ----------------------------------------
// 0000 0000 0000 0000 0000 0000 0001 0111
System.out.println(Integer.toBinaryString(~a));
// not 연산은 모든 비트를 반전시킨다. 이진수로는 아래와 같은결과가 나온다.
// 1111 1111 1111 1111 1111 1111 1111 0011
// MSB 가 1이므로 이 수는 음수이고, 음수를 10진수로 계산하려면 2의 보수를 취한다.
// 1의 보수 = 0000 0000 0000 0000 0000 0000 0000 1100
// + 1 = 0000 0000 0000 0000 0000 0000 0000 1101
// = 13 의 음수는 -13
System.out.println(Integer.toBinaryString(a << 2));
// 0000 0000 0000 0000 0000 0000 0000 1100 왼쪽으로 2 비트 이동
// ----------------------------------------
// 0000 0000 0000 0000 0000 0000 0011 0000
System.out.println(Integer.toBinaryString(a >> 3));
// 1
// 양수이므로 0으로 채워진다.
System.out.println(Integer.toBinaryString(c >> 3));
// 1111 1111 1111 1111 1111 1111 1111 1110
// 음수이므로 1로 채워진다.
System.out.println(Integer.toBinaryString(a >>> 3));
// 1
System.out.println(Integer.toBinaryString(c >>> 3));
// 0001 1111 1111 1111 1111 1111 1111 1110
}
}
관계연산자
논리연산자
- 논리 연산자는 비트 연산자와 비슷하게 생겼다.
- &&, || 처럼 두개가 들어간다.
- 가장 큰 차이는 비트연산자는 말 그대로 비트를 대상으로 하는 연산이고,
- 논리 연산자는 피연산자가 boolean 반환값을 가지는 조건식이라는 것이다.
instanceOf
- 참조 변수가 참조하고 있는 인스턴스의 실제 타입인지 여부 boolean 을 반환
- 한마디로, 어떤 클래스(or인터페이스) 로 만들어진 인스턴스인지 확인하는 연산자.
public class InstacneOf {
static class A {}
static class B extends A {}
interface C {}
static class D implements C {}
public static void main(String[] args) {
A a = new A();
B b = new B();
D d = new D();
System.out.println(a instanceof B); // false
System.out.println(a instanceof A); // true
System.out.println(b instanceof A); // true, B 클래스는 A를 상속받았으므로 true
System.out.println(d instanceof D); // true
System.out.println(d instanceof C); // true
}
}
대입연산자
- 이항 연산자로, 왼쪽 피연산자에 오른쪽 피연산자를 대입하는 역할을 한다.
화살표(->) 연산자
- 화살표 연산자는 Java 8 버전에서 함수형 프로그래밍이 도입되면서, 람다 표현식을 위해 만들어졌다.
- 람다 표현식은 익명 함수를 간단하게 표현한 식이다.
- 좌항에는 매개변수를 넣고, 우항에는 실행할 메서드를 기술한다.
- 메서드 부분은 더 간단하게 메서드레퍼런스라는 방식을 사용할 수 있다.
함수형 인터페이스와 람다는 주제와 조금 벗어나지만 간단히 설명하자면,
인터페이스에 추상메서드 하나만 정의되어있는 형태를 함수형 인터페이스라고 하며,
이 인터페이스를 구현할 때 익명 클래스를 이용하여 그 하나의 함수만 오버라이딩하여 사용할 수 있다.
그런데 그 익명클래스는 너무 길기 때문에, 람다식이라는 방식을 이용하여 인터페이스를 구현하고 그 유일한 함수를 실행한다.
추상 메서드가 하나이기 때문에 람다식으로 자바가 추론이 가능하며, 하나이기 때문에 그 함수가 인터페이스를 정의한다.
public class Lambda {
public static void main(String[] args) {
FunctionalInterface f = new FunctionalInterface() {
@Override
public int add(int a, int b) {
return a + b;
}
};
int result = f.add(1, 2);
System.out.println(result); // 3
FunctionalInterface f2 = (a,b) -> a + b + b;
System.out.println(f2.add(1, 2)); // 5
}
}
public interface FunctionalInterface {
int add(int a, int b);
}
3항 연산자
- 3항연산자는 다음과 같이 3개의 항과 2개의 연산자를 사용한다.
(조건식) ? (조건식이 참일때 실행될 구문) : (조건식이 거짓일때 실행될 구문)
- if 를 이용해야 할 것 같은 조건처리를 간단하게 해결할 수 있다.
연산자 우선순위
- 외우면 좋고,
- 헷갈린다면 괄호를 꾸준히 쓰자.
switch 연산자
- Java 13 버전에는 switch 라는 연산자가 새로 나왔다.
- 기존에 우리가 알던 분기문에 쓰이는 switch 랑은 다른 점이 있다.
- 아래를 보자.
- 보듯이 switch statement 에서 switch Expression 으로 바뀌었다.
- 기존의 switch 는 분기처리를 위해 사용하던 구문이었지만
- 자바 13 의 switch 는 분기에 따라 반환값을 가질 수 있는 표현이 되었다는 말이다.
public class Switch {
public static void main(String[] args) {
char choice = 'a';
int result = switch(choice) {
case 'a' -> 1;
case 'b' -> 2;
default -> throw new IllegalStateException("Unexpected value: " + choice);
};
System.out.println(result);
}
}
결과는 1이 나온다.
switch Expression 의 결과로 1이 반환된 것이다.
Java 10 에서 나온 var 타입추론을 이용하면, 여러 상황에 맞는 여러 자료형을 반환할 수 있다.
public class Switch {
public static void main(String[] args) {
char choice = 'b';
var result = switch(choice) {
case 'a' -> 1;
case 'b' -> "hi";
default -> throw new IllegalStateException("Unexpected value: " + choice);
};
System.out.println(result);
}
}
콘솔에는 hi 가 찍힌다.
마지막으로 yield 키워드가 있는데, 위와같이 람다식을 쓰면 각 분기에서 한가지 처리를 한다.
여러 처리를 하기 위해 원래처럼 : 연산자를 쓴다면, yield 키워드를 통해 반환할 값을 명시할 수 있다.
public static void main(String[] args) {
char choice = 'b';
var result = switch(choice) {
case 'a':
System.out.println("It is a.");
yield 1;
case 'b' :
System.out.println("It is b.");
yield "22";
default :
throw new IllegalStateException("Unexpected value: " + choice);
};
System.out.println(result);
}
java 13 switch 문서
docs.oracle.com/en/java/javase/13/language/switch-expressions.html
'WhiteShip Java Study : 자바 처음부터 멀리까지' 카테고리의 다른 글
클래스 (0) | 2021.01.30 |
---|---|
4주차) 과제 (0) | 2021.01.30 |
제어문 (0) | 2021.01.28 |
자바 데이터 타입, 변수 그리고 배열 (0) | 2021.01.16 |
JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가 (0) | 2021.01.13 |