목표
자바가 제공하는 다양한 연산자를 학습하세요.
학습할 것
- 산술 연산자
- 비트 연산자
- 관계 연산자
- 논리 연산자
- instanceof
- assignment(=) operator
- 화살표(->) 연산자
- 3항 연산자
- 연산자 우선 순위
- (optional) Java 13. switch 연산자
마감일시
2020년 11월 28일 오후 3시까지.
0. 연산관련 용어
- 연산: 수나 식을 일정한 규칙에 따라 계산하는 것이다.
- 연산자: 연산을 수행하는 기호
- 피연산자: 연산에 참여하는 변수나 상수
1. 자바 연산자와 연산자 우선 순위
연산기호 |
결합 방향 |
우선순위 |
[ ], . |
-> |
1 |
expr++, expr-- |
<- |
2 |
++expr, --expr, +expr, -expr~, !, (type) |
<- |
3 |
*, /, % |
-> |
4 |
+, - |
-> |
5 |
<<, >>, >>> |
-> |
6 |
<, >, <=, >=, instanceof |
-> |
7 |
==, != |
-> |
8 |
& |
-> |
9 |
^ |
-> |
10 |
! |
-> |
11 |
&& |
-> |
12 |
|| |
-> |
13 |
? expr : expr |
<- |
14 |
=, +=, -=, *=, /=, %=, &=^=, !=, <<=, >>=, >>>= |
<- |
15 |
2. 산술 연산자 와 대입 연산자 (assignment operator)
- 대입연산자: 오른쪽에 있는 값을 왼쪽에 있는 변수에 대입한다. (val = 20)
- 산술연산자: 흔히 사칙연산이라고 부르기도 한다.
연산자 |
기능 |
결합 방향 |
= |
연산자 오른쪽에 있는 값을 연산자 왼쪽에 있는 변수에 대입한다. |
<- |
+ |
두 피연산자의 값을 더한다. |
-> |
- |
왼쪽의 피연산자 값에서 오른쪽의 피연산자 값을 뺀다. |
-> |
* |
두 피연산자의 값을 곱한다. |
-> |
/ |
왼쪽의 피연산자의 값을 오른쪽의 피연산자 값으로 나눴을 떄 얻게 되는 몫을 반환한다. |
-> |
% |
왼쪽의 피연산자 값을 오른쪽의 피연산자 값으로 나눴을 때 얻게 되는 나머지를 반환한다. |
-> |
int val = 10 + 3 을 보면
우선순위가 높은 +( + 4순위, = 15순위) 연산부터 진행된다.
한 차례 연산 결과 int val = 13 이 된다. 그리고 나서
val 이라는 변수에 대입 연산자에 의해 값이 할당된다.
예시
int number1 = 9;
int number2 = 4;
// number1 + number2 = 13
System.out.println("number1 + number2 = " + (number1 + number2));
// number1 - number2 = 5
System.out.println("number1 - number2 = " + (number1 - number2));
// number1 * number2 = 36
System.out.println("number1 * number2 = " + (number1 * number2));
// number1 / number2 = 2
System.out.println("number1 / number2 = " + (number1 / number2));
// number1 & number2 = 1
System.out.println("number1 & number2 = " + (number1 % number2));
이 때 기존에 있던 변수에 저장된 값에 대해서
산술연산을 할 수 있는데 이것을 복합 대입연산자라고 한다.
number = number + 5; // 변수 number에 저장된 값이 5 증가한다.
number += 5;
여기서 흥미로운 점은 형변환 부분이다.
short shortNumber = 10;
shortNumber = (short) (shortNumber + 77L); // 형변환 필수 아니면 컴파일 에러
int intNumber = 3;
intNumber = (int) (intNumber * 3.3); // 형변환 필수 아니면 컴파일 에러
System.out.println(shortNumber);
System.out.println(intNumber);
shortNumber = 10;
shortNumber += 77L; // 자동 형변환
intNumber = 3;
intNumber += 3.3; // 자동 형변환
System.out.println(shortNumber);
System.out.println(intNumber);
복합연산자를 사용하면 컴파일러가 알아서 해석해주기 때문에 명시적인 형 변환을 줄일 수 있는 장점이 있다.
3. 비트 연산자
비트 연산자는 피연산자의 비트 열을 왼쪽 또는 오른쪽으로 이동시킨 결과를 반환하는 연산자이다. 이 연산자도 두 개의 피연산자가 필요한 이항 연산자이며 피 연산자는 모두 정수 이여야 한다.
연산자 |
기능 |
결합 방향 |
<< |
* 피연산자의 비트 열을 왼쪽으로 이동* 이동에 따른 빈 공간은 0으로 채움n << 2;n 의 비트 열을 두 칸 왼쪽으로 이동 시킨 결과 반환 |
-> |
>> |
* 피연산자의 비트 열을 오른쪽으로 이동* 이동에 따른 빈 공간이 음수의 경우 1, 양수의 경우 0으로 채움n >> 2;n 의 비트 열을 두 칸 오른쪽으로 이동 시킨 결과 반환 |
-> |
>>> |
* 피연산자의 비트 열을 오른쪽으로 이동* 이동에 따른 빈 공간은 0으로 채움n >>> 2;n 의 비트 열을 두 칸 왼쪽으로 이동 시킨 결과 반환 |
-> |
int number1 = 20;
System.out.println("(number1 >> 1) = " + (number1 >> 1)); // 10
>> 연산을 통해서 한 칸씩 오른쪽으로 밀 때마다 2로 나눈 결과를 반환한다.
4. 관계 연산자
관계 연산자는 두 개의 피연산자 사이에서 크기 및 동등 관계를 따져주는 이항 연산자
연산자 |
기능 |
결합 방향 |
< |
n1 < n2n1 이 n2 보다 작은가? |
-> |
> |
n1 < n2n1 이 n2 보다 큰가? |
-> |
<= |
n1 < n2n1 이 n2 보다 같거나 작은가? |
-> |
>= |
n1 < n2n1 이 n2 보다 같거나 큰가? |
-> |
== |
n1 < n2n1 이 n2 보다 같은가? |
-> |
!= |
n1 < n2n1 이 n2 보다 다른가? |
-> |
질문의 결과가 진실이면 true 거짓이면 false 가 반환된다.
System.out.println("3 < 2 : " + (3 < 2)); // false
System.out.println("3 > 2 : " + (3 > 2)); // true
System.out.println("3 >= 3 : " + (3 >= 3)); // true
// 자동 형 변환 예시
System.out.println("3.0 == 3 : " + (3.0 == 3)); // true
// 자동 형 변환 예시
System.out.println("3.0 != 3 : " + (3 != 3)); // false
5. 논리 연산자
논리 연산자도 true 또는 false 를 반환하는 연산자로써 다음과 같다.
연산자 |
기능 |
결합 방향 |
&& |
A && BA와 B 모두 true 이면 연산 결과는 true |
-> |
|| |
A || BA 또는 B가 true 이면 연산 결과는 true |
-> |
! |
!A연산결과가 true 이면 false, false 이면 true |
-> |
간단하지만 주의 할 점이 있다.
Short-Circuit Evaluation (SCE) 이다.
int number1 = 0;
int number2 = 0;
boolean result;
// 1
result = ((number1 += 10) < 0) && ((number2 += 10) > 0);
System.out.println("result = " + result);
System.out.println("number1 = " + number1);
System.out.println("number2 = " + number2);
// 2
result = ((number1 += 10) > 0) || ((number2 += 10) > 0);
System.out.println("result = " + result);
System.out.println("number1 = " + number1);
System.out.println("number2 = " + number2);
1.
result = false
number1 = 10
number2 = 0
2.
result = true
number1 = 20
number2 = 0
1번 같은 경우
(number1 += 10) < 0)
이 부분에서 이미 false 가 나와서 다음 연산 결과가 무엇이 나오든 false 이기 때문에 뒤의 부분 연산을 진행하지 않은 것이고
2번 같은 경우는
(number1 += 10) > 0)
이 부분에서 이미 true 가 나와서 다음 연산 결과가 무엇이 나오든 true이기 때문에 뒤의 부분 연산을 진행하지 않은 것이다.
이러한 이유 때문에 비교 연산자 부분에 대입 연산자를 같이 두지 않는 것이 바람직하다.
number1 += 10;
number2 += 10;
result = (number1 < 0) && (number2 > 0);
6. instanceof
참조변수가 참조하는 인스턴스의 '클래스'나 참조하는 인스턴스가 '상속하는 클래스'를 묻는 연산자이다.
예를 들면 다음과 같이 문장이 구성할 수 있다.
if (toast instanceof Bread)
toast 는 참조변수이고 Bread 는 클래스이다.
만약 toast 가 Bread를 참조하면 true 값이 나오고 아니면 false가 나온다.
예시
class Box {
public void simpleWrap() {
System.out.println("Simple Wrapping");
}
}
class PaperBox extends Box {
public void paperWrap() {
System.out.println("Paper Wrapping");
}
}
class GoldPaperBox extends PaperBox {
public void goldWrap() {
System.out.println("Gold Wrapping");
}
}
class Wrapping {
public static void main(String[] args) {
Box box1 = new Box();
PaperBox box2 = new PaperBox();
GoldPaperBox box3 = new GoldPaperBox();
wrapBox(box1);
wrapBox(box2);
wrapBox(box3);
}
public static void wrapBox(Box box) {
if(box instanceof GoldPaperBox) {
((GoldPaperBox)box).goldWrap();
}
else if(box instanceof PaperBox) {
((PaperBox)box).paperWrap();
}
else {
box.simpleWrap();
}
}
}
부모 클래스 타입으로 들어온 매개변수가 실제로는 참조하는 타입은 자식이고 어떤 자식인지 알아야 형변환하여 메소드를 호출하는데
이때 instanceof 를 사용해서 쉽게 해결 할 수 있다.
결론적으로, "연산자 instanceof는 명시적 형 변환의 가능성을 판단해주는 연산자이다."
추후에 상속을 유지하면서 메소드를 오버라이딩 기반으로 다음과 같이 리팩토링 할 수 있다.
class Box {
public void wrap() {
System.out.println("Simple Wrapping");
}
}
class PaperBox extends Box {
public void wrap() {
System.out.println("Paper Wrapping");
}
}
class GoldPaperBox extends PaperBox {
public void wrap() {
System.out.println("Gold Wrapping");
}
}
class Wrapping {
public static void main(String[] args) {
Box box1 = new Box();
PaperBox box2 = new PaperBox();
GoldPaperBox box3 = new GoldPaperBox();
wrapBox(box1);
wrapBox(box2);
wrapBox(box3);
}
public static void wrapBox(Box box) {
box.wrap();
}
}
7. 3항 연산자
3항 연산자는 A ? B : C 형태로 A가 true 이면 B false 이면 C 값을 반환한다.
C 자리에는 다른 3항 연산자가 들어와도 된다.
if else 구문을 한줄로 간단하게 처리할 때 사용하면 유용하다.
boolean isLunchTime = false;
boolean isDinnerTime = false;
//삼항 연산자
String time = isLunchTime ? "점심식사" : isDinnerTime ? "저녁식사" : "아침식사";
//if문
String time;
if (isLunchTime) {
time = "점심식사";
} else if (isDinnerTime) {
time = "저녁식사";
} else {
time = "아침식사";
}
8. Java 13. switch 연산자
자바 13 부터 break 자리에 yeild 키워드를 이용하여 리턴을 할 수 있게 되었다.
9. 화살표 연산자
자바는 객체지향 언어이지만, "기능 하나를 정의해야 하는 상황" 을 자주 접하게 된다.
functional 정의, functional interface, @FunctionalInterface가 생기었다.
이 함수형 인터페이스를 기반으로 람다식을 작성 할 수 있다.
매개변수가 있고 반환하지 않는 람다식
interface Printable {
void print(String s); // 매개변수 하나, 반환형 void
}
class OneParamNoReturn {
public static void main(String[] args) {
Printable p;
p = (String s) -> {System.out.println(s);}; // 줄임 없는 표현
p.print("Lambda exp one.");
p = (String s) -> System.out.println(s); // 중괄호 생략
p.print("Lambda exp two.");
p = (s) -> System.out.println(s); // 매개변수 형 생략
p.print("Lambda exp three.");
p = s -> System.out.println(s); // 매개변수 소괄호 생략
p.print("Lambda exp four.");
}
}
interface Calculate {
void cal(int a, int b); // 매개변수 둘, 반환형 void
}
class TwoParamNoReturn {
public static void main(String[] args) {
Calculate c;
c = (a, b) -> System.out.println(a + b);
c.cal(4, 3); // 이번엔 덧셈이 진행
c = (a, b) -> System.out.println(a - b);
c.cal(4, 3); // 이번엔 뺄셈이 진행
c = (a, b) -> System.out.println(a * b);
c.cal(4, 3); // 이번엔 곱셈이 진행
}
}
매개변수가 있고 반환 하는 람다식
interface Calculate {
int cal(int a, int b); // 값을 반환하는 추상 메소드
}
class TwoParamAndReturn {
public static void main(String[] args) {
Calculate c;
c = (a, b) -> { return a + b; };
System.out.println(c.cal(4, 3));
c = (a, b) -> a + b; // return 과 중괄호 생략 가능
System.out.println(c.cal(4, 3));
}
}
매개변수가 없는 람다식
interface Generator {
int rand(); // 매개변수 없는 메소드
}
class NoParamAndReturn {
public static void main(String[] args) {
Generator gen = () -> {
Random rand = new Random();
return rand.nextInt(50);
};
System.out.println(gen.rand());
}
}
마지막으로 화살표 연산자를 사용할 때, 매개변수 개수와 타입이 같다면 더블클론 형태로 바꿀 수 있다.
예시
@FunctionalInterface
public interface StringToDog {
public String convert(String name, String species, int price);
}
public class Dog {
private String name;
private String species;
private int price;
public static String introduce(String name, String species, int price) {
return name + " : " + species + " : " + price;
}
}
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class DoubleColonTest {
public static void main(String[] args) {
StringToDog stringToDog1 = (name, species, price) -> Dog.introduce(name, species, price);
StringToDog stringToDog2 = Dog::introduce;
System.out.println(stringToDog1.convert("개똥이", "믹스", 100));
System.out.println(stringToDog2.convert("누렁이", "믹스", 1000));
}
}
'스터디 > [white-ship] 자바 스터디(study hale)' 카테고리의 다른 글
1주차 과제: JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가. (0) | 2021.01.02 |
---|---|
2주차 과제: 자바 데이터 타입, 변수 그리고 배열 (0) | 2021.01.02 |
4주차 과제: 제어문 (0) | 2021.01.02 |
4주차 과제: live-study 대시 보드 (0) | 2021.01.02 |
4주차 과제 LinkedList (0) | 2021.01.02 |
댓글