연산자는 연산을 수행하는 기호를 말한다.
연산자가 연산을 수행하기 위해서는 반드시 연산의 대상이 있어야 하는데, 이를 피연산자(operand)라고 한다. 피연산자로 상수, 변수 또는 식(계산식) 등을 사용할 수 있다.
산술 연산자에는 사칙 연산자 +, -, *, /와 나머지 연산자 %가 있다.
boolean 타입을 제외한 모든 기본 타입에 사용할 수 있다
피연산자들의 타입이 동일하지 않을 경우 피연산자들의 타입을 일치시킨 후 연산을 수행한다
자바 가상 기계 (JVM)가 기본적으로 32비트 단위로 계산하기 때문에 long을 제외한 정수는 모두 int로 계산한다.
ex)
byte byte1 = 1;
byte byte2 = 2;
byte byte3 = byte1 + byte2; // 컴파일 에러
// long 타입을 제외한 정수의 산술 연산은 무조건 int 타입으로 변환 후 연산을 수행하고,
// 산출 타입도 int 이기 때문
int result = byte1 + byte2; // 이게 맞는 코드
//2.5를 얻고 싶다면, 아래와 같이 피연산자 중 최소한 하나는 실수 타입이어야 함
int int1 = 10;
int int2 = 4;
int result2 = int1 / int2; // 2
double result3 = int1 / int2; // 2.5가 아닌 2.0
//char 타입도 정수 타입이므로 산술 연산이 가능함 (결과는 int)
double result3 = (int1*1.0) / int2;
double result3 = (double) int1 / int2;
double result3 = int1 / (double) int2;
char c1 = 'A' + 1;
char c2 = 'A';
char c3 = c2 + 1; // 컴파일 에러
// char를 얻고 싶으면, 강제 타입 변환 (캐스팅) 필요
char c4 = (char) (c2 + 1);
오버플로우 탐지
정확한 계산은 정수 사용
NaN 과 Infinity 연산
5 / 0.0 => Infinity
5 % 0.0 => NaN
입력값의 NaN 검사
비트 연산자는 피연산자를 비트단위로 논리 연산한다. 피연산자를 이진수로 표현했을 때의 각 자리를 규칙에 따라 연산을 수행하며, 피연산자로 실수는 허용하지 않는다. 오직 정수(문자 포함)만 허용된다.
구분
관계 연산자(Relational Operator) 또는 비교 연산자(Comparing Operator)라 불리는 연산자는 두 피연산자를 비교하는 데 사용되는 연산자이다. 주로 조건문과 반복문의 조건식에 사용되며, 연산결과는 오직 true와 false 둘 중의 하나이다.
두 피연산자의 값의 크기를 비교하는 연산자로 참이면 true를, 거짓이면 false를 반환한다.
두 피연산자의 값이 같은지 또는 다른지를 비교하는 연산자이다.
기본형의 경우 변수에 저장되어 있는 값이 같은지를 알 수 있고, 참조형의 경우 객체의 주소값을 저장하기 때문에 두 개의 피연산자(참조변수)가 같은 객체를 가리키고 있는지를 알 수 있다.
논리 연산자는 둘 이상의 조건을 ‘그리고(AND)’나 ‘또는(OR)’으로 연결하여 하나의 식으로 표현할 수 있게 한다.
instanceof연산자는 참조변수가 참조하고 있는 인스턴스의 실제 타입을 알아보기 위해 사용한다.
주로 조건문에 사용되며 좌측에는 참조변수가, 우측에는 타입(클래스명)이 피연산자로 위치한다.
연산 결과로 boolean값인 true와 false 중의 하나를 반환한다. 값이 null인 참조변수에 대해 수행할 경우 false를 결과로 얻는다.
instanceof를 이용한 연산결과로 true를 얻었다는 것은 참조변수가 검사한 타입으로 형변환이 가능하다는 것을 뜻한다.
조상타입의 참조변수로 자손타입의 인스턴스를 참조할 수 있기 때문에, 참조변수의 타입과 인스턴스의 타입이 항상 일치하지는 않는다.
ex)
public void method(Parent parent) {
// Parent 매개변수가 참조하는 객체가 Child인지 조사
if (parent instanceof Child) {
Child child = (Child) parent;
}
}
대입 연산자(assignment operator)는 변수와 같은 저장공간에 값 또는 수식의 연산결과를 저장하는데 사용된다.
이 연산자는 오른쪽 피연산자의 값(식이라면 평가값)을 왼쪽 피연산자에 저장한다. 그리고 저장된 값을 연산결과로 반환한다.
대입 연산자는 연산자들 중에서 가장 낮은 우선순위를 가지고 있기 때문에 식에서 가장 마지막에 수행된다.
연산 진행 방향이 오른쪽에서 왼쪽이기 때문에 x = y = 3;을 시행하면 y = 3이 먼저 수행되고 x = y가 수행된다.
람다식(Lambda expression)은 메서드를 하나의 ‘식(expression)’으로 표현한 것이다.
메서드를 람다식으로 표현하면 메서드의 이름과 반환 값이 없어지므로, 람다식을 ‘익명 함수(anonymous function)’라고도 한다.
ex)
int[] arr = new int[5];
Arrays.setAll(arr, (i) -> (int)(Math.random() * 5) + 1);
모든 메서드는 클래스에 포함되어야 하므로 클래스를 생성하고, 객체도 생성해야만 메서드를 호출할 수 있다.
그러나 람다식은 이 모든 과정없이 람다식 자체만으로도 메서드의 역할을 대신할 수 있다.
람다식은 메서드의 매개변수로 전달되어지는 것이 가능하고, 메서드의 결과로 반환될 수도 있다. 람다식으로 인해 메서드를 변수처럼 다루는 것이 가능해진 것이다.
자세한 설명은 Java8 시리즈에서 다루도록 하겠다
조건 연산자 ? :는 조건식, 식1, 식2 총 세 개의 피연산자를 필요로 하는 3항 연산자이며, 조건 연산자가 유일한 3항 연산자이다.
조건 연산자는 첫 번째 피연산자인 조건식의 평가결과에 따라 다른 결과를 반환한다. 조건식의 평가결과가 true이면 식1이, false이면 식2가 결과로 반환된다.
ex)
result = (x > y) ? x : y; // x > y가 true이면 x, false이면 y가 변수 result에 저장된다.
식에 사용된 연산자가 둘 이상인 경우, 연산자의 우선순위에 의해서 연산순서가 결정된다.
수학에서 배웠듯이 곱셈과 나눗셈(*, /)이 덧셈과 뺄셈(+, -)보다 우선순위가 높다는 것을 알고 있다.
Java 12에서 Switch문이 확장되었다.
case에 복수의 값을 설정할 수 있게 되었다.
switch(weekday) {
case MONDAY, FRIDAY:
time = "10:00 - 18:00";
break;
case TUESDAY, THURSDAY:
time = "10:00 - 14:00";
break;
default:
time = "휴일";
}
지시자(->)를 사용하여 break를 생략할 수 있게 되었다.
String time;
switch(weekday) {
case MONDAY, FRIDAY -> time = "10:00 - 18:00";
case TUESDAY, THURSDAY -> time = "10:00 - 14:00";
default -> time = "휴일";
}
String time;
switch(weekday) {
case MONDAY, FRIDAY -> {
var endTime = getEndTime();
time = "10:00 - " + endTime;
}
case TUESDAY, THURSDAY -> time = "10:00 - 14:00";
default -> time = "휴일";
}
Switch를 식으로도 사용할 수 있다. 지시자 문법을 사용하지 않는 경우나 지시자 문법에 블록을 사용한 경우 break로 값을 반환한다.
String time = switch(weekday) {
case MONDAY, FRIDAY -> {
var endTime = getEndTime();
break "10:00 - " + endTime;
}
case TUESDAY, THURSDAY -> "10:00 - 14:00";
default -> "휴일";
};
break로 값을 반환하는 문법이 yield로 변경되었다.
Java 12
String result = switch(code) {
case 1:
break "code 1";
case 2:
break "code 2";
default:
break "default";
};
System.out.println(result);
Java 13
String result = switch(code) {
case 1:
yield "code 1";
case 2:
yield "code 2";
default:
yield "default";
};
System.out.println(result);
참조