수학적인 계산을 하기 위한 연산자.
연산 | 연산자 | 수식 | 결과 |
---|---|---|---|
덧셈 | + | A+B | A와 B를 더한값 |
뺄셈 | - | A-B | A와 B를 뺀 값 |
곱셉 | * | A*B | A와 B를 곱한값 |
나눗셈 | / | A/B | A를 B로 나눈값 |
나머지 | % | A%B | A를 B로 나눈 나머지 |
특징 피연산자들의 타입이 다를 경우 자동 타입 변환하여 피연산자 들의 타입을 일치 시킨후 연산을 진행
결과 유형은 다음과 같이 피연산자 또는 피연산자 유형에 따라 결정된다
피연산자 중 하나가 double 또는 Double 이면 결과 유형은 double 이다
그렇지 않으면 피연산자 중 하나가 float 또는 Float 이면 결과 유형은 float 이다
그렇지 않으면, 피연산자 중 하나가 long 또는 Long 이면 결과 유형은 long 이다
그렇지 않은 경우 결과 유형은 int 입니다. 여기에는 byte , short , char 피연산자와 int.
연산의 결과 유형에 따라 산술 연산이 수행되는 방식과 피연산자가 처리되는 방식이 결정된다
결과 유형이 double 이면 피연산자가 double 으로 승격되고 연산은 64 비트 (배정 밀도 이진) IEE 754 부동 소수점 산술을 사용하여 수행된다
결과 유형이 float 이면 피연산자가 float 로 승격되고 연산은 32 비트 (단 정밀도 2 진수) IEE 754 부동 소수점 산술을 사용하여 수행된다
결과 유형이 long 경우, 피연산자는 long 으로 승격되고 연산은 64 비트 부호있는 2의 보수 2 진 정수 산술을 사용하여 수행된다
결과 유형이 int 이면 피연산자가 int 로 승격되고 연산은 32 비트 부호있는 2의 보수 2 진 정수 연산을 사용하여 수행된다
(정수 타입의 연산의 결과가 int타입으로 나온느 이유는 자바가상기계(JVM)이 기본적으로 32bit 단-위로 계산하기 때문이다 )
보수 ( ~ ) 연산자는 하나의 피연산자 비트를 비트 또는 논리 반전하는 단항 연산자
AND ( & ) 연산자는 두 개의 피연산자의 비트 또는 논리 "and"를 수행하는 이항 연산자
OR ( | ) 연산자는 2 개의 피연산자의 비트 또는 논리 "포함 또는"을 수행하는 2 진 연산자
XOR ( ^ ) 연산자는 두 개의 피연산자의 비트 또는 논리 "배타적 논리합"을 수행하는 이항 연산자
연산자는 실제로 모든 32 또는 64 비트의 피연산자 또는 피연산자를 병렬로 연산한다
~ 연산자는 부울 값을 뒤집거나 정수 피연산자의 모든 비트를 변경하는 데 사용된다
& 연산자는 정수 피연산자의 비트 중 일부를 "마스킹"하는 데 사용된다
==
: Equal to!=
: Not equal to>
: greater than<
: less than>=
: greater than or equal to<=
: less than or equal toboolean
&&
(LOGICAL AND)||
(LOGICAL OR)boolean
boolean
참조 변수가 참조 하고있는 인스턴스의 실제 타입을 알아보기 위해 instanceof 연산자를 사용한다. instanceof는 객체 타입을 확인하는 연산자로 instanceof를 이용하여 true라는 연산결과를 얻었다면 참조 변수가 검사하는 타입으로 형 변환이 가능하다는 뜻이다.
[참고] 값이 null인 참조 변수를 instanceof로 연산하면 false결과를 얻음.
class Parent{}
class Child extend Parent{}
public class Instanceof{
public static void main(String[] args){
Parent parent = new Parent;
Child child = new Child;
System.out.println( parent instanceof parent ); //true
System.out.println( child instanceof parent); //true
System.out.println( parent instanceof child); //flase;
System.out.println( child instanceof child); //true;
}
}
Parent는 Child의 상위클래스이기 때문에 3번 째 문장에서는 false가 출력된다.
(상위클래스는 하위클래스로 형 변환 할 수 없기 때문)
대입 연산자
대입 연산자 | 설명 |
---|---|
= | 왼쪽의 피연산자에 오른쪽 피연산자를 대입함 |
+= | 두 피연산자를 더한 값을 왼쪽의 피연산자에 대입함 |
-= | 왼쪽의 피연산자에서 오른쪽 피연산자를 뺀 값을 왼쪽 피연산자에 대입함 |
*= | 두 피연산자를 곱한 값을 왼쪽의 피연산자에 대입함 |
/= | 왼쪽 피연산자를 오른쪽 피연산자로 나눈 몫을 왼쪽 피연산자에 대입함 |
%= | 왼쪽 피연산자를 오른족 피연산자로 나눈 나머지를 왼쪽 피연산자에 대입함 |
&= | 왼쪽 피연산자와 오른쪽 피연산자를 AND연산 한 후 그 값을 대입함 |
|= | 왼쪽 피연산자와 오른쪽 피연산자를 OR연산 한 후 그 값을 대입함 |
^= | 왼쪽 피연산자와 오른쪽 피연산자를 XOR연산 한 후 그 값을 대입함 |
<<= | 왼쪽 피연산자를 오른쪽 피연산자만큼 왼쪽 시프트 한 후 그 값을 대입함 |
>>= | 왼쪽 피연산자를 오른쪽 피연산자 만큼 부호를 유지하며 오른쪽으로 시프트 한 후 그 값을 대입함 |
>>>= | 왼쪽 피연산자를 오른쪽 피연산자 만큼 부호 상관없이 오른쪽으로 시프트 한 후 그 값을 대입함 |
Java 8부터 사용가능한 연산자로 람다표현 기능을 수행할 수 있다.
람다 이전의 자바에서는 내부 익명 클래스를 통해 구현체를 만들어 사용했지만 람다를 사용하면서
내부익명 클래스로 구현한 구현체의 단점들(가독성, 길어진 코드)를 보완 할 수 있게 되었다.
람다 이전의 자바
@FunctionalInterface
public interface Foo{
void printInt(int x); // 한 개의 메소드 추상화(함수형 인터페이스)
}
현재 printInt는 추상화만 되어있기 때문에 사용이 불가능하다.
추상메소드 사용하기
public class JavaArrow implement Foo{
@Override //오버라이드
public void printInt(int x){ //Foo 인터페이스의 메소드 가져와서 사용
System.out.println(x); //메소드 구현
}
public static void mian(String[] args){
JavaArrow ja = new JavaArrow(); //JavaArrow 인스턴스 만들기
int y = 3;
ja.printInt(y); //인스턴스에 메소드 호출
}
}
public static void main(String[] args){
int y = 3;
Foo foo = new Foo(){ //내부 익명 클래스 구현 (Ananimous inner class)
@Override //Foo interface를 받아와서 구현
public void printInt(int x){
System.out.println(x); //실제 구현
}
}
foo.printInt(y); //foo 인스턴스를 가져와서 사용
}
간단한 한 줄 짜리 출력문을 뽑기 위해 약 6줄 정도가 추가되었고 람다는 이를 보완할 수 있다.
public static void main(String[] args){
Foo foo = (x) -> System.out.println(x);
}
이렇게 한 줄로 구현이 가능하다.
자세한 내용은 Interface를 다룰 때 작성해보도록 하겠다.
간단히 알 수 있는 내용은 Java 8이상부터 사용이 가능한 람다식을 ->연산자를 이용해 사용한다는 것이다.
if else 구조를 간결하게 표현할 수 있는 연산자
간단하게 if else문을 3항 연산자로 표현하는 법을 살펴보자
int a = 10;
int b = 20;
int bigger;
if( a > b ) {
bigger = a;
}else{
bigger = b;
}
위의 if else문을 3항 연산자로 표현하면
int bigger = (a > b) ? a : b;
이렇게 더 직관적인 표현으로 로직을 구현 할 수 있다. 그럼 단순히 이러한 기능만을 위해 존재하는 연산자인가??
아니다
우선 문(statement)과 식(expression)의 차이를 알고 넘어가자 둘의 가장 큰 차이는 바로
값(value)이다 문장은 스스로 값을 return할 수 없다
if문 하나만 가지고는 어떤 값(value)를 나타내지 못한다. 반면 식인 삼항연산자는 값을 return 할 수 있다.
String message = String.format("%d와 %d중 더 큰 수는 %d입니다.", a, b, (a > b) ? a : b);
연산자 우선순위 | 연산자 |
---|---|
최우선 연산자 | .(점) , [] , () |
단항 연산자 | ! , ~ , +/- , ++/-- , (cast 자료형) , instanceof |
산술 연산자 | + , - , * , / , % |
Shift 연산자 | << , >> , >>> |
관계 연산자 | < , > , <= , >= , == , != |
비트 연산자 | & , |
논리 연산자 | && , |
삼항 연산자 | (조건항) ? 참항:거짓항 |
배정 대입 연산자 | = , *= , +=, -=, /= ,%= , <<= , >>= , >>>= |
증감 후위 연산자 | ++/-- |
순차 연산자 | , |
기존의 switch문이 아닌 switch 연산자가 추가된 것
[기존의 switch statement]
다수의 case , break 사용
break를 사용하지 않으면 다음 분기가 실행됨
return 값 없음
[state operator]
break를 사용하지 않아도 된다.
yield 존재함
return값 존재해도됨
case -> A 같은 형식으로 표현가능
switch의 반환값이 따로 필요하지 않거나 case가 switch 들어오는 모든 인자를 커버하는 경우
default 항목을 넣어주지 않아도 되나 그렇지 않은 경우는 default -> code를 작성해야 한다.
public class Switch
public static void main(String[] args){
//Java 12 이전
int num = 1;
int returnNum = 0;
switch(num){
case 1:
returnNum = 1;
break;
case 2:
returnNum = 2'
break;
}
//Java 12
returnNum = switch(num){
case 1 -> 1;
case 2 -> 2;
default -> throw new IllegalStateException("Unexpected value: " + num);
};
//Java13
returnNum = switch(num){
case 1 : yield 3;
default : throw new IllegalStateException("unexpected value : " + num);
};
}
결과
1
1
3
switch 연산자에서 yield는 함수의 return과 같은 역할을 한다고 생각하면 편하다.