728x90

https://kotlinlang.org/docs/basic-types.html

 

Basic types | Kotlin

 

kotlinlang.org

 

  • Basic types

코틀린에서도 모든 것은 객체이다.

호출하는 함수와 그 어떤 속성도 모두 객체이다.

 

Integer types

코틀린에서는 4가지의 숫자 타입을 제공한다.

Type Size Min Value Max Value
Byte 8 -128 127
Short 16 -32768 32767
Int 32 -2,147,483,648 (-231) 2,147,483,647 (231 - 1)
Long 64 -9,223,372,036,854,775,808 (-263) 9,223,372,036,854,775,807 (263 - 1)

만약 처음에 타입을 지정해주지 않는다면, 컴파일러는 자동으로 Int로 지정해주게 된다.

만약 Int의 범위 밖이라면, 타입은 Long으로 지정되게 된다.

처음에 Long 타입으로 지정해주고 싶다면, 숫자 뒤에 L을 붙여야 한다.

 

val a = 1 // Int
val b = 3030303030303030303030 //Long
val c = 123L // Long

 

Floating-point types

코틀린은 실수에 대해, Float와 Double을 제공한다.
Float은 Single precision, Double은 Double precision

 

Type Size Significant bits Exponent bits Decimal digits
Float 32 24 8 6-7
Double 64 53 11 15-16

 

실수를 선언하면 자동으로 Double로 지정이되며, Float로 지정하고 싶다면 뒤에 f를 붙여주어야 한다.

val e = 2.7182818284 // Double
val eFloat = 2.7182818284f // Float, actual value is 2.7182817

 

Literal constants for numbers

수는 다음과 같이 표현할 수 있다.

- Decimals: 123

- Longs: 123L

- Hexadecimals: 0x0F

- Binaries: 0b00010101

- Doubles by default: 123.5, 123.5e10

 

Numbers representation on the JVM

자바에서는 수를 Int, double로 저장하게 된다.

하지만 이런 타입에는 null이 지정되지 못한다.

그러면 코틀린에서의 Int?는 어떻게 되는 것일까?

그런 경우에는 자바에서의 boxed type인 Integer, Double을 사용했었다.

 

nullable 타입은 같은 수라도 다른 object를 참조한다.

fun main() {
    val a: Int = 100
    val boxedA: Int? = a
    val anotherBoxedA: Int? = a

    val b: Int = 10000
    val boxedB: Int? = b
    val anotherBoxedB: Int? = b

    println(boxedA === anotherBoxedA) // true
    println(boxedB === anotherBoxedB) // false
}

 

이런 일이 생기는 이유는 ~128~127의 범위는 JVM이 메모리 최적화를 위해 같은 곳을 참조하도록 하기 때문이다.

하지만 b의 경우에는 그런 일이 생기지 않는다.

 

Explicit number conversions

다른 표현 방식 때문에, smaller type은 bigger의 subtype이 아니다.

따라서 아래와 같은 경우 문제가 발생한다.

// Hypothetical code, does not actually compile:
val a: Int? = 1 // A boxed Int (java.lang.Integer)
val b: Long? = a // Implicit conversion yields a boxed Long (java.lang.Long)
print(b == a) // Surprise! This prints "false" as Long's equals() checks whether the other is Long as well

 

그렇기 때문에 Smaller type은 bigger 타입으로 자동 캐스팅이 되지 않는다.

따라서 명시적인 변환을 거쳐야 한다.

val b: Byte = 1 // OK, literals are checked statically
// val i: Int = b // ERROR
val i1: Int = b.toInt()

 

Operations on numbers

코틀린은 +, -, *, /, %와 같은 기본 연산자를 지원한다.

 

Division of integers

Int 끼리의 나누기는 항상 Int를 반환한다.

소숫점 부분은 무시된다.

val x = 5 / 2
//println(x == 2.5) // ERROR: Operator '==' cannot be applied to 'Int' and 'Double'
println(x == 2)

 

소숫점까지 구하기 위해서는 하나를 명시적으로 float 타입으로 변환해주어야 한다.

val x = 5 / 2.toDouble()
println(x == 2.5)

 

  • Unsigned integer types

Unsigned integer types

Integer type에 더해, 코틀린은 unsigned 값들을 제공한다.

Type Size Min value Max value
UByte 8 0 255
UShort 16 0 65,535
UInt 32 0 4,294,967,295
ULong 64 0 18,446,744,073,709,551,615

 

Unsigned arrays and ranges

다른 원시 타입들과 같이, 해당 데이터 타입들도 배열을 제공한다.

UByteArray: and array of unsigned bytes

UShortArray: an array of unsigned shorts

UIntArray: an array of unsigned ints

ULongArray: an array of unsigned longs

Unsigned integers literals

unsigned 타입을 더 명확하게 사용하기 위해, 코틀린은 해당 suffix를 제공한다.(Float, Long과 같이)

뒤에 u, U를 붙이면 해당 unsigned 타입으로 컴파일러가 인지하게 된다.

val b: UByte = 1u  // UByte, expected type provided
val s: UShort = 1u // UShort, expected type provided
val l: ULong = 1u  // ULong, expected type provided

val a1 = 42u // UInt: no expected type provided, constant fits in UInt
val a2 = 0xFFFF_FFFF_FFFFu // ULong: no expected type provided, constant doesn't fit in UInt

 

  • Booleans

Boolean 타입은 true, false 이렇게 두가지만 가지는 boolean object이다.

 

다른 언어와 마찬가지로

|| : disjunction(Logical OR)

&&:: conjunction (Logical AND)

!: negation(Logical NOT)

 

val myTrue: Boolean = true
val myFalse: Boolean = false
val boolNull: Boolean? = null

println(myTrue || myFalse)
// true
println(myTrue && myFalse)
// false
println(!myTrue)
// false
println(boolNull)
// null

 

||, &&는 Lazy하게 동작하기도 한다.

무슨말이냐면, first operand가 true라면 OR는 second operand를 확인하지 않는다.

마찬가지로, first operand가 false라면 and는 second operand를 확인하지 않는다.

 

  • Charaters

Character는 작은따옴표 안에 있는 문자 하나를 말한다. ex) '1'

backslash로 시작하는 Special Character가 존재한다.

아래와 같은 역할을 한다.

\t: tab

\b: backspace

\n: new line

\r: carriage return

\': single quotation mark

\": double quotation mark

\\: backslash

\$: dollar sign

 

  • Strings

String은 문자열이며, JVM에서 UTF-16을 사용하기 때문에 문자 하나당 2bytes를 사용한다.

String은 큰따옴표 안에 존재한다.

 

String은 immutable로 후에 바꿀 수 없기 때문에 새로운 문자열 객체를 만들어서 대입해야 한다.

String은 +를 사용하여 문자열들을 이을 수 있다.

 

val s = "abc" + 1
println(s + "def")
// abc1def

 

 

  • Strings

Array는 같은 타입이거나 그것들의 sub 타입 객체들을 고정된 숫자로 가지고 있는 자료구조이다.

 

Create arrays

코틀린에서 배열을 생성하기 위해서는 다음과 같은 함수들을 사용한다.

arrayOf(), arrayOfNulls(), emptyArray()

 

arrayOf()는 괄호 안에 value들을 넣어서 생성한다.

// Creates an array with values [1, 2, 3]
val simpleArray = arrayOf(1, 2, 3)
println(simpleArray.joinToString())
// 1, 2, 3

 

arrayOfNulls를 사용하면 해당 사이즈를 가지는 null 배열을 생성한다.

// Creates an array with values [null, null, null]
val nullArray: Array<Int?> = arrayOfNulls(3)
println(nullArray.joinToString())
// null, null, null

 

emptyArray는 빈 배열을 생성한다.

 

Nested arrays

Array도 객체이기 때문에 다른 Array 안에 들어 갈 수 있다.

// Creates a two-dimensional array
val twoDArray = Array(2) { Array<Int>(2) { 0 } }
println(twoDArray.contentDeepToString())
// [[0, 0], [0, 0]]

 

Access and modify elements

Array는 mutable하기 때문에 수정이 가능하다.

접근 할 때도 []를 사용하여 접근 할 수 있다.

simpleArray[0] = 10
twoDArray[0][0] = 2

 

Work with arrays

Pass variable number of arguments to a function

코틀린에서는 vararg를 통해, 가변 개수의 parameter를 받을 수 있다.

이런 방법은 사전에 정해지지 않은 수의 파라미터를 받는 경우에 굉장히 유리하다.

 

이런 vararg를 사용하는 함수에 array를 통해 가변 개수의 parameter를 넘기려면 *을 사용한다.

배열에 있는 각각의 객체를 spread해서 넘겨주는 연산자이다.

 

fun main() {
    val lettersArray = arrayOf("c", "d")
    printAllStrings("a", "b", *lettersArray)
    // abcd
}

fun printAllStrings(vararg strings: String) {
    for (string in strings) {
        print(string)
    }
}

 

 

Compare arrays

두개의 Array가 같은 순서로 같은 객체들을 가지고 있는지 확인하기 위해서는 .contentEquals()를 사용하면 된다.

val simpleArray = arrayOf(1, 2, 3)
val anotherArray = arrayOf(1, 2, 3)

// Compares contents of arrays
println(simpleArray.contentEquals(anotherArray))
// true

// Using infix notation, compares contents of arrays after an element 
// is changed
simpleArray[0] = 10
println(simpleArray contentEquals anotherArray)
// false

 

 

Transform arrays

코틀린은 array를 transform 하는 것에 많은 함수들을 제공한다.

 

  • Sum

.sum을 사용하여 해당 Array의 element를 모두 더한 값을 리턴한다.

val sumArray = arrayOf(1, 2, 3)

// Sums array elements
println(sumArray.sum())
// 6

 

  • Shuffle

Array에서 해당 elements들을 랜덤하게 섞기 위해서 사용하는 함수이다.

val simpleArray = arrayOf(1, 2, 3)

// Shuffles elements [3, 2, 1]
simpleArray.shuffle()
println(simpleArray.joinToString())

// Shuffles elements again [2, 3, 1]
simpleArray.shuffle()
println(simpleArray.joinToString())

 

  • Convert arrays to collections

Array를 List와 Set으로 변환 할 수 있다.

.toList()와 .toSet()을 사용하면 된다.

val simpleArray = arrayOf("a", "b", "c", "c")

// Converts to a Set
println(simpleArray.toSet())
// [a, b, c]

// Converts to a List
println(simpleArray.toList())
// [a, b, c, c]

 

  • Type checks and casts

is and !is operators

인스턴스가 해당 타입의 객체인지  확인하기 위해서는 is, !is operator를 사용한다.

if (obj is String) {
    print(obj.length)
}

if (obj !is String) { // Same as !(obj is String)
    print("Not a String")
} else {
    print(obj.length)
}

 

Smart casts

컴파일러는 is, !is로 확인 한 경우에는 안전하게 해당 타입으로 캐스팅을 해준다.

그렇기 때문에 개발자가 직접 타입을 as를 사용하여 변환 할 필요가 없다.

fun demo(x: Any) {
    if (x is String) {
        print(x.length) // x is automatically cast to String
    }
}

 

if (x !is String) return

print(x.length) // x is automatically cast to String

 

"Unsafe" cast operator

명시적으로 타입을 캐스팅하고 싶다면 as를 사용한다.

val x: String = y as String

만약 캐스팅이 불가능하다면, Exception이 발생한다.

 

"Safe" (nullable) cast operator

이런 exception을 피하기 위해서는 as? 연산자를 사용한다.

만약 해당 캐스팅이 실패하면 null이 return 되게 된다.

 

val x: String? = y as? String

 

728x90

https://kotlinlang.org/docs/basic-syntax.html

 

Basic syntax | Kotlin

 

kotlinlang.org

 

Package definition and imports

패키지는 소스파일 가장 위에 명시한다.

package seungkyu

class PackageDefinitionAndImports {

}

 

코틀린에서는 디렉토리와 패키지를 똑같이 맞출 필요는 없다고 한다.

 

Program entry point

코틀린 애플리케이션이 시작하는 부분은 main 함수 부분이다.

package seungkyu

fun main(args: Array<String>) {
   println("Hello, world!")

    println(args[0])
}

 

만약 애플리케이션 실행에서 매개변수를 받고 싶으면, 메인 함수에 저렇게 문자열 배열로 받을 수 있다.

 

print 함수는 매개변수를 standard output에 출력한다.

package seungkyu

fun main(){
    print("seungkyu")
    
    println("seungkyu")
}

println은 print에서 한 line을 차지하여 출력하는 함수이다.

다음 출력은 해당 출력의 다음줄부터 시작된다.

Read from the standard input

readln은 standard input으로부터 읽어오는 함수이다.

이 함수는 한 줄 전체를 읽어온다.

package seungkyu

fun main(){
    print("Enter your name: ")

    val name = readln()

    print("Your name: ")
    println(name)

    println("is contain new line? : ${name.contains("\n")}")
}

 

엔터키는 제외하고 읽어오는 것을 볼 수 있다.

Functions

아래는 2개의 Int를 매개변수로 받고 Int를 반환하는 함수이다.

fun sum1(a: Int, b: Int): Int {
    return a + b
}

 

아래와 같이 명시적이라면 return과 괄호를 생략 할 수 있다.

fun sum2(a: Int, b: Int) = a + b

 

만약 return이 아무것도 반환하지 않는다면 Unit으로 return type을 준다.

fun printSum(a: Int, b: Int): Unit {
    println("sum of $a and $b is ${a + b}")
}

 

이 때 Unit은 생략이 가능하다.

fun printSum(a: Int, b: Int) {
    println("sum of $a and $b is ${a + b}")
}

 

Variables

코틀린은 val, var 키워드로 변수 선언이 가능하며, 그 뒤에 변수의 이름을 적어준다.

 

val은 할당이 한 번만 일어나는 변수를 선언 할 때 사용하며, 후에 값이 변하지 않는다.

선언 이후에는 read-only이다.

val x: Int = 5

 

그에 비해 var은 선언 이후에도 값을 변경 할 수 있다.

fun main(){
    var x: Int = 5
    x += 1
}

 

위에서는 변수의 type을 :로 같이 명시해 준 것을 볼 수 있는데, 사실 코틀린은 변수의 타입을 추정이 가능하기 때문에 변수 타입은 생략을 해주어도 된다.

 

var x = 5

 

아래와 같이 변수의 타입까지만 선언해두고 값은 나중에 할당하는 것도 가능하다.

fun main(){
    val x = 5
    
    val c: Int
    c = 3
}

 

자바와는 다르게, 변수를 클래스 밖인 top level에 선언도 가능하다.

val value = 0

fun main(){

    println(value)
}

 

Creating classes and instances

늘 그렇듯, 클래스를 정의하기 위해서는 class 키워드를 사용한다.

class Shape

 

클래스의 속성들은 선언이나 body에 작성할 수 있다.

class Rectangle(val height: Double, val length: Double){
    val perimeter = (height + length) * 2
}

 

이 때, 클래스 선언부에 작성된 매개변수를 바탕으로 기본 생성자가 만들어진다.

class Rectangle(val height: Double, val length: Double){
    val perimeter = (height + length) * 2
}

fun main(){
    val rectangle = Rectangle(10.0, 20.0)
    println("The Perimeter is ${rectangle.perimeter}")
}

 

클래스 간의 상속은 : 을 사용하면 된다.

클래스는 기본적으로 상속이 불가능한 final 상태이지만, 앞에 open 키워드를 붙여주면 상속 가능한 클래스가 된다.

 

open class Shape

class Rectangle(val height: Double, val length: Double): Shape() {
    val perimeter = (height + length) * 2
}

Comments

주석은 //와 /* */를 사용해서 작성 할 수 있다.

//주석입니다.

/* 이것은
주석 블럭입니다 */

 

String templates

기본적으로 String은 ""이런 형태로 있을 것이다.

자바에서는 문자열들을 붙일 때 +를 사용했지만 코틀린에서는 $을 사용하여 문자열 안에 넣을 수 있다.

val mystring = "${1+2}, but now is $a"

 

Conditional expressions

조건식도 If를 사용한다.

fun max_result(a: Int, b: Int): Int{
	if (a > b){
    	return a
    }
    else{
    	return b
    }
}

 

코틀린에서는 3항 연산자가 없으며, 대신 if 또한 표현식으로 사용된다.

fun max_result(a: Int, b: Int) = if (a > b) a else b

 

for loop

다른 언어와 마찬가지로 for를 사용해서 반복문을 작성한다.

 

fun main(){
    val items = listOf("apple", "banana", "kiwi")
    for (item in items) {
        println(item)
    }
}

 

배열에서 in으로 각각의 item을 가져올 수 있다.

while loop

이것도 마찬가지로 while의 괄호 안에 있는 조건이 true일 동안 반복하게 된다.

fun main(){
    val items = listOf("apple", "banana", "kiwi")
    var index = 0
    while (index < items.size) {
        println("item at $index is ${items[index]}")
        index++
    }
}

 

when expression

C언어에서의 switch이다.

C언어와는 다르게 다양한 타입으로 분기할 수 있다.

 

또한 이것도 표현식이기 때문에 when을 사용하여 변수에 값을 할당 할 수 있다.

이 때는 else로 모두 해당하지 않는 경우를 꼭 지정해주어야 한다.

fun main(args: Array<String>) {
    val obj = "hi"
    
    val result = when (obj) {
        "hi" -> "hello"
        "hello" -> "hi"
        else -> ""
    }
}

 

Ranges

in 연산자를 사용하여 숫자가 범위 내에 있는지 확인한다.

fun main(){
    val x = 10
    val y = 9

    if(x in 1..y+1){
        println("fits in range")
    }
}

 

반복문에서도 이렇게 사용할 수 있다.

for (x in 1..5){
	print(x)
}

 

downTo와 step을 사용하여 증가인지 감소인지와 간격을 지정해 줄  수 있다.

fun main(){
    for (x in 1..10 step 2) {
        print(x)
    }
    println()
    for (x in 9 downTo 0 step 3) {
        print(x)
    }
}

 

 

Collections

collection을 반복하는 방법

for (item in items){
	println(item)
}

 

map을 사용하여 해당 collection을 반복 할 수도 있다.

    val fruits = listOf("banana", "avocado", "apple", "kiwifruit")
    fruits
    	//a로 시작하는 단어 찾기
        .filter { it.startsWith("a") }
        //정렬
        .sortedBy { it }
        //대문자로 변환
        .map { it.uppercase() }
        //각각을 출력
        .forEach { println(it) }

 

Nullable values and null checks

코틀린에서는 null을 허용할 때 명시를 해주어야 한다.

타입의 마지막에 ?를 붙여주면 nullable 타입이다.

fun main(){
    val a: Int? = null
    val b: Int = 1
}

 

Type checks and automatic casts

is는 인스턴스가 해당 타입이 맞는지 확인하는 연산자이다.

그리고 is로 검사가 끝나면 해당 타입으로 자동 캐스팅해준다.

fun getStringLength(obj: Any): Int? {
    if (obj is String) {
        // `obj` is automatically cast to `String` in this branch
        return obj.length
    }

    // `obj` is still of type `Any` outside of the type-checked branch
    return null
}

fun main() {
    fun printLength(obj: Any) {
        println("Getting the length of '$obj'. Result: ${getStringLength(obj) ?: "Error: The object is not a string"} ")
    }
    printLength("Incomprehensibilities")
    printLength(1000)
    printLength(listOf(Any()))
}

 

'백엔드 > 코틀린' 카테고리의 다른 글

Concepts:Control flow  (1) 2024.10.05
Idioms  (1) 2024.10.01
코틀린 시작  (0) 2024.09.28
728x90

거의 1년간 코틀린으로 스프링부트를 사용하고 있었지만, 사실 나의 코틀린은 자바에서 단지 널 안정성만 추가된 언어였다.

 

물론 널 안정성 만으로도 자바에서 코틀린으로 넘어 올 가치는 있지만, 그래도 더 나은 개발자가 되기 위해서는 코루틴까지 자유롭게 사용할 수 있어야 한다는 생각이 들었다.

 

코틀린은 아직 한국어 자료가 많이 없기 때문에 이 참에 공식문서를 참고하여 코틀린을 깊게 공부해보려 한다.

 

https://kotlinlang.org/docs/home.html

 

Kotlin Docs | Kotlin

 

kotlinlang.org

 

'백엔드 > 코틀린' 카테고리의 다른 글

Concepts:Control flow  (1) 2024.10.05
Idioms  (1) 2024.10.01
Basic syntax  (0) 2024.09.28

+ Recent posts