연산자
Operator
연산자 (Operator)
산술연산자
- Binary Operator(이항)
- 덧셈 (Addition,
+)- 피연산자 중 하나가 문자열이면 다른 피연산자는 문자열로 변환되어 수행됨
System.out.println("Total: " + 3 + 4); // Total: 34 System.out.println("Total: " + (3 + 4)); // Total: 7 - 뺄셈 (Subtraction,
-) - 곱셈 (Multiplication,
*) - 나눗셈 (Division,
/)- 결과는 integer, 값을 잃을 수도 있다.
- 0으로 나누게 되면
ArithmeticException발생
7 / 3 // 2 7 / 3.0f // 2.33333f 7 / 0 // ArithmeticException!! 7 / 0.0 // positive infinity 0.0/0.0 // NaN - 나머지 연산 (Modulo,
%)- 한 숫자를 다른 숫자로 나눈 후 나눗셈의 나머지 또는 부호있는 나머지를 반환
7 % 3 // 1 4.3 % 2.1 // 0.1 4 % 0 // ArithmeticException !! 4 % 0.0 // NaN
비트연산자 (bitwise operator) & Shift Operators
- Binary Operator(이항)
- bit 단위로 논리 연산을 할 때 사용하는 연산자, 비트 단위로 전체 비트를 왼쪽이나 오른쪽으로 이동시킬 때도 사용함.
- floating-point, boolean, array, object 는 비트 연산자를 사용할 수 없음
- 결과는 int값이나 연산자 중 하나가 long이면 결과는 long 이다.
~(비트NOT연산)- 비트를 1이면 0으로, 0이면 1로 반전시킴
byte b = ~12; // ~00001100 => 11110011 ( or -13 decimal)&(비트AND연산)- 대응되는 비트가 모두 1이면 1을 반환
10 & 7 // 00001010 & 00000111 => 00000010 (or 2)|(비트OR연산)- 대응되는 비트 중에서 하나라도 1이면 1 반환
10 | 7 // 00001010 | 00000111 => 00001111 (or 15)^(비트XOR연산)- 대응되는 비트가 서로 다르면 1 반환
10 ^ 7 // 00001010 ^ 00000111 => 00001101 (or 13)-
<<(Left Shift연산)💡 x « n 은 x * 2^n 의 결과와 같다.
- 지정한 수만큼 비트들을 전부 왼쪽으로 이동시킴
10 << 1 // 0b00001010 << 1 = 00010100 = 20 = 10*2 7 << 3 // 0b00000111 << 3 = 00111000 = 56 = 7*8 -1 << 2 // 0xFFFFFFFF << 2 = 0xFFFFFFFC = -4 = -1*4 // 0xFFFF_FFFC == 0b1111_1111_1111_1111_1111_1111_1111_1100 -
>>(Right Shift 연산)💡 x » n 은 x / 2^n 의 결과와 같다.
- 부호를 유지하면서 지정한 수만큼 비트를 전부 오른쪽으로 이동시킴
10 >> 1 // 00001010 >> 1 = 00000101 = 5 = 10/2 27 >> 3 // 00011011 >> 3 = 00000011 = 3 = 27/8 -50 >> 2 // 11001110 >> 2 = 11110011 = -13 != -50/4
관계연산자
- 개념
- 비교 연산자라고도 함
- 두개의 변수 또는 리터럴을 비교하는 데 사용되는 연산자
- 연산결과는
true또는false - 이항연산자이므로 비교하는 피연산자의 자료형이 서로 다를 경우에는 자료형의 범위가 큰 쪽으로 형변환하여 피연산자의 타입을 일치시킨 후 비교한다.
-
대소비교 연산자
> : 왼쪽 항이 크면 true, 아니면 false 반환 < : 왼쪽 항이 작으면 true, 아니면 false 반환 >= : 왼쪽 항이 오른쪽 항보다 크거나 같으면 true, 아니면 false 반환 -
등가비교 연산자
== : 두개 항의 값이 같으면 true, 아니면 false 반환 != : 두개 항이 다르면 true, 아니면 false 반환
논리연산자
- 조건문과 반복문에서 조건식 간의 결합에 사용
- 피연산자로
boolean형 또는boolean형 값을 결과로 하는 조건식만 허용
- 피연산자로
&&가||연산보다 우선순위가 높으므로 한 조건식에 같이 사용할 때는 괄호를 사용하여 우선순위를 명확히 해 줘야 한다.- 효율적인 연산을 함
||연산의 경우 어느 한 쪽만true여도 전체 연산결과가true이므로 좌측의 피연산자가true이면 우측의 피연산자 값은 검사하지 않는다.&&연산의 경우 어느 한쪽만false여도 전체 연산결과가false이므로 좌측의 피연산자가false이면 우측의 피연산자 값은 검사하지 않는다.- 연산 속도를 위해 단락회로평가(short circuit evaluation)를 고려 하여 코딩하는 것이 좋음.
&또는|을 사용한다면 양쪽 다 평가한다.
&& (논리곱) : 두 항이 모두 true인 경우에만 true, 아니면 false 반환
|| (논리합) : 두 항 중 하나의 항이 true이면 결과 값은 true, 아니면 flase 반환
- 논리부정연산자 (단항연산자)
! (부정) : true를 false로 바꾸고, false인 경우 true로 변경
instanceof Operator
참조변수가 참조하는 인스턴스의 실제 타입을 체크하는데 사용하는 연산자이다.
연산결과는 true 또는 false이다. true이면 해당 타입으로 형변환이 가능하다.
"string" instanceof String // True (all strings are instances of String)
"" instanceof Object // True (strings are also instances of Object)
null instanceof String // False (null is never an instance of anything)
Object o = new int[] {1,2,3};
o instanceof int[] // True (the array value is an int array)
o instanceof byte[] // False (the array value is not a byte array)
o instanceof Object // True (all arrays are instances of Object)
다형성을 통해 조상타입의 참조변수로 자손타입의 인스턴스를 가리킬 수 있게 되었기 때문에 참조변수의 타입과 참조변수가 가리키는 인스턴스의 타입이 항상 같지는 않는다.
따라서 참조변수가 가르키는 인스턴스 타입이 어떤 것인지 확인하기 위해서 instanceof 연산자를 사용하는 것
// Use instanceof to make sure that it is safe to cast an object
if (object instanceof Test) {
Test t = (Test) object
}
assignment operator
변수에 값 또는 수식의 연산결과를 저장(in 메모리)하는데 사용한다. 왼쪽에는 반드시 변수가 위치해야 하며, 오른쪽에는 리터럴이나 변수 또는 수식이 올 수 있다.
연산 진행 방향이 오른쪽에서 왼쪽 (←) 이다. (right-associative)
a=b=c⇒a=(b=c)
기본적인 assignment operator 는 = 이다. (equality operator 인 == 와 혼동 주의)
또한 다른 연산자와 결합하여 op= 와 같은 방식으로 사용이 가능하다.
i = i + 3 => i += 3
i *= 10 + j => i = i * (10 + j)
...
+= -= *= /= %= // Arithmetic operators plus assignment
&= |= ^= // Bitwise operators plus assignment
<<= >>= >>>= // Shift operators plus assignment
x +=2와x = x+2는 거의 같다, 다만op=형식을 쓸 때 왼쪽피연산자가 한번만 evaluated 된다.
Lambda expression (→)
람다 표현식은 실행 가능한 자바 코드의 anonymous collection 으로, 메서드와 비슷하지만 이름이 필요하지 않고 method body에서 바로 구현이 가능한 표현식이다.
TestSomething test = () -> System.out.println("Hello, Lamda");
자바는 객체지향 언어이기 때문에 위 람다식을 변수에 할당 가능하고, 메서드의 파라미터로 전달 및 리턴타입으로 리턴할 수 있다. (람다식 자체를 리턴 또한 가능하다.)
표현 방법
(인자 리스트) → { body }
인자리스트
- 인자 리스트는 없을 수도 있고, 한개 또는 여러개 일수도 있다.
- 인자의 타입은 생략 가능, 컴파일러가 infer(추론) 하지만 명시할 수도 있다.
(String str, Integer one)
1. 인자가 없는 경우: () -> { body } // 구현해야 할 추상메서드가 파라미터를 아무것도 받지 않을 때
2. 인자가 한개인 경우: (one) or one -> { body }
3. 인자가 여러개인 경우: (one, two) -> { body }
바디
- 화살표 오른쪽에 함수 내용을 구현한다.
- 코드가 한줄인 경우
{}를 생략 가능하고,return도 생략 가능하다. - 코드가 여러 줄인 경우
{}를 사용하여 묶는다.
특징
💡
final또는effective final인 경우에만 로컬 변수 참조 가능 람다는 람다를 감싸는 별도의 scope 이 존재하여 쉐도잉을 하지 않는다.
-
로컬변수 참조 (local variable capture) 란
private void run() { final int baseNumber = 25; // 로컬클래스 class LocalClass { void printBaseNumber() { System.out.println(baseNumber); // 로컬변수 참조 } } // 익명클래스 Consumer<Integer> integerConsumer = (i) -> { System.out.println(baseNumber) // 로컬 변수 참조 }; } -
람다의 로컬변수 참조
람다 표현식을 사용할 때 local variable capture를 하려면 그 변수가
final이거나effective final인 경우에만 참조할 수 있다.-
effective final
자바 8부터 지원하는 기능으로 사실상
final인 변수이다.final키워드를 사용하지 않은 변수를 익명클래스 구현체 또는 람다에서 참조할 수 있다.
private void run() { int baseNumber = 25; // effective final IntConsumer printInt = (i) -> { System.out.println(i + baseNumber); // 참조 가능 } // 컴파일 에러 발생 IntConsumer printNotFinal = (~~baseNumber~~) -> { // Variable 'baseNumber' System.out.println(baseNumber) // is already defined }; // in the scope }위 에러가 발생하는 이유는 다음과 같다.
💡 람다는 run() 메소드와 scope이 같음 (쉐도잉이 적용 안됨)
→ 같은 scope에서는 동일한 변수명을 사용할 수 없음 (concurrency 문제 발생 할 수있음)
→ 컴파일에러 발생-
쉐도잉이란 ?
private void run() { // ① int baseNumber = 25; // 로컬클래스 class LocalClass { void printBaseNumber() { // ② int baseNumber = 12; System.out.println(baseNumber); // 12 출력 } } // 익명클래스 Consumer<Integer> integerConsumer = (i) -> { int baseNumber = 12; System.out.println(baseNumber) // 12 출력 }; }위 코드에서 로컬클래스와 익명클래스는 run() 메소드 안에 있지만 run 메소드 scope과 다른 scope에 있어서 ①
baseNumber가 ②baseNumber로 가려져서 12가 출력이 된다. 이 것을 쉐도잉 이라 한다.
-
Conditional operator
삼항연산자는 세 개의 피연산자를 필요로 하기 때문에 삼항 연산자라 불린다.
if문 으로 바꿔 쓸 수 있으며 간단한 if문을 삼항 연산자로 사용하면 코드를 보다 간단히 할 수 있다.
표현방법
-
조건식 ? 피연산자1 : 피연산자2int max = (x > y) ? : x : y; String name = (name != null) ? name : "unknown"조건식의 연산 결과가
true이면 결과가피연산자1,false이면피연산자2가 결과값이 된다.피연산자들에는 주로 값이 오지만 경우에 따라 연산식이 올 수도 있다.
-
if문 ↔ 삼항연산자
// if문 사용
if (x > 0 ) {
result = x;
} else {
result = -x;
}
// 삼항연산자 사용
result = (x > 0 ) ? x : -x;
연산 진행방향
3 * 4 * 5 // 연산 진행방향이 왼쪽에서 오른쪽인 경우 ① (3 * 4) ② 12 * 5
x = y = 3 // 연산 진행방향이 오른쪽에서 왼쪽인 경우 ① y = 3 ② x = y
- 산술 > 비교 > 논리 > 대입 (대입은 제일 마지막에 수행)
- 단항 (1) > 이항(2) > 삼항(3) (단항 연산자의 우선순위가 이항 연산자보다 높다)
- 단항 연산자와 대입 연산자를 제외한 모든 연산의 진행방향은 왼쪽에서 오른쪽이다.
1. -x + 3 // 단항 연산자가 이항 연산자보다 우선순위가 높음 -> x의 부호를 바꾼 다음 덧셈 수행
// - 는 뺄셈 연산자가 아니라 부호 연산자임.
