본문 바로가기

Programming/Kotlin

[Kotlin] 코틀린을 이용한 안드로이드 프로그래밍 실습 01-2

fun main(args: Array<String>) {

    println("Hello, world!")

}


- fun: 함수임을 나타내는 키워드

- main: 함수 이름 ( 여기서는 엔트리포인트가 되는 메인 함수)

- class 필요 없음 – 탑 레벨 함수 정의 가능.

- (args: Array<Sting>): 함수인자  "변수명: 타입" 

- println("Hello, world!"): System.out.println을 println으로 간단하게 사용 표준 자바 라이브러리 함수를 간소화해주는 wrapper를 제공

- ; (세미콜론) 불필요


* 이후 예제는 안드로이드 스튜디오에서… 

현재 안드로이드 스튜디오에서 직접 코틀린 메인 실행 안됨. (버그)

실제 안드로이드 예제전까지 유닛테스트의 테스트로 예제 실행



# Kotlin 파일

- 일반 파일과 클래스 파일

 • 코틀린 프로그램은 확장자가 kt인 파일

 • 파일(File)과 클래스 파일(Class) 편의상 구분 

- Java 와 같이 파일 이름과 class 이름이 같은 경우 class 파일로 인식

- 패키지는 java 와 다르게 실 경로와 맞지 않아도 가능. 그러나 가능한 실 경로와 맞게 해주는것이 편리함



# Kotlin 변수

- 변수 선언 

 • val(혹은 var) 변수명 : 타입 = 값

 • val (value)는 Assign-once 변수 → 값이 변하지 않기 때문에 setter 없음 

 • var (variable)은 Mutable 변수 → setter 있음

 • 타입 추론 지원 (타입 생략 가능)

- 변수 초기화

 • 변수 선언은 최상위(클래스 외부), 클래스 내부, 함수 내부에 선언

   * 최상위 레벨이나 클래스의 멤버 변수는 선언과 동시에 초기화 (예외 : lateinit)

 • 함수 내부의 지역변수는 선언과 동시에 초기화 필요 없음

 • 기본적으로 null 대입이 허용되지 않지만 ? 을 이용하면 허용

   ex) var str String ?= null

 • """ 으로 멀티라인 스트링 대입 가능

- 문자열 템플릿으로 사용 가능

var s1=“s1”

println(“s1=$s1”)

- 코틀린에서 변수는 프로퍼티(property) : getter, setter로 접근

- val로 선언한 변수의 초기값을 변경할 수는 없지만, 일반적인 상수변수와 다름 → 단지 setter 가 없는, 바꿀 수 없는 것

- const라는 예약어를 이용해 상수 변수 선언

- 최상위 레벨에서 선언할 때만 const 예약어 사용 가능 

var <propertyName>[: <PropertyType>] [= <property_initializer>]

[<getter>]

[<setter>]

  * [] 부분은 생략 가능(자동으로 추론됨)

  * getter, setter 는 기본적으로 만들어지지만, 재정의할 수 있음.


val topData1: Int//error
var topData2: Int//error

const var topData3: Int//error

const val topData4: Int = 10


var str: String = "aaa" // ok
var str2 = "bbb"        // 타입 추론에 의해 ok
var str3: String = null // error
var str4: String? = null // ok
var str5 = """           // ok
            abde
            efg
            high
"""
.trimIndent()

class User {
   
val objData1: String//error
   
var objData2: String//error

   
fun some(){
       
val localData1: Int//ok...
       
var localData2: String//ok...

       
println(localData1)//error
       
localData2="hello"//ok...
       
println(localData2)//ok...
   
}
}



# Kotlin - Null 처리하는 방법

- 디폴트는 null 허용되지 않음. 하지만 ? 을 이용하면 null이 허용됨.

 ① ?. 연산 : if(a != null) a.length

fun getFirstChar(text: String?): Char? {

    return text?.get(0) // textnull이면 get 메서드는 호출되지 않으며, get의 리턴 값도 null이 된다.

}

fun getTextOf(editText: EditText?): String? {

   return editText?.getText()?.toString() // 둘 중 하나라도 null 이면 null 리턴

}

 ② !! 연산 

 •  간혹 변수가 null 값이 아님이 확실한데도 Nullable로 선언된 경우(특히 Java로 정의된 메서드에 접근할 때)  변수의 이름 뒤에 !!를 붙여 Non-Null 타입으로 강제 캐스팅

 • !!로 캐스팅한 변수가 null이었다면 NullPointerException이 발생

fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {

    // inflaterNon-Null임이 확실한 상태. !!을 붙여 LayoutInflater로 강제 캐스팅한다.

    inflater!!.inflate(R.layout.fragment_statistics, container)

    return super.onCreateView(inflater, container, savedInstanceState)

}

 ③ ?: 연산(앨비스 연산) : Kotlin에는 삼항연산자 없음.

fun function(param: Map<String, String>) {

    // 만약, param.get("key")의 값이 null이면 ?: 오른쪽에 있는 "default value"value에 대입된다.

    val value = param.get("key") ?: "default value"

}

 ④ as 연산자(캐스팅 연산자)

 • 캐스팅 불가능한 경우 ClassCastException 발생

 • as? 연산자는 ClassCastException이 발생해야 하는 상황에 에러 발생 없이 Null 리턴


# Kotlin - lateinit, lazy

- lateinit : 초기화 지연 프로퍼티(Late-initialized property). modifier

lateinit var lateT01:String

 * 나중에 함수의 로컬영역에서 꼭 초기화 시킨 후 실행시켜야함.

- lazy : 초기화 지연시킬 때 사용. 람다를 파라미터로 받고 Lazy<T> 인스턴스를 반환

val lazyT01: String by lazy {
println("Hello lazyT01")
"abde"
}

 * println(lazyT01) 해보면 Hello lazyT01, abde 가 순서대로 나온다.

- 둘의 차이점

 • lateinitvar 타입만 가능하고 lazyval 타입만 가능

 • lateinit은 primitive type은 불가능하나 lazy는 가능

 • lateinit은 Non-null 타입만 가능하나 lazy는 둘 다 가능

 • lateinit은 로컬 변수에서는 불가능 하나 lazy는 가능



# Kotlin - 숫자 타입

- Int, Double 등은 클래스이며 이 클래스로 타입을 명시하여 선언한 변수는 그 자체로 객체

Type

Bit width

Double

64

Float  - f

32

Long  - L

64

Int

32

Short

16

Byte

8

 * -f, -L : 자동으로 타입 추론 가능

- 코틀린의 숫자 타입의  클래스들은 모두 Number 타입의 서브 클래스

- 문자(Characters)는 Number Type이 아니다.

- Number Type에 대한 자동 형 변형(implicit conversions for number)을 제공하지 않는다. : ToXXX() 변환 함수 사용

- 숫자 타입에 대입되는 데이터에 언더바(Underscore) 추가 가능(가독성 Up!)

 ex) val oneMillion: Int = 1_000_000 

 


# Kotlin - 논리, 문자, 문자열타입

val isTrue1: Boolean = true && false

val isTrue2: Boolean = true || false
val
isTrue3: Boolean = !true
val
charData='C'
var charData2:Char ='C'
var str0: String = "Hello"



# Kotlin - Any, Unit, Nothing 타입

- 코틀린 클래스의 최상위 클래스는 Any (Java의 Object 느낌)

- Unit : 기본 리턴 (java 의 void 느낌), 생략 가능

- Nothing : 의미 있는 데이터가 없다는 것을 명시적으로 선언하기 위해 사용하는 타입

 • return 타입이나 인자로만 사용

 • 리턴도 없고, 호출코드로 복귀하지 않을 때 사용 가능



# Kotlin - collection 타입

타입

함수

특징

List

List

listOf()

Immutable

MutableList

mutableListOf()

mutable

Map

Map

mapOf()

Immutable

MutableMap

mutableMapOf()

mutable

Set

Set

setOf()

Immutable

MutableSet

mutableSetOf()

mutable


Iterator “ hasNext() 함수와 next() 함수를 이용해 순차적 이용

val list1= listOf<String>("hello","list")
val iterator1=list1.iterator()
while (iterator1.hasNext()){
    println(iterator1.next())
}



# Kotlin - is, as

- is (!is) : java 에서의 instanceof. true 또는 false 리턴

fun getStringLength(obj: Any): Int? {

    if (obj is String) {

    // 'obj' is automatically cast to 'String' int this branch

    return obj.length

    }

    // 'obj' is still of type 'Any'

    // TypeString이 아니라서 nullreturn 하게 됩니다.

    return null

}

- as (as?) : 타입 캐스팅

 • val x: String? = y as? String // 캐스팅에 실패할 경우 Exception이 발생하지 않고 x에 null값이 대입된다. 

 • 별칭으로도 사용 ex) import MotorCycle.Engine as engine


# Kotlin - 함수

- 함수 선언 

 • fun 함수명(매개변수명 : 타입) : 리턴타입 { } 

 • 매개변수에는 var, val 선언불가 (클래스 primary 생성자는 var, val 사용 가능)

 • 의미있는 반환값이 없을 때는 Unit (void) – 생략가능

 • 탑레벨 함수 선언 가능 

 • 함수내에 함수(지역함수) 선언 가능 

 • Class 안의 멤버 함수 선언 가능 -> Java로 디컴파일 해보면 클래스 내 static 메소드로 생성됨

 • 함수 오버로딩 가능 -> open 해줘야함(?)

 • 기본 인수(default parameter)와 명명된 인수(원하는 parameter) 사용 가능

 • 확장함수 가능 : 이미 만들어진 클래스를 확장해서 메소드를 만들 수 있음

fun Int.addex(){

  ~~~~~~~~~

}

1.addex()

 • Infix 로 중위 표현식을 함수 호출에도 사용이 가능  ex) a add b

  * 클래스의 맴버 함수로 선언되거나 혹은 클래스의 extension 함수인 경우

  * 하나의 매개변수를 가지는 함수의 경우 

 • 가변인수 : vararg, 함수의 파라미터가 몇 개가 될지 모를 때

 • 재귀함수 

  * Tailrec 꼬리재귀함수 가능 : 재귀함수로 컴파일하는 것이 아닌 while문으로 컴파일 하여 최적화(stack overhead 발생 줄임), 사용 가능한 조건 있음(예를 들면 끝이 있다던지!)

 • 제너릭 함수 가능 : 타입을 parameter로 넘길 수 있음

 • 람다 함수 가능 : 함수를 식으로 만들 수 있음

 • 하이 오더 function(고차함수) 가능 : 함수를 parameter로 사용 가능

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

fun sayHello(name: String = "kkang", no: Int){
      println("Hello!!"+name)
}
fun main(args: Array<String>) {
      // sayHello(10)//error
      sayHello("lee", 20)
      sayHello(no=10)
      sayHello(name="kim", no=10)



# Kotlin - if문

- 코틀린에서 if는 표현식(expression) 가능

fun main(args: Array<String>) {

    val a = 5
   
if (a < 10) println("$a < 10")

    //if - else
   
if (a > 0 && a <= 10) {
        println("0 < $a <= 10")
 
   } else if(a > 10 && a <= 20){
        println("10 < $a <=20")
    }else {
        println("$a > 20")
    }
}
val result=if (a > 10) "hello" else "world"   // else 문이 꼭 필요함



# Kotlin - when (switch-case문 upgrade 버전)

- 표현식

- 문자가능, is 를 통한 타입 가능

- 여러 값 조건 표현 가능 ( , 이용)

- 범위 조건 표현 가능 ( .. 이용)

- 다양한 타입에 대한 조건 표현 가능

- else 가 꼭 있어야함

fun main(args: Array<String>) {

    val a2=1
    when (a2) {
        1 -> println("a2 == 1")
        2 -> println("a2 == 2")

        in 3..10 -> println("3 <= a2 <= 10")

        else -> {
            println("a2 is neither 1 nor 2.... 3~10도 아님!")
        }
    }
}


* 디컴파일해보면 모두 if-else if 구조로 되어있다.



# Kotlin - 반복문

- for 반복문

fun main(args: Array<String>) {

    var sum: Int=0
    for(i in 1..10) {
        sum += i
    }
    println(sum)
}

- while, do-while 반복문 가능

- break와 continue 사용 가능

 • label 사용 가능 : 약간 goto 문 느낌? 그래서 잘 사용되지 않을 것

for(){

@label1

…..

continue @label1

}



# Kotlin - 연산자

- 코틀린은 연산자가 연산함수로 변경되어 처리하므로 연산자 오버로딩 가능

- 산술/대입/전개/복합/증감/논리/일치/비교/범위/nullcheck 등의 연산자



# Kotlin - 예외처리

- Java 와 같이 try-catch-finally 로 표현

- Checked exception 없음. (예외 강요하지 않음)

- 식으로 사용 가능. – 맨 마지막 값이 반환값.

fun readNumber(reader: BufferedReader) {

    val number = try {

        Integer.parseInt(reader.readLine())

    catch (e: NumberFormatException) {

        null

    }

    println(number)

}


# 출처 : 모베란 백지훈 대표이사님