[Kotlin/코틀린] 8. 접근제한자, 예외 처리, 지연초기화, 널 세이프티

2023. 12. 12. 20:30스파르타/Kotlin

4주차 '객체지향 프로그래밍의 심화' 강의 내용 정리

 

8-1. 접근제한자

 

변수나 메소드의 접근을 제한할 수 있다.

코틀린에서는 public, private, internal, protected 로 접근을 제한한다.

객체를 이용해서 변수나 메소드를 호출할 수 있는 지의 여부를 접근이라고 한다.

 

 

용어 정리

프로젝트 : 최상단 개념이고 <모듈, 패키지, 클래스> 를 포함한다.

모듈 : 프로젝트 아래의 개념이고 <패키지, 클래스> 를 포함한다.

패키지 : 모듈 아래의 개념이고 <클래스> 를 포함한다.

 

 

public : 명시하지 않으면 기본적으로 public 이다. (어디서나 접근 가능)

private : 동일한 클래스 내부에서만 접근할 수 있다.

internal : 같은 모듈 내부에서만 접근할 수 있다.

protected : 기본적으로 private 이지만 상속을 받은 경우에 타 모듈에서 접근할 수 있다.

 

 

접근제한자가 필요한 이유

접근권한을 통해 데이터에 무분별한 접근을 막을 수 있다.

클래스들간에 접근하면 안되는 상황을 구분하기 때문에 향후 유지보수를 하기 용이하다.

 

 

 


 

 

8-2. 예외 처리

 

프로그램을 실행하기 전에 알 수 있는 컴파일 에러를 오류라고 한다.

프로그램을 실행하는 도중에 발생하는 런타임 에러인 예외가 발생할 수 있다.

실행 도중에 예외가 발생하면 프로그램이 비정상적으로 종료된다.

코틀린은 try-catchthrow 로 예외를 처리한다.

 

 

 

 

 

try-catch 기본 구조

fun method1() {
    try {
        예외가 발생할 가능성이 존재하는 코드
    } catch(예외종류) {
        예외가 발생했을때 처리할 코드
    }
}

 

 

 

 

 

 

 

throw 기본 구조

fun method1(num1:Int) {
    if(num1 > 10) {
        throw 예외종류
    }
}

 

 

 

 

 

예외 처리가 필요한 이유

 

고품질의 프로그램이란 사용성을 해치지 않아야 한다.

여러 측면의 사용성이 있지만 프로그램이 도중에 종료되는 것은 심각한 문제이다.

미리 예외를 생각하고 소스코드를 작성해야 안정성을 높인 프로그램이라 할 수 있다.

예를 들어 숫자를 입력받아서 더하는 프로그램인데 실수로 문자를 입력했다면 예외를 처리해야 한다.

다른 예시로 사진을 다운로드 받는 도중 인터넷이 끊긴다면 예외를 처리해야 한다.

또 다른 예시로는 수술을 받고 있는데 메인 전력이 끊겼다면 보조 전력을 사용하도록 예외를 처리해야 한다.

 

 

 

 

 

 

예시 코드 1

예외를 처리한 상황 (try-catch)

while(true) {
    try {
        var num1 = readLine()!!.toInt()
        println("내가 입력한 숫자는 ${num1}입니다")
        break
    } catch(e:java.lang.NumberFormatException) {
        println("숫자를 입력하세요")
    }
}

 

입력한 내용을 toInt 메소드로 정수 변환할 때 예외가 발생한다.

숫자를 입력할 때까지 반복문을 무한으로 실행하는 코드이다.

break 는 가장 가까운 반복문을 탈출시켜 주는 키워드이다.

 

 

 

 

 

 

예시 코드 2

예외를 처리한 상황 (try-catch-finally)

while(true) {
    try {
        var num1 = readLine()!!.toInt()
        println("내가 입력한 숫자는 ${num1}입니다")
        break
    } catch(e:java.lang.NumberFormatException) {
        println("숫자를 입력하세요")
    } finally {
        println("키보드와의 연결은 정상적입니다")
    }
}

 

예외 처리와 관계없이 항상 실행하는 코드를 finally 에 작성한다.

* 실제 예시 1) USB와 연결하는 코드는 반드시 사용후에 연결을 끊어야 한다. (자원낭비)

* 실제 예시 2) GPS를 사용하는 코드는 반드시 사용후에 연결을 끊어야 한다. (자원낭비)

 

 

 


 

 

8-3. 지연초기화

 

코틀린은 클래스를 설계할 때 안정성을 위해 반드시 변수의 값을 초기화 할 것을 권장한다.

클래스를 설계할 때 초기의 값을 정의하기 난처해서 나중에 대입하기 위한 문법이다.

코틀린은 지연초기화 또는 늦은초기화를 위해 lateinit, lazy 키워드를 활용한다.

저사양으로 제한되어 있는 환경에서는 메모리를 더욱 효율적으로 사용할 수 있다.

 

 

 

 

 

예시 코드 1

변수의 지연초기화

fun main(){
    var s1 = Student()
    s1.name = "참새"
    s1.displayInfo()

    s1.age = 10
    s1.displayInfo()
}

class Student {
    lateinit var name:String
    var age:Int = 0

    fun displayInfo() {
        println("이름은: ${name} 입니다.")
        println("나이는: ${age} 입니다.")
    }
}

name 변수 값을 초기에 정의하기 어렵기 때문에 lateinit 을 사용한다.

물론, ""과 같이 공백으로 처리할 수 있지만 가독성 측면에서 좋은 행위는 아니다.

 

 

 

 

class Student {
    lateinit var name:String
    var age:Int = 0

    fun displayInfo() {
        if(this::name.isInitialized) {
            println("이름은: ${name} 입니다.")
            println("나이는: ${age} 입니다.")
        } else {
            println("name변수를 초기화해주세요.")
        }
    }
}

 

변수를 사용하기 전에 초기화 되었는지 확인해야 안정성을 높일 수 있다.

isInitalized 를 활용해서 값이 초기화 되었는지 확인할 수 있다. (true/false)

사용할 때는 값이 아니라 참조 형태로 사용해야 하기 때문에 this:: 또는 :: 을 붙인다.

 

 

 

 

 

 

예시 코드 2

상수의 지연초기화

 

fun main(){
    var s1 = Student()
    s1.name = "참새"
    s1.displayInfo()

    s1.age = 10
    s1.displayInfo()
}

class Student {
    lateinit var name:String
    var age:Int = 0
    val address: String by lazy {
        println("address 초기화")
        "seoul"
    }

    fun displayInfo() {
        println("이름은: ${name} 입니다.")
        println("나이는: ${age} 입니다.")
        println("주소는: ${address} 입니다.")
    }
}

 

lazy 키워드를 활용해서 지연초기화를 한다.

상수를 사용하는 시점에 값을 대입하고 초기화가 수행된다.