우당탕탕 앱 도전기/kotlin

[kotlin] Array,list,반복문,nullable/nonnull

그린푸딩 2022. 10. 6. 00:21
728x90
반응형

지난번에 이어서 코드윗조이스님의 코틀린강의 1강에서 배운걸 정리해보려고 한다.  뒷부분의 짧은부분이긴한데.. 사실 뭔가 짚고 넘어갈 생각할 부분들이 좀 있어서 좀 오래걸렸다. cs공부 복습한다 생각하고 그때그때 정리하고 넘어가야지!

 

5. Array 와 List 

//5. Array and List

fun array() {
    // Array: 만들때 크기 정해져서 나옴 (mutable) 값 변경 가능
    val array: Array<Int> = arrayOf(1, 2, 3)
    val array2: Array<Any> = arrayOf(1, "a", 3.4f)
   // List : 1.List(수정 불가능) 읽기 전용 2. MutalbeList(수정가능)  읽기/쓰기
    val list: List<Int> = listOf(1, 2, 3)
    val list2: List<Any> = listOf(1, "a", 11L)

    //2. mutableList
    val arrayList : ArrayList<Int> = arrayListOf<Int>() //집주소 자체는 바뀌지 않음
    arrayList.add(10)
    arrayList.add(20)

    //arrayList=arrayListOf() 이건 안됨
    // arrayList-arrayListOf() //??
}

 

kotiln에는 array, list가 있는데 array의 경우 만들때 크기가 정해져서 나오고, 값을 변경할수 있다. list의 경우 값을 변경할수 없는 버전(읽기 전용) 과 변경할수 있는 버전(앍가 +쓰기) 이  있다. 

 

Array 

  • 선언시 크기로 고정됨
  • 선언된 요소 내에서 값 변경 가능(mutable)
  • val array : Array<타입> = arrayOf(원소1,원소2..) 
  • '타입' 부분에 Any를 설정할경우 원소 타입을 다르게 해도 된다. 

🤔 약간 헷갈리는게 구글링해보니까 (array)=(array).plus(원소) 형식으로 값을 추가하는 방식이 있었다.  선언시 크기가 정해진다는게 배열 크기가 고정된다는 의미이라면 저 plus는 뭘까..? array.plus(값)하고 출력해보았는데 새로 들어간 값은 출력되지 않았다. 아마도 기존 array는 바뀌지 않고 새로운 배열이 생성되는게 아닐까..? 나중에 알게되면 다시 정리해야지

그리고 Any도 자바의 제네릭같은 느낌인데  동일한 특징을 가지고 있을까? + 제네릭의 컴파일시 타입보장이란? 

 

List

  • 선언시 크기 고정,값 변경 x 버전; val list: List<타입> = lisftOf(원소1,원소2..) 
  • 선언시 크기 고정x,값 변경 O 버전 (mutableList) ; val arrayList : ArrayList<타입>=arrayListOf<타입>() -> arrayList.add(원소) 
  • 집에서 누가 들어오고 나와도 집주소는 변경되지 않듯이 mutablelist에서 뭐가 추가되어도 주소는 바뀌지 않음

맨위의 코드상에서  어쩌다가 arrayList-arrayListOf()를 했는데 오류가 안떠서 출력해보았는데 arrayList 전체가 출력되었다. 뭐지?

 

자바가 주언어가 아니라서 자바도 헷갈리는데 배열에서 헤매기 시작했다. 이러다 다차원 배열나오고 삽입,삭제 시간복잡도 계산하는거까지 공부하면... 코틀린으로 코테 보시는분들은 대단한것 같다. 뭐 지금은 처음 공부하는거니까 최대한 재밌게 공부하자ㅎㅎ

 

 

6. 반복문  for/ while 

 

//6. 반복문  for / while
fun forAndWhile(){

    val students:ArrayList<String> = arrayListOf("hi","hello","bye","b")
    for( name in students){
        println("${name}")  //그냥 name해도 되지 않나
    }
    //withIndex -> 인덱스와 함께 사용 가능
    for((index,name) in students.withIndex()){
      println("${index+1}번째 : ${name}")
    }
    var sum:Int=0
    for(i in 1..10 step 2){ //1,3,5,7..
        sum+=i
        println(sum)
    }
    for(i in 10 downTo 1){ //10,9,8,7..
        sum+=i
        println(sum)
    }
    for( i in 1 until 100){ //1..99   1..100은 100까지
        sum+=i
        println(sum)
    }
    var index=0
    while (index<10){
        println("current Index: ${index}")
        index++
    }
}

 

for 반복문의 경우 배열 내 원소를 출력하고 싶으면 >>  for(변수 in 배열) 혹은 인덱스를 표시하고 싶으면 for((index 표시변수,변수) in  배열.withIndex())로 사용하면된다. 

아니면 단순 반복 작업을 하고싶은거라면 >> for(i  in 처음 숫자..끝숫자) 이고, 만약 간격을 띄우고 싶으면 step 간격수 를 뒤에 덧붙이면  된다. 내림차순은  for(i in 끝숫자 downTo 첫숫자)임. 주의할것은 for( i in 첫숫자 until 끝숫자) 형식이면 끝숫자는 포함아니다. 내림차순 있는건 꽤 편해보인다.

while의 경우  while(조건) 형식이다. 

 

7. NonNull과  Nullable  - 자바와 다른 코틀린만의 가장 큰 특징

자 이제 대망의 1강에서 개인적으로 어렵다고 느껴지는 부분이다. null 값의 위험성은 아직 체험하지 않아봐서 null을 예외처리하는것의 중요성을 약간 책으로만 간접적으로 알고 있다. 클린코드에서도 오류처리할때 이부분이 있었던게 언뜻 생각났었다. https://sunnn21.tistory.com/27  그래도 이부분  배우면서 약간 오픈소스 언어를 개발하는것에 대한 흥미가 커졌다.. 편리성을 증진하기 위해 기존 언어에서 뭔가를 조금씩 바꾸거나 추가하는 작업이 매력적으로 보였다. 

 

//7. NonNull과 Nullable - 자바와 다른 코틀린만의 가장큰 특징

fun  nullcheck(){
    //NPE Nullpointer Exception - 자바: 컴파일x 런타임 시점 알수 있음
    //컴파일 시점바꾸기 위한것 null 넣고 싶으면 ?넣기
    var name: String ="joyce"  //생략할수 있음
    var nullName: String? =null //null 타입하려면 생략하면 안됨

    var nameInUppeCase = name.toUpperCase()
     var nullNameInUpperCase : String? = nullName?.toUpperCase() //null이면 null 반환 아니면 그대로..

    // ?:
    val lastName: String? = null
    val fullName = name+" "+ (lastName?: "No last Name")
    var mLastName :String =lastName ?:  throw IllegalArgumentException("No Last Name")
    println(fullName)
}

//null 타입 매우 중요
//!!
//let 자신의 리시버 객체를 람다식 내부로 옮겨줌
fun IgnoreNulls(str:String?){
    var mNotNull: String =  str!! //절대 null일리가 없어!!
    val upper = mNotNull.toUpperCase() //오류 안뜸, mNotNull의 null타입 체크안해도됨
    val email:String? = "hello@gmail.com"
    email?.let{println("my email is${email}")}
}

 

자바: NPE Nullpointer Expection 컴파일x 런타임 시점에 알수 있음/ 컴파일 에러와 런타임 에러의 차이를 간단히 생각해보면 무한 루프같이 코드상으로는 크게 문제 없는데 돌려보면 큰 문제가 있는걸 생각할수 있다. c/c++도 정리하기

컴파일단계에서 이것을 잡기 위해 kotin에서 "?" 라는게 도입되었다.  변수를 선언할때 변수에 null이 들어갈수 있으면 타입옆에 ?를 붙이면 된다. 

 

 

  var name: String ="joyce"  //생략할수 있음
  var nullName: String? =null //null 타입하려면 생략하면 안됨
  var nameInUppeCase = name.toUpperCase()
  var nullNameInUpperCase : String? = nullName?.toUpperCase() //null이면 null 반환 아니면 그대로..

 

?

nameInputCase에서 name에 ?가 붙지않은이유는 name이 null이 아니므로... 하지만 nullName은 null의  위험이  있는것이다. 따라서 다른 변수에 대입할때 nullName?으로 대입하여 null이면 null을,  아니면 그 값을 대입시키도록 한다. 그리고 대입되는 변수에도 ?를 붙인다. 약간 줄줄이 다 붙여주는거 같다. 

 

 

var mLastName :String =lastName ?:  throw IllegalArgumentException("No Last Name")

 

Elvis operator ?:

?:의 경우는  앞의 내용이 null경우 뒤에 코드를 실행한다.

 

 

//null 타입 매우 중요
//!!
//let 자신의 리시버 객체를 람다식 내부로 옮겨줌
fun IgnoreNulls(str:String?){
    var mNotNull: String =  str!! //절대 null일리가 없어!!
    val upper = mNotNull.toUpperCase() //오류 안뜸, mNotNull의 null타입 체크안해도됨
    val email:String? = "hello@gmail.com"
    email?.let{println("my email is${email}")}
}

 

!!

!!은 절대 null일리가 없음을 알릴때 쓴다고 한다. 하지만 어떻게 확신할수 있는가.. 약간의 위험이 따름 

 

let

let은 자신의 리시버 객체를 람다식 내부로 옮겨준다는데..  코틀린에서 리시버,람다식 개념이 중요하다고 하는것 같다.. 좀더 자세히 알아봐야겠다.

 

너무 길다.. 남은 내용은 다음 포스트에..

728x90
반응형