본문 바로가기
언어/Kotlin

[Kotlin 문법 종합] - 널 세이프티 @@수정하기

by 젼젼39 2024. 3. 6.

1. 널 세이프티

    : Null 예외로부터 안전한 설계를 위해 자료형에 Null 여부를 명시

  •     ?, !!, ?. , ?:

 

1) ?    null 할당 허용 기호

    * null 허용 여부에 따라 String과 String? 는 서로 다른 자료형임

    // null을 저장하지 않고 설계하려면 lateinit var 로 대체할 수 있음
                    <-- 이러면 나중에 null 검사 안해도 됨. 초기화할거라고 보장하는거니까.

fun main(){
    var s = Student()
    s.name = "참새"
    s.address = "서울"
    s.displayInfo()
}

class Student {
    lateinit var name:String
    var address:String? = null 			//null 저장
    
    fun displayInfo() {
        println("이름은: ${name} 입니다")
        println("주소는: ${address} 입니다")
    }
}

 

2) !!    non-null 단정 기호

    * 강제로 null이 아니라고 하는 것. (사용 지양할 것)

    //null이 있어도 컴파일은 진행되나 실행 중 예외 오류 발생...

fun main(){
//  var data = readLine()!!.toInt() 		//이렇게 한줄로 나타낼 수도 있음

    var inputData = readLine()!! 		//readLine 메소드 호출 시의 리턴값이 null이 아님을 보장
    var data = inputData.toInt() 		//여기선 null 체크를 하지 않음. 위에서 보장하니까!
    println("Null아닌 값: ${data}")
}

3) ?.  안전 호출연산자, 세이프 콜

    : null이 할당되어있을 가능성이 있는 변수를 검사, 안전하게 호출. null이면 접근 X 

fun main(){
    var s = Student()
    s.name = "참새" 		//이 단계에서 address는 null임
    s.displayAddressLength()
    
    s.address = "서울" 		//여기에서 address가 바뀜
    s.displayInfo()
}

class Student {
    lateinit var name:String
    var address:String? = null

    fun displayInfo() {
        println("이름은: ${name} 입니다")
        println("주소는: ${address} 입니다")
    }
    
    fun displayAddressLength() {
        println("주소의 길이는: ${address?.length} 입니다") 		//null이면 호출되지 않음
    }
}

4) ?:    엘비스 연산자

    : 변수가 null인지 여부를 검사, null이 아니면 좌측 식을, null이면 우측 식 실행  

fun main(){
    var s = Student()
    s.name = "참새"
    s.displayAddressLength()

    s.address = "서울"
    s.displayInfo()
}

class Student {
    lateinit var name:String
    var address:String? = null

    fun displayInfo() {
        println("이름은: ${name} 입니다")
        println("주소는: ${address} 입니다")
    }
    
    fun displayAddressLength() {
        println("주소의 길이는: ${address?.length ?: "초기화하세요"} 입니다")
        //?.length로 한번 검사를 하는데 그 뒤에 ?:로 어떤걸 리턴할지 결정
    }
}

 

 

2. 활용

fun main() {
    val worldName = "스코월드"

    var myName = inputMyInfo("name").toString() 		//" " 안에 종류 넣어주기
    var myAge = inputMyInfo("age").toString().toInt() 		//밑에서 리턴값이 숫자라서 .toString().toInt()  
	var myJob = inputMyInfo("job").toString()

    var isNamePass = true
    var names = arrayOf("참새", "꿩", "비둘기")
    for(name in names) {
        if(myName == name) {
            println("중복된 이름이 존재합니다.")
            isNamePass = false 						//밑에서 && 이용해 다 만족 시에만 넘어가게
            break
        }
    }

fun inputMyInfo(type:String): Any? { 		//모든 타입 또는 null을 반환 가능
    return when(type) {
        "name" -> {
            println("이름을 입력해주세요")
            while(true) {
                try {
                    var originName = readLine()
                    if(originName?.first() != '_' && originName?.first() != '!') { 		//.first()는 첫번째 인자 반환
                        return originName
                    } else {
                        println("이름을 다시 입력해주세요")
                    }
                } catch(e:Exception) { 						//예외처리
                    println("이름을 다시 입력해주세요")
                }
            }
        }
        "age" -> {
            println("나이를 입력해주세요")
            while(true) {
                try {
                    var originAge:String? = readLine()
                    return originAge?.toInt() ?: -1 			//originAge가 null이 아니면 .toInt()값 리턴, 아님 -1리턴
                } catch(e:Exception) {
                    println("나이를 다시 입력해주세요")
                }
            }
        }
        "job" -> {
            println("직업을 입력해주세요")
            while(true) {
                try {
                    var originName = readLine()
                    if(originName?.equals("궁수") == true || originName?.equals("마법사") == true) {
                        return originName
                    } else {
                        println("직업을 다시 입력해주세요")
                    }
                } catch(e:Exception) {
                    println("직업을 다시 입력해주세요")
                }
            }
        }
        else -> {
            return "no"
        }
    }
}