Kotlin 기초 - 기초 언어

안녕하세요. 이번 시간에는 코틀린의 기초 언어에 대하여 알아보겠습니다. 


1. 기본 문법

- 기본 문법에서는 지역변수를 정의하는 방법과 참조, 함수 호출, 단항/이항 연산자 같은 코틀린에서 정말 기본적인 것들을 다뤄보겠습니다.

 

1.1 주석

- 주석의 사전적 정의는 "낱말이나 문장의 뜻을 쉽게 풀이함 또는 그런글."로 말그대로 문장의 뜻을 쉽게 풀이한 것이다. 

- 주석은 프로그래밍 업무를 하면서 반드시 사용하게된다.

- 주석을 적용하면 해당 부분은 컴퓨터가 읽지 않는다.

 

① 주석의 종류

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

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

- KDoc 주석 : /**로 시작하고 */로 끝난다. 

 

② 예시

< 코드 >

/* 주석 */
fun main() {
    println("Hello World!!")    // 한 줄짜리 주석
    /*
    여러줄 주석
    예시 입니다.
    /* 주석안에 주석 입니다....1 */
    /* 주석안에 주석 입니다....2 */
    /* 주석안에 주석 입니다....3 */
    */
    /**
     * KDoc 주석 예시 입니다.
     *
     * */
}

 

< 결과 >

 

③ vs Java

- 여러 줄 주석 예시를 보면 자바와는 달리 코틀린에서는 여러 줄 주석을 여러 번 내포 할 수 있다.

 

1.2 변수 정의하기

- val 키워드 : 값을 뜻하는 value에서 유래

- 변수 식별자 : 변수에 이름을 부여하고, 나중에 이를 가르킬 때 사용.

- 변수의 초깃값 : = 기호 뒤에 온다.

 

① 예시

< 코드 >

/* 변수 정의하기 */
fun main() {
    val nAge = 32
    println("내 나이는 $nAge" + "살 입니다.")
}

< 결과 >

 

② vs Java

- 자바와 달리 문장 끝에 세비콜론인 ';'를 생략해도 된다.

 

1.3 식별자

- 자바 식별자와 비슷하다.

- 오직 문자, 숫자, 밑줄 문자( _ )만 포함한다.

- 숫자로 식별자를 시작할 수 없다.

- 하드 키워드를 식별자로 사용할 수 없다.

 

① 예시

< 코드 >

/* 식별자 */
fun main() {
    val nAge     = 32
    val nAge2    = 31
    val TEST_JJY = 30
    // val 2nAge    = 31 // Error
    // val fun      = 29 // Error
    // val $        = 28 // Error
    var `fun`    = 29

    println("nAge = $nAge")
    println("nAge2 = $nAge2")
    println("TEST_JJY = $TEST_JJY")
    println("`fun` = $`fun`")
}

< 결과 >

 

② vs Java

- 달러 기호( $ )를 식별자로 쓸수 없다.

- 작은역따옴표( ` )로 감싼 실별자로, 두 작은역따옴표 사이에는 빈 문자열을 제외한 아무문자열 가능하다.

 

1.4 가변 변수

- 불변 변수인 val 키워드는 한번 초기화 하면  다시는 값을 대입할 수 없다. ( Java의 final 변수와 비슷 )

- 가변 변수인 var 키워드를 사용하면 원할 때 변수값을 얼마든지 바꿀 수 있다.

- 전위/후위 연산자 사용가능 하다.

 

① 예시

< 코드 >

/* 가변변수 */
fun main() {
    // 불변 변수 재대입 예시
    /*
    val nSum = 1
    nSum = nSum + 2
    */

    // 가변 변수 예시
    var nSum = 1
    nSum = nSum + 2
    println("nSum = $nSum")

    // 가변 변수 잘못된 타입 대입 예시
    /*
    var nTest = 1
    nTest = "Test"
    */

    // 복합 대입 연산 예시
    var nSum2 = 1
    nSum2 += 2
    println("nSum2 = $nSum2")

    // 연쇄 대입문 사용 불가 예시
    var a = 1
    var b = 2
    var c = 3
    // a = b = c // Error
    
    // 전위 후위 연산자
    var nNum = 1
    println("nNum = " + nNum++)
    println("nNum = " + ++nNum)
    println("nNum = " + --nNum)
    println("nNum = " + nNum--)
}

< 결과 >

 

② vs Java

- 코틀린에서는 자바와 다르게 a = b = c 같은 연쇄 대입문을 쓸 수 없다. ( 복합 대입 연산도 마찬가지 )

 

1.5 식과 연산자

① 코틀린 식 분류

- 각 타입에 속하는 구체적인 값을 표현하는 리터럴

- 변수/프로퍼티 참조와 함수 호출

- 전위와 후위 단항 연산

- 이항 연산

 

② 연산자 우선순위

우선순위 분류 연산자
1 후위 ++, --, .
2 전위 +, -, ++, --, !
3 곱셈 *, /, %
4 덧셈 +, -
5 중위 이름이 붙은 중위 연산자들
6 비교 <, >, <=, >=
7 동등 ==, !=
8 논리곱 &&
9 논리합 ||
10 대입 =, +=, *=, /=, %=

 

2. 기본 타입

- 기본 타입에서는 수, 문자, 불 값 등을 표현하는 코틀린 타입에 대해 다뤄보겠습니다.

 

2.1 정수 타입

① 정수 타입 종류

이름 크기(바이트) 범위 vs Java
Byte 1 -128 ~ 127 Byte
Short 2 -32768 ~ 32767 Short
Int 4 -2^31 ~ 2^31 - 1 Int
Long 8 -2^63 ~ 2^63 - 1 Long

- 가장 간단한 리터럴 정수는 10진수 이다.

- 리터럴에 "_" 를 넣어서 가독성을 높일 수 있다.

- 리터럴에 "L"이다 "l"을 접두사로 붙이면 Long 타입이 된다.

- 2진수( 0b )나 16진수( 0x )를 붙여서 리터럴 작성이 가능하다.

- 수 리터럴 경우 0이 아닌이상 0을 맨앞에 올 수 없다.

- 음수는 단항 음수 연산자( - )를 사용 한다.

- 각 정수 타입에는 최솟값과 최댓값을 포함하는 상수 정의가 들어있다.\

 

② 예시

< 코드 >

/* 정수 타입 */
fun main() {
    val nYear = 2023
    val nBigNum = 123_456_789
    val nLongNum = 100L
    // val nIntNum: Int = 100L // Error
    val nBin = 0b10101
    val nHex = 0xF9
    val nZero = 0
    // val nZero2 = 01 // Error
    val nNeg = -10
    val nShortMin = Short.MIN_VALUE
    val nIntMax   = Int.MAX_VALUE + 1

    println("10진수형 리터럴 : $nYear")
    println("리터럴에 _ 넣기 : $nBigNum")
    println("Long타입 변환 : $nLongNum")
    println("2진수형 리터럴 : $nBin")
    println("16진수형 리터럴 : $nHex")
    println("0 리터럴 : $nZero")
    println("단항 음수 연산자 : $nNeg")
    println("Short 정수 타입 최솟값 : $nShortMin")
    println("Int 정수 타입 최댓값 : $nIntMax")
}

 

< 결과 >

 

2.2 부동소수점 수

- Java와 동일하게 Float와 Double 제공

- 10진 소수 형태로, 정수 부분과 소수 부분을 나눠 소수점( . )을 찍어 놓았다.

- 정수 부분이 비어있는 경우 정수 부분을 0으로 간주한다.

- 코틀린은 과학적 표기법인 e나 E 뒤에 10을 몇 번 거듭제곱하는지 알려주는 숫자를 허용한다.

- 디폴트로 부동소수점 리터럴은 Double이며 f나 F를 뒤에 사용 시 Float 타입이 된다.

 

① 예시

< 코드 >

/* 부동소수점 수 */
fun main() {
    val nPi = 3.14
    println("10진소수 형태 : $nPi")

    val nQuarter = .25
    println("10진소수의 정수부분 0생략 가능 : $nQuarter")

    val nPi100 = 0.314E3        // 0.314 * 1000
    val nPiOver100 = 3.14E-2    // 3.14 / 100
    println("거듭제곱 표현1 : $nPi100")
    println("거듭제곱 표현2 : $nPiOver100")

    val nPiF = 3.14F
    println("Float 형변환 : $nPiF")
}

 

< 결과 >

 

② vs Java

- Double이나 Float의 16진 리터럴을 지원하지 않는다.

- Java에서는 D나 d를 붙여 강제로 Double을 만들었지만 코틀린에서는 허용하지 않으며 디폴트가 Double 이다.

 

2.3 산술 연산

① 산술 연산 종류

연산
+(단항) 원래 값과 같은 값
-(단항) 원래 값의 부호를 반전한 값
+ 덧셈
- 뺼셈
* 곱셈
/ 나눗셈
% 나머지

- 코틀린에는 정수 나눗셈인 floorDiv()함수와 정수 나머지인 mod() 함수가 있다.

- 단항 +/- 연산의 겨로가는 인자들의 타입과 같다. 다만 Byte와 Short의 경우에는 Int를 내놓는다.

- Double > Float > Long > Int > Short > Byte 순으로 크다.

 

② 예시

<코드>

/* 산술연산 */
fun main() {
    println("floorDiv함수 예시 : " + 9.floorDiv(4))
    println("mod함수 예시 : " + 9.mod(4))

    val nByte: Byte     = 1
    val nShort: Short   = 1
    val nInt: Int       = 1
    val nFloat          = 1.5f
    val nDouble         = 1.5
    println("Byte형 -연산 : " + -nByte)        // -1: Int
    println("Short형 -연산 : " + -nShort)      // -1: Int
    println("Int형 -연산 : " + -nInt)          // -1: Int
    println("Float형 -연산 : " + -nFloat)      // -1.5: Float
    println("Double형 -연산 : " + -nDouble)    // -1.5: Double
}

 

<결과>

 

2.4 비트 연산

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

 

①  비트 연산 종류

연산 vs Java
shl 왼쪽 시프트(shift) <<
shr 오른쪽 시프트(shift) <<
ushr 부호 없는 오른쪽 시프트 >>>>
and 비트 곱(AND) &
or 비트 합(OR) |
xor 비트 배타합(XOR) ^
inv 비트 반전(inversion) ~

 

2.5 문자 타입

- Char 타입으로 한 글자를 표현하며 16비트이다.

- 리터럴을 작은따옴표( ' ) 사이에 문자를 넣어 표현 한다.

- \t는 탭, \n은 새줄, /r은 캐리지 리턴, \'는 작은따옴표, \"는 큰따옴표, \\는 역슬래시, \$는 달러표시, \u 다음에 네 자리 16진수를 넣어 임의의 유니코드 문자를 넣을 수 있다.

- +/- 연산자를 사용해 새 문자를 반환할 수 있다.

- ++/-- 연산자를 사용해 새문자를 반환할 수 있다.

 

① 예시

< 코드 >

/* 문자 타입 Char */
fun main() {
    val sJ = 'J'
    println("Char형 표현: $sJ")

    val sTab            = '\t'
    val sNewLine        = '\n'
    val sCarriageRetun  = '\r'
    val sSingleQuote    = '\''
    val sDoubleQuote    = '\"'
    val sBackslash      = '\\'
    val sDollar         = '\$'
    println("탭 $sTab 탭")
    println("새 $sNewLine 줄")
    println("캐리지 $sCarriageRetun 리턴")
    println("$sSingleQuote 작은따옴표 $sSingleQuote")
    println("$sDoubleQuote 큰따옴표 $sDoubleQuote")
    println("백슬래쉬 : $sBackslash")
    println("달러 : $sDollar")

    val sPi = '\u03C0'
    println("16진수 파이 : $sPi")

    var sA = 'a'
    var sY = 'y'
    println("+/- 연산자 사용하여 새문자 생성 : " + sA + 7)
    println("++/-- 연산자 사용하여 새문자 생성 : " + --sY)
}

 

< 결과 >

 

② vs Java

- Java에서는 Char형 산술연산 결과가 정수로 반환되지만 코틀린에서는 Char형으로 반환한다.

 

2.6 수 변환

- 각 수 타입마다 값을 다른 수 타입으로 변환하는 연산이 정의돼 있다.

- 정수 타입 사이의 변환은 대상 타입이 더 큰 범위를 담는 타입인 경우 손실 없이 수행된다.

- 부동소수점 수 타입과 관련된 경우, 일반적으로 대상 타입과 무관하게 정밀도를 잃을 수 있다.

 

① 예시

< 코드 >

/* 수 변환 */
fun main() {
    val nNumber = 1
    val nFloat  = 1.5
    println("Byte 변환 : " + nNumber.toByte())
    println("Short 변환 : " + nNumber.toShort())
    println("Int 변환 : " + nNumber.toInt())
    println("Long 변환 : " + nNumber.toLong())
    println("Float 변환 : " + nNumber.toFloat())
    println("Double 변환 : " + nNumber.toDouble())

    val nNumber2 = 945
    println("Byte 변환 : " + nNumber2.toByte())    // 손실
    println("Short 변환 : " + nNumber2.toShort())
    println("Char 변환 : " + nNumber2.toChar())
    println("Long 변환 : " + nNumber2.toLong())

    val nFloat2 = 2.5
    println("Int 변환 : " + nFloat2.toInt()) // 소수점 손실

    val nNumber3 = 1_000_000_000_000
    println("Flat 변환 후 Long 변환 : " + nNumber3.toFloat().toLong()) // 정밀도 손실
}

 

< 결과 >

 

② vs Java

- 범위가 큰 타입이 사용돼야 하는 문맥에 범위가 작은 타입을 사용 할 수 없다.

 

2.7 불 타입과 논리 연산

- 참(true) or 거짓(false) 중 하나로 판명되는 불(Boolean) 타입과 놀리 연산을 제공.

- !은 논리부정, or은 즉시계산 논리합, and는 즉시계산 논리곱, xor은 즉시계산 논리배타합, ||은 지연계산 논리합, &&은 지연계산 논리곱

 

① vs Java

- &와 | 연산자를 제공하지 않고 and와 or가 대체한다

 

2.8 비교와 동등성

- ==(같다), !=(같지 않다), <(~보다 작다), <=(~보다 작거나 같다), >(~보다 크다), >=(~보다 크거나 같다) 비교 연산 제공

- 두인자가 모두 같은 타입일 때만 ==와 != 허용.

- 모든 수 타입의 값은 서로 비교 연산 가능

- char와 Boolean 값도 비교연산 가능

- NaN값은 어떤값과도 같지 않고 무한대를 포함한 다른 어떤 값보다 작지도 않고 크지도 않다.

 

① vs Java

- Java에서는 Boolean형은 동등성 비교만 가능하다.

 

3. 문자열

- String 타입은 문자들로 이뤄진 문자열을 표현한다.

- String 객체를 만들고나면 그 안에 문자를 수정할 수 없으며, 문자를 바꾸려면 새로운 문자열을 만들어야 한다.

 

3.1 문자열 템플릿

- 문자열 리터럴을 정의하는 가장 간단한 방법은 큰따옴표( " )로 문자열을 감싸는 것이다.

 

① 예시

< 코드 >

/* 문자열 템플릿 */
fun main() {
    val sHelloWorld = "Hello, World"
    println("문자열 기본 형태 : $sHelloWorld")
}

 

< 결과 >

 

3.2 기본 문자열 연산

- length와 문자열의 마지막 문자 인덱스를 표현하는 lastIndex 프로퍼티를 제공한다.

- 문자열의 인덱스는 0부터 시작한다.

- + 연산자를 이용해 두 문자열을 연결 할 수 있다.

- ==, !=를 사용해 동등성 비교가 가능하다. ( 순서와 길이가 같으면 같은 문자열로 간주한다. )

- <, >, <=, >= 같은 연사자를 사용해 비교 가능하다.(사전 순서)

 

① 유용 함수

함수
isEmpty() 문자열이 비어있는지 검사
isNotEmpty 문자열이 안비어있는지 검사
substring 부분 문자열 추룰
startsWith 접두사나 인지 검사
endsWith 접미사 인지 검사
indexOf 인자로 받은 문자나 문자열이 수신 객체인 문자열에 나타나는 첫번째 인덱스를 반환한다.

 

② 예시

< 코드 >

/* 기본 문자열 연산 */
fun main() {
    val sHello = "Hello"
    println("문자열 길이 : ${sHello.length}")
    println("문자열 마지막인덱스 : ${sHello.lastIndex}")
    println("문자열 인덱스 값 : ${sHello[0]}")

    val sWorld = "World"
    println("문자열 +연산 : ${sHello + sWorld}")
    println("문자열 비교1 : ${sHello == sWorld}")
    println("문자열 비교2 : ${sHello != sWorld}")
    println("문자열 비교3 : ${sHello > sWorld}")
    println("문자열 유용함수1 : ${sHello.isEmpty()}")
    println("문자열 유용함수2 : ${sHello.isNotEmpty()}")
    println("문자열 유용함수3 : ${sHello.substring(1, 3)}")
    println("문자열 유용함수4 : ${sHello.startsWith("Hel")}")
    println("문자열 유용함수5 : ${sHello.endsWith("lo")}")
}

 

< 결과 >

 

4. 배열

- 배열은 내장된 코틀린 데이터 구조로, 미리 정해진 숫자만큼 같은 타입의 원소를 모아서 저장하고 각각을 인덱스로 참조할 수 있게 해준다.

 

4.1 배열 정의하기

- 배열 구조를 구현하는 가장 일반적인 코틀린 타입은 Array<T>이고 T는 원소의 타입을 나타낸다.

- 중괄호를 사용하여 람다식 배열이 가능하다.

 

① 예시

< 코드 >

import java.util.*

/* 배열 정의 */
fun main() {
    val aEmpty = emptyArray<String>()
    val aTest1 = arrayOf("Hellow", "World")
    val aTest2 = arrayOf(1, 3, 5, 7)

    println("aEmpty 배열 갯수 : " + aEmpty.size)
    println("aTest1 배열 갯수 : " + aTest1.size)
    println("aTest2 배열 갯수 : " + aTest2.size)

    val aLamda = Array(5, {i -> i*2})   // 크기가 5인 짝수형 람다식 배열 표현
    println("aLamda: ${Arrays.toString(aLamda)}")
}

 

< 결과 >

 

② vs Java

- Java와 달리 new 연산자가 없어 일반 함수 호출처럼 보인다.

- 코틀린에서는 배열 원소를 명시적으로 초기화 해야한다.

 

4.2 배열 사용하기

- size와 lastIndex 프로퍼티가 있다는 점에서 문자열 타입과 비슷하다.

- 잘못된 인덱스를 사용하면 런타임에 IndexOutOfBoundsException 예외가 발생한다.

- 문자열과는 달리 배열에서 원소를 변경할 수 있다.

- 자바와 마찬가지로 배열 타입의 변수 자체에는 실제 데이터에 대한 참조를 저장한다.

- 원본과 별도로 배열을 만들고 싶다면 copyOf() 함수를 사용한다.

- 배열 타입 변수에 타입이 다른 배열을 대입할 수 없다

- 배열을 생성하고나면 그 길이를 바꿀 수 없지만 + 연산을 사용해 새로운 배열을 만들 수 있다.

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

- 배열 원소를 비교하고 싶으면 contentEquals() 함수를 사용한다.

 

① 유용 함수

함수
isEmpty() 배열이 비어있는지 검사
isNotEmpty 배열에 원소가 있는지 검사
indexOf 인자와 일치하는 최초 배열 아이템의 인덱스를 반환(일치하는게 없으면 -1 반환)

② 예시

< 코드 >

import java.util.*

/* 배열 사용하기 */
fun main() {
    val aNumber = arrayOf(1, 3, 5, 7, 9)
    println("aNumber 배열 크기 : " + aNumber.size)
    println("aNumber 배열 마지막 인덱스 : " + aNumber.lastIndex)
    println("aNumber 배열 값 : " + aNumber[2])

    aNumber[2] = 5000
    println("aNumber 배열 값 변경 : " + aNumber[2])

    val aNumber2 = aNumber
    aNumber2[0] = 1000
    println("aNumber 배열 값도 같이 변경 : " + aNumber[0])

    val aNuber3 = aNumber.copyOf()
    aNuber3[1] = 3000
    println("aNumber 배열 값은 변경 안됨 : " + aNumber[1])
    println("aNuber3 배열 값만 변경 : " + aNuber3[1])

    // val aNumber = arrayOf("One", "Three", "Five", "Seven", "Nine") // Errors

    val aNumber4 = arrayOf(1, 3, 5, 7, 9) + 11
    val aNumber5 = arrayOf(1, 3, 5, 7, 9) + arrayOf(11, 13)
    println("aNumber4: ${Arrays.toString(aNumber4)}")
    println("aNumber5: ${Arrays.toString(aNumber5)}")

    println("배열은 ==/!= 연산자는 참조 비교 : " + (aNumber == aNumber))
    println("배열은 contentEquals함수로 값 비교 : " + aNumber.contentEquals(aNumber))

    println("배열 유용함수1 : " + aNumber.isEmpty())
    println("배열 유용함수2 : " + aNumber.isNotEmpty())
    println("배열 유용함수3-1 : " + aNumber.indexOf(9))
    println("배열 유용함수3-2 : " + aNumber.indexOf(10))
}

 

< 결과 >


이번시간에는 코트린의 기본에 대해 처음으로 맛보았습니다. 다음시간에는 코틀린 함수에 대해 알아보는 시간을 갖겠습니다. 감사합니다 :)

  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유