코틀린을 배우기 위해서 인프런에서 강의를 구매하고 코틀린과 친해지고 기본기를 다지기 위해서 공부하는 중이다. 글 내용은 연산자를 다루는 방법이고 최태현님의 자바 개발자를 위한 코틀린 입문(Java to Kotlin Starter Guide) 강의에 소금을 조금 친 내용이다
단항 연산자 (++, –)
var a = 5
var b = 5
println(++a) // 6 (전위 증가)
println(a++) // 6 (후위 증가, a는 7이 됨)
println(--b) // 4 (전위 증가)
println(b--) // 4 (후위 증가, a는 3이 됨)
산술 연산자 (+, -, *, /, %)
val x = 10
val y = 3
println(x + y) // 13 (덧셈)
println(x - y) // 7 (뺄셈)
println(x * y) // 30 (곱셈)
println(x / y) // 3 (나눗셈)
println(x % y) // 1 (나머지)
산술대입 연산자 ( +=, -=, *=, /=, %=)
var num = 10
num += 5 // num = num + 5, 결과: 15
num -= 3 // num = num - 3, 결과: 12
num *= 2 // num = num * 2, 결과: 24
num /= 4 // num = num / 4, 결과: 6
num %= 5 // num = num % 5, 결과: 1
println(num) // 1
JavaMoney Record
public record JavaMoney(long amount) implements Comparable<JavaMoney> {
public JavaMoney plus(JavaMoney other) {
return new JavaMoney(this.amount + other.amount);
}
@Override
public int compareTo(JavaMoney o) {
return Long.compare(this.amount, o.amount);
}
}
KotlinMoney data class
data class KotlinMoney (
val amount: Long
) {
operator fun plus(another: KotlinMoney): KotlinMoney {
return KotlinMoney(this.amount + another.amount)
}
}
비교 연산자 (>, <, >=, <=)
// Java
JavaMoney money1 = new JavaMoney(2_000L);
JavaMoney money2 = new JavaMoney(1_000L);
// 비교 시 compareTo 직접 호출
if (money1.compareTo(money2) > 0) {
System.out.println("money1이 money2보다 금액이 큽니다");
}
// Kotlin
val money1 = JavaMoney(2_000L)
val money2 = JavaMoney(1_000L)
// 직관적인 비교 연산자
if (money1 > money2) {
println("money1이 money2보다 금액이 큽니다")
}
동일성과 동등성
동일성(Identity)
- 두 객체의 메모리 상에서 같은 객체(Object)를 가르키는지를 비교하는 개념(주소 비교)으로 “나와 내 클론”처럼 유전자까지 똑같은 것 (메모리 주소 동일)
- C 언어의 포인터 비교와 유사하게, 결국 같은 메모리 주소를 가리키고 있는지를 확인하는 것이다
- 원본과 사본이 아닌, 완전히 동일한 원본 자체인지 확인하는 것과 같다
동등성(Equality)
- 두 객체가 같은 값(Value)을 가지는지 비교하는 개념(내용 비교)으로 “나와 내 도플갱어”처럼 겉모습만 똑같은 것(객체의 값 동일)
- 겉모습과 내용은 같지만, 실제로는 독립적인 별개의 것인지 확인하는 것과 같다
Java 동일성과 동등성
JavaMoney money3 = new JavaMoney(1_000L);
JavaMoney money4 = money3; // 같은 객체 참조
JavaMoney money5 = new JavaMoney(1_000L); // 새로운 객체
// 동일성 (같은 객체인가)
System.out.println(money3 == money4); // true - 같은 참조
System.out.println(money3 == money5); // false - 다른 객체
// 동등성 (값이 같은가)
System.out.println(money3.equals(money5)); // true - 같은 값
Kotlin 동일성과 동등성
val money3 = JavaMoney(2_000L)
val money4 = money3 // 같은 객체 참조
val money5 = JavaMoney(2_000L) // 새로운 객체
// 동일성 (같은 객체인가)
println("money3와 money4는 같은 객체: " + (money3 === money4)) // true - 같은 참조
println("money3와 money5는 같은 객체: " + (money3 === money5)) // false - 다른 객체
// 동등성 (값이 같은가)
println("money3와 money5는 같은 값: " + (money3 == money5)) // true - 같은 값 (내부적으로 equals 호출)
논리 연산자 (&&, !!, !)
&& (논리 AND)
val a = true
val b = false
println(a && b) // false
println(true && true) // true
|| (논리 OR)
val x = true
val y = false
println(x || y) // true
println(false || false) // false
! (논리 NOT)
val isLoggedIn = false
println(!isLoggedIn) // true
println(!true) // false
단축 평가(Short-circuit evaluation)
fun main() {
// OR 연산 ||
if(fun1() || fun2()) {
println("OR 조건문 본문 실행")
}
// AND 연산 (&&)
if (fun2() && fun1()) {
println("AND 조건문 본문 실행") // 실행되지 않음
}
}
fun fun1(): Boolean {
println("fun1() 호출됨 - true 반환")
return true
}
fun fun2(): Boolean {
println("fun2() 호출됨 - false 반환")
return false
}
OR 연산 (||) – 단축 평가
- fun1()이 true 반환 → 전체 결과가 true로 확정
- fun2()는 호출되지 않음(단축 평가)
AND 연산 (&&) – 단축 평가
- fun2()가 false 반환 → 전체 결과가 false로 확정
- fun1() 호출되지 않음(단축 평가)
in, !in 연산자
val numbers = listOf(1, 2, 3, 4, 5)
val fruits = setOf("사과", "바나나", "오렌지")
println(3 in numbers) // true
println(6 in numbers) // false
println("사과" in fruits) // true
println("포도" !in fruits) // true
범위 연산자 (a..b)
val range1 = 1..5 // 1, 2, 3, 4, 5
val range2 = 'a'..'z' // a부터 z까지
for (i in 1..3) {
println(i) //1, 2, 3 출력
}
// 역순 범위
for (i in 5 downTo 1) {
println(i) // 5, 4, 3, 2, 1
}
// 간격 지정
for (i in 1..10 step 2) {
println(i) // 1, 3, 5, 7, 9
}
// 마지막 값 제외
for (i in 1 until 5) {
println(i) // 1, 2, 3, 4, (5 제외)
}
인덱싱 연산자 (a[i], a[i] = b)
// 값 가져오기 (get)
val str = "ABCDE"
val numbers = listOf(10, 20, 30)
val map = mapOf("name" of "홍길동", "age" to "30")
println(str[0]) // A
println(numbers[1]) // 20
println(map["name"]) // 홍길동
// 값 할당하기 (set)
val mutableList = mutableListOf(1, 2, 3)
val mutableMap = mutableMapOf("a" to 1, "b" to 2)
val array = arrayOf(1, 2, 3, 4, 5)
mutableList[0] = 10 // [10, 2, 3]
mutableMap["a"] = 100 // {"a"=100, "b"=2}
array[2] = 30 // [1, 2, 30, 4, 5]
println(mutableList) // [10, 2, 3]
연산자 오버로딩
- Kotlin에서는 연산자 오버로딩을 지원한다. 객체마다 연산자를 직접 정의할 수 있다
- 연산자 오버로딩은 기존 연산자에 새로운 의미를 부여하는 것
- 일반적으로 연산자들은 숫자에 대해서만 동작. 하지만 연산자 오버로딩을 통해 사용자 정의 클래스에서도 이러한 연산자들이 의미있게 동작하도록 만들 수 있다
- 타입별로 다른 의미와 동작을 가질 수 있게 하는 것이 연산자 오버로딩
- Int에서는 수학적 덧셈
- String에서는 문자열 연결
- Money에서는 금액 합계
- List에서는 리스트 합치기
출처 – 인프런 강의 중 자바 개발자를 위한 코틀린 입문(Java to Kotlin Starter Guide)