-
1. 코틀린에서 변수와 타입, 연산자를 다루는 방법Kotlin/자바 개발자를 위한 코틀린 입문 2023. 7. 5. 17:25
1. 코틀린에서 변수를 다루는 방법
1. 변수 선언 키워드 - var과 val의 차이점
- java에서 long과 final long의 차이!
ㆍ이 변수는 가변인가, 불변인가(read-only)
- 코틀린에서는 모든 변수에 수정 가능 여부(var / val)를 명시해주어야 한다.
fun main() { var number1 = 10L // 바꿀 수 있는 변수 val number2 = 10L // 바꿀 수 없는 변수 }
- 코틀린에서는 타입을 추론해주지만 명시적으로 작성해줄 수도 있다.
fun main() { var number1: Long = 10L // 바꿀 수 있는 변수 val number2: Long = 10L // 바꿀 수 없는 변수 }
- 초기값을 지정해주지 않는 경우에는 타입을 명시해주고, 값을 넣어 주지 않고 사용하려고 하면 이 변수는 무조건 초기화 되어야 한다라는 에러가 발생.
var number: Int println(a) // 컴파일 에러 발생, Variable 'number' must be initialize
- val 컬렉션에는 element를 추가할 수 있다.
- 간단한 TIP
ㆍ 모든 변수는 우선 val로 만들고 꼭 필요한 경우 var로 변경한다.
2. Kotlin에서의 Primitive Type
- Kotlin에서는 모두 Long인데? 성능상 문제는 없는 것인가?
ㆍ숫자, 문자, 불리언과 같은 몇몇 타입은 내부적으로 특별한 표현을 갖는다.
ㆍ이 타입들은 실행시에 Primitive Value로 표현되지만, 코드에서는 평범한 클래스처럼 보인다.
ㆍ즉, 프로그래머가 boxing / unboxing 을 고려하지 않아도 되도록 Kotlin이 알아서 처리 해준다.
3. Kotlin에서의 nullable 변수
- kotlin에서 null이 변수에 들어갈 수 있다면 "타입?" 를 사용해야 한다.
var number5: Long? = 1_000L number5 = null
4. Kotlin에서의 객체 인스턴스화
- Kotlin에서 객체 인스턴스화를 할 때에는 new를 붙이지 않아야 한다.
val person = Person("박현민")
정리
- 모든 변수는 var / val을 붙여 주어야 한다.
ㆍvar : 변경 가능하다 / val : 변경 불가능하다 (read-only)
- 타입을 명시적으로 작성하지 않아도, 타입이 추론된다.
- Primitive Type과 Reference Type을 구분하지 않아도 된다.
- Null이 들어갈 수 있는 변수는 타입 뒤에 ? 를 붙여주어야 한다.
ㆍ아예 다른 타입으로 간주된다.
- 객체를 인스턴스화 할 때 new를 붙이지 않아야 한다.
2. 코틀린에서 null을 다루는 방법
1. Kotlin에서의 null 체크
- Kotlin에서는 null이 가능한 타입을 완전히 다르게 취급한다!
2. Safe Call과 Elvis 연산자
- null이 가능한 타입만을 위한 기능은 없나?!
- Safe Call
ㆍnull 이 아니면 실행하고, null이면 실행하지 않는다 ( 그대로 null )
val str: String? = "ABC" str.length // 불가능 str?.length // 가능
- Elvis 연산자
ㆍ앞의 연산 결과가 null이면 뒤의 값을 사용
val str: String? = "ABC" str?.length ?: 0
- Elvis 연산은 early return엗 사용할 수 있다!
// java public long calculate(Long number) { if(number == null) { return 0; } // 다음 로직 } // kotlin fun calculate(number: Long?): Long { number ?: return 0 // 다음 로직 }
3. 널 아님 단언!!
- nullable type이지만, 아무리 생각해도 null이 될 수 없는 경우
fun startsWithA1(str: String?): Boolean { return str!!.startsWith("A") }
- 혹시나 null이 들어오면 NPE가 나오기 떄문에 정말 null이 아닌게 확실한 경우에만 널 아님 단언!! 을 사용해야 한다.
4. 플랫폼 타입
- Kotlin에서 Java 코드를 가져다 사용할 때 어떻게 처리할까?!
ㆍjavax.annotation 패키지
ㆍandroid.support.annotation 패키지
ㆍorg.jetbrains.annotation 패키지
- @Nullable이 없다면?!!
ㆍKotlin에서는 이 값이 nullable인지 non-nullable인지 알 수가 없다
- 플랫폼 타입
ㆍ코틀린이 null 관련 정보를 알 수 없는 타입 Runtime 시 Exception이 날 수 있다.
* 코틀린에서 자바 코드를 사용할 때는 null 관련 정보를 꼼꼼히 작성하고, 라이브러리의 경우도 null값이 들어갈 수 있는지 없는 지 확인할 것
* 최초에 코틀린에서 자바 라이브러리를 가져다 쓴 지점을 랩핑해서 단일 지점으로 만듦으로써 추후에 뭔가 이슈가 났을 때 좀 더 쉽게 대응할 수 있게 하면 좋다.
정리
- 코틀린에서 null이 들어갈 수 있는 타입은 완전히 다르게 간주된다.
ㆍ한 번 null 검사를 하면 non-null임을 컴파일러가 알 수 있다.
- null이 아닌 경우에만 호출되는 Safe Call (?.) 이 있다.
- null인 경우에만 호출되는 Elvis 연산자(?:) 가 있다.
- null이 절대 아닐때 사용할 수 있는 널 아님 단언(!!) 이 있다.
- Kotlin에서 Java 코드를 사용할 때는 플랫폼 타입 사용에 유의해야 한다.
ㆍJava 코드를 읽으면 널 가능성 확인 / Kotlin으로 Wrapping
3. 코틀린에서 Type을 다루는 방법
1. 기본 타입
- Byte, Short, Int, Long, Float, Double, 부호없는 정수들
- 코틀린에서는 선언된 기본값을 보고 타입을 추론한다.
- Java와 다른 내용
ㆍJava : 기본 타입간의 변환은 암시적으로 이루어질 수 있다.
int number1 = 4; long number2 = number1; System.out.println(number1 + number2);
ㆍKotlin : 기본 타입간의 변화은 명시적으로 이루어져야 한다.
val number1 = 4 // val number2: Long = number1 //Type mismatch val number2: Long = number1.toLong() println(number1 + number2)
- kotlin에서 타입 변환 시 to변환타입() 을 사용해야 한다.
- 변수가 nullable이라면 적절한 처리가 필요하다!
val number3: Int? = 3 val number4: Long = number3?.toLong() ?: 0L
2. 타입 캐스팅
- 기본 타입이 아닌 일반 타입은 어떨까?
fun printAgeIfPerson(obj: Any) { if(obj is Person) { println(obj.age) // 스마트 캐스트 // val person = obj as Person // println(person.age) } }
- value is Type
ㆍvalue가 Type이면 → true
ㆍvalue가 Type이 아니면 → false
- value !is Type
ㆍvalue가 Type이면 → false
ㆍvalue가 Type이 아니면 → ture
- value as Type
ㆍvalue가 Type 이면 → Type으로 타입 캐스팅
ㆍvalue가 Type이 아니면 → 예외발생(ClassCastException)
- value as? type
ㆍvalue가 Type 이면 → Type으로 캐스팅
ㆍvalue가 null이면 → null
ㆍvalue가 Type 아니면 → null
3. Kotlin의 3가지 특이한 타입
- Any
ㆍJava의 Object 역할. (모든 객체의 최상위 타입)
ㆍ모든 Primitive Type의 최상의 타입도 Any이다.
ㆍAny 자체로는 null을 포함할 수 없어 null을 포함하고 싶다면, Any?로 표현.
ㆍAny 에 equals / hashCode / toString 존재
- Unit
ㆍUnit은 Java의 void와 동일한 역할
ㆍ(살짝 어려운 내용) void와 다르게 Unit은 그 자체로 타입 인자로 사용 가능하다
ㆍ함수형 프로그래밍에서 Unit 은 단 하나의 인스턴스만 갖는 타입을 의미.
즉, 코틀린의 Unit은 실제 존재하는 타입이라는 것을 표현
- Nothing
ㆍNothing은 함수가 정상적으로 끝나지 않았다는 사실을 표현하는 역할
ㆍ무조건 예외를 반환하는 함수 / 무한 루프 함수 등
fun fail(message: String): Nothing { throw IllegalArgumentException(message) }
4. Stirng Interpolation, String indexing
// java1 Person person = new Person("박현민", 27); String log = String.format("사람의 이름은 %s이고 나이는 %s세 입니다", person.getName(), person.getAge()); // java2 StringBuilder builder = new StringBuilder(); builder.append("사람의 이름은"); builder.append(person.getName()); builder.append("이고 나이는"); builder.append(person.getAge()); buidler.append("세 입니다");
val person = Person("박현민", 27) val log = "사람의 이름은 ${person.name}이고 나이는 ${person.age}세 입니다"
- ${변수} 를 사용하면 값이 들어간다.
- TIP
ㆍ변수 이름만 사용하더라도 ${변수}를 사용하는 것이 1) 가독성 2) 일관 변환 3) 정규식 활용 측면에서 좋았다.
ㆍ코틀린 공식 코딩 컨벤선은 $변수 사용
val str = """ ABC """.trimIndent() println(str)
val str2 = "ABCDE" val ch = str[1]
정리
- 코틀린의 변수는 초기값을 보고 타입을 추론하며, 기본 타입들 간의 변환은 명시적으로 이루어진다.
- 코틀린에서는 is, !is, as, as? 를 이용해 타입을 확인하고 캐스팅한다.
- 코틀린에서 Any는 Java의 Object와 같은 최상위 타입이다.
- 코틀린의 Unit은 Java의 void와 동일하다
- 코틀린에 있는 Nothing은 정상적으로 끝나지 않은 함수의 반환을 의미한다.
- 문자열을 가공할 때 ${변수}와 """ """ 를 사용하면 깔끔한 코딩이 가능하다.
- 문자열에서 문자를 가져올때의 Java의 배열처럼 []를 사용한다.
4. 코틀린에서 연산자를 다루는 방법
1. 단항 연산자 / 산술 연산자
- 단항 연산자 : ++ , --
- 산술 연산자 : +, -, *, /, %
- 산술대입 연산자 : +=, -=, *=, /=, %=
→ 자바, 코틀린 완전 동일
- 비교 연산자 : >, <, >=, <=
→ Java, Kotlin 사용법은 동일하다.
단, Java와 다르게 객체를 비교할 때 비교 연산자를 사용하면 자동으로 compareTo를 호출해준다.
2. 비교 연산자와 동등성, 동일성
- 동등성(Equality) : 두 객체의 값이 같은가?!
- 동일성(Identity) : 완전히 동일한 객체인가?! 즉 주소가 같은가?!
- Java 에서는 동일성에 == 를 사용, 동등성에 equals를 직접 호출
- Kotlin에서는 동일성에 === 를 사용, 동등성에 ==를 호출
ㆍ==를 사용하면 간접적으로 equals를 호출해준다.
3. 논리 연산자 / 코틀린에 있는 특이한 연산자
- 논리 연산자 : &&, ||, !
→ Java와 완전히 동일하다. Java처럼 Lazy 연산을 수행한다.
if (fun1() || fun2()) { println("본문") }
- fun1()이 true 이면 fun2()는 실행 X → Lazy 연산
- in / !in
ㆍ컬렉션이나 범위에 포함되어 있다, 포함되어 있지 않다.
println(1 in numbers)
- a..b
ㆍa부터 b까지의 범위 객체를 생성한다.
- a[i]
ㆍa에서 특정 Index i로 값을 가져온다
val str = "ABC" println(str[2]) //C
- a[i] = b
ㆍa의 특정 index i에 b를 넣는다.
4. 연산자 오버로딩
- Kotlin에서는 객체마다 연산자를 직접 정의할 수 있다.
val money3 = Money(1_000L) val money4 = Money(2_000L) println(money3 + money4) // Money(amount=3000)
정리
- 단항연산자, 산술연산자, 산술대입연산자 Java와 똑같다
- 비교 연산자 사용법도 Java와 똑같다
ㆍ단, 객체끼리도 자동 호출되는 compareTo를 이용해 비교 연산자를 사용할 수 있다.
- in, !in / a..b / a[i] / a[i] = b 와 같이 코틀린에서 새로 생긴 연산자도 있다.
- 객체끼리의 연산자를 직접 정의할 수 있다.
'Kotlin > 자바 개발자를 위한 코틀린 입문' 카테고리의 다른 글
5. 추가적으로 알아두어야 할 코틀린 특성 (0) 2023.07.29 4. 코틀린에서의 FP (0) 2023.07.26 3. 코틀린에서의 OOP (0) 2023.07.10 2. 코틀린에서 코드를 제어하는 방법 (0) 2023.07.06