[Kotlin] 기본 문법

2023. 11. 26. 20:43개발지식/Kotlin

주석

- 한 줄짜리 주석: // 로 시작하며 줄이 끝나면 주석도 끝난다. 

- 여러 줄 주석: /* 로 시작하고 */로 끝난다. 

- kDoc 여러 줄 주석: /** 로 시작하고 */ 로 끝난다. (kDoc 주석은 자바독과 비슷한 리치 텍스트 문서를 생성하기 위해 사용한다.)

/*
여러 줄 주석
/*주석 안에 내포된 주석*/
*/
println("Hello world") // 한 줄 주석

 

자바 vs 코틀린

자바와 달리 코틀린에서는 여러 줄 주석을 여러 번 내포시킬 수 있다. 

 

변수 정의

val timeInSecond = 15

 

자바 vs 코틀린

- 코틀린에서는 줄 끝에 세미콜론을 생략해도 된다.

- 위 코드는 변수 타입을 지정하지 않았는데도 프로그램이 성공적으로 컴파일되고 실행된다. 이유는 코틀린의 타입추론기능 때뮨이다.  

val n: Int = 100
val text: String = "HelloWorld"

필요할 때는 타입을 명시해도 된다. 타입을 명시하려면 변수 이름 뒤에 : 를 표시하고 그 뒤에 타입을 적어주면 된다. 

fun main() {
    val a = readLine()!!.toInt()
    val b = readLine()!!.toInt()
    println(a+b)
}

 

- readLIne(): 표준입력에서 한 줄을 읽어서 문자열로 변환해주는 표준 코틀린 함수(호출식) 

- !!: null이 아닌 단언으로 readLine()의 결과가 널이 아닌경우 예외를 발생시킨다. 

 

자바 vs 코틀린

자바와 달리 코틀린은 어떤 타입이 널 값이 될  수 있는지를 추적하고, 널이 아닌 것이 확실하지 않은 값에 대해 toInt()함수를 호출하지 못하게 막음으로써 널로 인한 오류를 방지한다. 

 

식별자

식별자는 변수나 함수  등 프로그램에 정의된 대상에 붙은 이름이다. 

코틀린 식별자는 아래 두 가지로 구분된다. 

  • 임의의 문자열 
    • 식별자는 오직 문자, 숫자, 밑줄 문자(_)만 포함한다.
    • 숫자로 식별자를 시작할 수는 없다. 
    • 밑줄로만 이뤄질 수도 있으나, 이런 식별자( _ , _ _ , _ _ _ 등)는 모두 미리 예약된 식별자이므로 일반적인 식별자로는 사용될 수 없다. 
    • 하드 키워드(val, fun 등)를 식별자로는 쓸 수는 없다. 
  • 작은역따옴표( ' )로 감싼 식별자 
    • 작은역따옴표 사이에는 빈 문자열을 제외한 아무 문자열이나 와도 된다.  
val 'fun' = 1
val 'name with spaces' = 2

 

자바 vs 코틀린

자바와 달리 코틀린에서는 달러기호($)를 쓸 수 없다. 

 

가변 변수 

불변 변수는 한 번 초기화하면 다시는 값을 대입할 수 없는 변수이다.

불변변수를 사용하면 함수가 사이드 이팩트를 일으키지 못하고, 함수형 스타일 코드를 장려할 수 있으며, 코드에 대한 추론이 쉬워지기 때문에 가능하면 불변변수를 많이 사용해야 한다. 

 

val 대신 var 키워드를 사용해 가변변수를 정의할 수 있다. 

가변변수의 기본적인 문법은 불변변수와 동일하나, 원할 때 변수의 값을 변경할 수 있다. 

var sum = 1
sum = sum + 2
sum += 3

 

처음 변수에 값을 대입할 때 추론된 변수 타입은 변수가 불변이든 아니든  계속 유지된다는 점을 주의하자. 

(잘못된  타입의 값을 대입하면 컴파일 오류가 발생한다.)

 

자바 vs 코틀린

자바와 달리 코틀린은 대입은 문(statement)이다. 따라서 아무 값도 돌려주지 않는다. 때문에 코틀린에서는 자바의 a = b = c와 같은  대입문 연쇄를 사용할 수 없다. 

 

기본 타입

자바에서는 int와 같은 원시 타입과 String과 같이 클래스를 기반으로 하는 참조 타입 사이에 면확한 구분이 있었다.

코틀린에서는 똑같은 타입이 문맥에 따라 원시타입과 참조타입을 가리키기 때문에 이런 구분이 약간 모호하다. 

 

자바에서는 원시타입을 감싸는 특별한 박싱 타입이 있지만, 코틀린은 필요할 때 암시적으로 박싱을 수행한다.

 

자바 vs 코틀린

자바와 달리 모든 코틀린의 타입은 근본적으로 어떤 클래스 정의를 기반으로 만들어진다. 이 말은 int와 같이 원시타입과 비슷한 타입들도 메서드와 프로퍼티를 제공한다는 뜻이다.

1.5.toInt() // Double의 값을 Int값으로 변환해줌

 

타입은 하위타입(subType)이라는 개념으로 계층화 할 수 있다. A타입이 B타입의 하위타입이라는 말을 근본적으로 B타입의 값이 쓰일 수 있는 모든 문맥에 A타입의 값을 넣어도 아무 문제가 없다는 것이다. 

예를 들어 , null을 허용하지 않는 모든 코틀린 타입은 Any라는 내장 타입의 직간접적인 하위 타입이다. 따라서 다음 코드는 1이라는 값을 박싱하게 만든다. 

val n: Any = 1 // OK. Int는 Any의 하위 타입

 

 

정수 타입

코틀린에서는 정수를 표현하는 네 가지 기본 타입이 있다. 

코틀린 1.1부터는 자바 7+와 마찬가지로 수 리터럴에 _를 넣어서 가독성을 높일 수 있다. 리터럴이 아주 큰 수를 나타낼 때 _가 유용하다. 

val n = 34_721_189

 

부동소수점 수 

자바와 마찬가지로 코틀린도 부동소수점 수를 따른는 Float과 Double을 제공하며, 각각 자바의 float 과 double에 대응한다.

 

자바 vs 코틀린

자바와 달리 코틀린에서는 Double(Float보다 2배의 정밀도)이나 Float의 16진 리터럴을 지원하지 않는다. 

부동소수점 리터럴의 타입은 디폴트로 Double 타입이다. f나 F를 뒤에 붙이면 Float타입이 된다. 

val pi: Double = 3.14f // Error

 

Float 과 Double도 각 타입의 특별한 값을 표현하는 몇 가지 상수를 제공한다. 

 

- MIN_VALUE, MAX_VALUE: 각 타입에서 표현할 수 있는 가장 작은 유한값과 가장 큰 유한값

- NEGATIVE_INFINITY, POSITIVE_INFINITY: 음의 무한대와 양의 무한대. 각 타입이 표현할 수 있는 가장 작은 값과 가장 큰 값

-NaN: 0/0의 결과처럼 숫자가 아닌 값을 의미 

 

비트 연산

Int와 Long은 비트 수준의 연산을 지원한다.

 

문자 타입 Char

- +/- 연산자를 사용해 문자에 수를 더하거나 뺄 수 있다. 더하거나 뺀 수만큼 코드 포인트가 이동한 새 문자를 반환한다. 

- 두 문자로 뺄셈을 반환하면 두 문자의 코드 포인트 간 거리를 얻을 수 있다. 

- 문자를 ++ 또는 -- 로 증가시키거나 감소시킬 수 있다. 

var a = 'a'
var h = 'h'
println(a+5) // f (a보다 뒤에 있는 다섯 번째 글자) 
println(h-a) //7 (a와 h사이의 거리)
println(--h) // g (h 바로 앞의 글자)

 

자바 vs 코틀린

자바에서는 문자(char)에 대한 산술 연산 결과가 암시적으로 정수로 변환된다. 반면 코틀린에서는 char에 대한 연산은(두 문자의 차이는 제외) Char를 결과로 돌려준다. 

 

수 변환 

자바 vs 코틀린

자바와 달리 코틀린에서는 범위가 큰 타입이 사용돼야 하는 문맥에 범위가 작은 타입을 쓸 수 없다. 

예를 들면 Int 값을 Long 변수에 대입할 수 없다. 

val n = 100
val l: Long = n // Error: can't assign Int to Long

 

이렇게 하게 된 이유는 암시적인 박싱 때문이다.

일반적인 Int값이 꼭 원시 타입의 값으로 표현된다는 보장이 없다. 따라서 위 코드와 같은 더 큰 범위의 타입으로 변환하는 경우 다른 박싱한 타입의 값을 만들어 낼 수 있는 가능성이 생기고. 이로 인해 동등성 요구 조건을 만족시키지 못하게 되면서 미묘한 오류를 발생시킬 수 있다. 

위 코드를 올바른 코드로 인정하면 다음 연산의 결과는 false일 것이다. 

 

불 타입과 논리연산 

- !: 논리 부정

- or , and , xor : 즉시 계산 방식의 논리합, 논리곱, 논리배타합

- ||, &&: 지연 게산방식의 논리합, 논리곱

 

자바 vs 코틀린

자바와 달리 코틀린은 &와 | 연산자를 제공하지 않는다. and와 or가 각각 &와 |를 대신한다. 

 

비교와 동등성 

기본적으로 코틀린 타입은 두 인자가 모두 같은 타입일 때만 ==와 !=를 허용한다. 예를 들어, 한 인자가 Int이고 다른 인자가 Long이면 ==를 적용할 수 없다. 

 

값이 박싱돼  있는지에 따라 동등성 연산이 다른 결과를 낳을 수 있는데, 코틀린에서는 박싱이 암시적으로 진행되기 때문에 타입 사이의 동등성 연산을 허용하면 혼란을 야기할 수 있기 때문이다. 

하지만 도든 수 타입의 값은 서로 < , <=, >, >=를 사용해 비교할 수 있다. 

 

NaN

- 의미상으로 NaN은 수가 아니다. 

- 기본적으로 NaN은 그 어떤 값과도 같지 않다. 특히 다른 NaN과도 같지 않고, 무한대를 포함한 다른 어떤 값보다 작지도 않고 크지도 않다. 

- NaN은 자기 자신과 같다. 집합에 NaN이 단 하나만 추가됐기 때문이다. 

- NaN은 Double에서 가장 큰 값으로 취급된다.(십지어 양의 무한대보다도 크다.) 

 

 

문자열  탬플릿 

 

- ${}의 중괄호 사이에 넣기만 하면, 어떤 올바른 코틀린 식이든 문자열에 넣을 수 있다. 

- 간단한 변수 참조의 경우 중괄호를 생략하고 $ 기호만 붙여도 된다.

import java.util.Date

fun main(){
	val name = readLine()
    println("Hello, $name!\n Today is ${Date()} ")
}

 

로우 문자열을 사용하면 이스케이프 시퀀스를 사용하지 않고도 문자열을 작성할 수 있다. 

val message = """
    Hello, $name!
    Today is ${Date()}
""".trimIndent()

- trimIndent()는 여러 줄에 공통된 최소 들여쓰기를 제거해주는 표준 코틀린 함수이다. 

 

기본 문자열 연산 

 모든 String 인스턴스는 문자열에 든 문자 수를 표현하는 length와 문자열의 마지막 문자 인덱스를 표현하는 lastIndex 프로퍼티를 제공한다. 

"Hello!".length // 6
"Hello!".lastIndex // 5

 

인덱스를 각괄호 ([]) 안에 넣는 연산자를 사용해 개별 문자에 접근할 수 있다. JVM에서 잘못된 인덱스를 넘기면 자바와 마찬가지로 StringIndexOutOfBoundsException 예외가 발생한다. 

val s = "Hello!"
println(s[0]) // H
println(s[1]) // e
println(s[5]) // l
println(s[10]) // 잘못된 인덱스

 

+ 연산자를 사용해 두 문자열을 연결할 수 있다. toStirng()을 사용해 문자열로 변환될 수 있는 모든 값을 +의 두 번째 피연산자로 지정할 수 있다. 하지만 일반적으로 문자열 탬플릿이 더 간결하다. 

 

val s = "The sum is:" + sum // "The sum is $sum"으로 대신할 수 있음

 

문자열은 ==와 !=를 사용해 동등성을 비교할 수 있다. 이들 연산은 문자열의 내용을 비교하므로, 서로 다른 두 객체의 인스턴스를 비교해도 문자들의 순서와 길이가 같으면 같은 문자열로 간주한다. 

val s1 = "Hello!"
val s2 = "Hel" + "lo!"
println(s1 == s2) //true

 

자바 vs 코틀린

자바에서 문자열 내용을 비교시 equals()를 사용해야 하지만, 코틀린은 == 가 기본적으로 equals()를 호출하므로 따로 equals()를 호출할 필요가 없다.

만약, 참조 동등성을 쓰고 싶으면  === 와 !== 연산자를 사용하면 된다.

 

배열

배열구조를 구현하는 가장 일반적인 코틀린 타입은 Array<T>이다. 여기서 T는 원소 타입을 뜻한다. 

 

val a = emptyArray<String>() // Array<String> , 원소 0개
val b = arrayOf("hello", "world") // Array<String> , 원소 2개
val c = arrayOf(1,3,5) // Array<Int> , 원소 3개

 

Array<Int>를 사용하는 배열은 제대로 동작하지만 모든 수를 박싱하기 때문에 그다지 실용적이지 못한 해법이다. 

이런 이유로 코틀린은 더 효율적인 ByteArray, ShortArray, IntArray, LongArray, DoubleArray, CharArraym BooleanArray라는 특화된 배열 타입을 제공한다. 

JVM에서 이런 배열 타입들은 int[], boolean[] 등의 원시 타입 배열로 표현된다. 

 

val size = readLine()!!.toInt()
val squares = Array(size) {(it + 1)*(it + 1)}

중괄호{()} 안에 들어있는 언어 요소를 람다라고 부른다. 람다는 인덱스를 기반으로 값을 계산하는 식을 정의한다. 

(이 때 인덱스를 표현하는 변수로 자동으로 선언되는 it을 사용한다.) 

 

val operations = charArrayOf('+', '-', '*', '/', '%')
val squares  = IntArray(10) {(it + 1) * (it + 1)}

 

자바 vs 코틀린

자바와 달리 코틀린에서는 new연산자가 없기 때문에 배열 인스턴스 생성이 일반적인 함수 호출처럼 보인다. 코틀린에서는 배열원소를 명시적으로 초기화해야 한다는 점에도 유의하라. 

 

배열 사용하기

val squares = arrayOf(1,4,9,16)
squares.size //4
squares.lastIndex //3
squares[3] //16
squares[1] // 4

// 문자열과 달리 배열에서는 원소를 변경할 수 있음
squares[2] = 100 // squares: 1,4,100,16
squares[3] += 9 // squares: 1,4,100,25
squares[0]--  // squares: 0,4,100,16

 

자바와 마찬가지로 배열 타입의 변수 자체에는 실제 데이터에 대한 참조를 저장한다. 이로 인해 배열 변수에 다른 배열을 대입하면 같은 데이터 집합을 공유하게 된다. 

val numbers = squares 
numbers[0] = 1000 // squares에는 영향이 없다. 
squares.copyOf(2) // 뒤가 잘림 : 1, 4
squares.copyOf(5) // 부족한 부분에 0으로 채워짐: 1, 4, 9, 16, 0

 

 

 

 

자바에서는 상위 타입의 배열에 하위 타입의 배열을 대입할 수 있었다. 배열이 가변 데이터 구조이므로 이런 대입은 런타임 시 문제를 발생시킬 수 있다. 

Object[] objs new String[] {"one","two","three"};
objs[0] = new Object(); // ArrayStoreException 예외 발생

 

이런 이유로 코틀린 배열 타입은 모든 다른 배열 타입과 서로 하위 타입 관계가 성립하지 않는다고 간주되며, 위와 같은 대입도 금지된다.

 

자바 vs 코틀린

코틀린에서 String은 Any의 하위 타입이지만 Array<String>은 Array<Any>의 하위 타입이 아니다. 배열을 생성하고 나면 그 길이를 바꿀 수는 없지만, + 연산을 사용해 원소를 추가한 새로운 배열을 만들 수는 있다. 

val a = intArrayOf(1,2,3) + 4 // 1,2,3,4
val c = intArrayOf(1,2) + intArrayOf(3,4) // 1,2,3,4

 

문자열과 달리 배열에 대한 == 와 != 연산자는 원소 자체를 비교하지 않고 참조를 비교한다. 

intArrayOf(1,2,3) == intArrayOf(1,2,3) //false

 

배열 내용을 비교하고 싶으면 contentEquals() 함수를 사용하면 된다. 

intArrayOf(1,2,3).contentEquals(intArrayOf(1,2,3)) //true

 

'개발지식 > Kotlin' 카테고리의 다른 글

[Kotlin] 고차함수  (0) 2024.01.07
[Kotlin] 클래스와 객체 다루기  (0) 2023.12.31
[Kotlin] 코틀린 함수  (1) 2023.12.21