세현's 개발로그

Kotlin 개발 완전 정복(2) 본문

Kotlin

Kotlin 개발 완전 정복(2)

SarahPark 2022. 10. 6. 15:13

#1 컬렉션 개요

◎ 컬렉션은 단순히 같은 데이터 타입 또는다른 데이터 타입의 묶음이다.

코틀린에서 컬렉션은 두 가지 분류로 나뉜다.

 

ⓛ특정 데이터 타입의 요소를 저장하는 클래스

ex)

- IntArray-Integer

- BooleanArray-Boolean

- DoubleArray-Double

- ByteArray-Byte

- LongArray-Long

- ShortArray-Short

- FloatArray-Float

②서로 다른 타입의 요소도 저장 가능한 클래스

ex)

- arrayOf<String>

- arrayOf<Fruit>

- array(1,2,"John","Doe",0.5,Fruit())

 

◎ Immutable Collections : 이뮤터블은 값을 읽을 수는 있지만 변경할 수 없다는 것이다.

- List-listOf : List는 arrayOf랑 비슷하지만, 더 많은 연산 메서드 도우미가 있다. 또한 필요시 크기도 쉽게 키울 수 있다.

- Set-setOf : Set는 중복되는 값이 없게 하는 클래스이다.

- Map-mapOf : Map는 key와 값이 한 쌍으로 정리되는데, 이 키로 값을 찾을 수 있다.

 

◎ Mutable Collections : list, set, map을 읽고 기재하기 좋은 특별한 클래스들이다. 이런 방법으로, 공개적으로 수정할 수 있는 요소와 비공개 요소를 분리할 수 있다.

- Mutable List - ArrayList, arrayListOf, mutableListOf

- Mutable Set - mutableSetOf, hashSetOf

- Mutable Map - Hashmap, hashMapOf, mutableMapOf

 

#2 리스트

같은 정수 리스트를 표현하는 방법 세 가지

val numbers: IntArray = intArrayOf(1, 2, 3, 4, 5, 6)
val numbers = intArrayOf(1, 2, 3, 4, 5, 6)
val numbers = arrayOf(1, 2, 3, 4, 5, 6)

◎ 리스트의 요소를 출력하는 방법

val numbers = arrayOf(1, 2, 3, 4, 5, 6)
    
print(numbers.contentToString()) // 출력은 [1, 2, 3, 4, 5, 6]
for (element in numbers) {
    print(element) // 출력은 123456
}

◎ 리스트의  특정 요소를 출력하는 방법

val numbers = arrayOf(1, 2, 3, 4, 5, 6)

print(numbers[0]) // 출력은 1

 

#3 집합과 맵

◎ 세트는 중복되는 데이터를 삭제하는 컬렉션이다. 이뮤터블 클래스는 setOf, 뮤터블 타입은 mutableSetOf 이고, hashSetOf이 있다.

val fruits = setOf("Orange", "Apple", "Mango", "Grape", "Apple", "Orange") //immutable
print(fruits.size) // 중복되는 원소를 중복 제거하였을 때 총 원소의 개수는 4개이므로 4가 출력된다.
print(fruits.toSortedSet()) // 알파벳 순으로 정렬하여 출력은 [Apple, Grape, Mango, Orange]

val newFruits = fruits.toMutalbleList()
newFruits.add("Water Melon")
newFruits.add("Pear")
print(newFruits) // 출력은 [Apple, Grape, Mango, Orange, Water Melon, Pear]

◎ 맵은 키와 값을 짝 형태로 데이터를 저장하는 컬렉션이다. 키는 하나의 값만 저장할 수 있다.

val daysOfTheWeek = mapOf(1 to "Monday", 2 to "Tuesday", 3 to "Wednesday")
print(daysOfTheWeek[2]) // 출력은 Tuesday
for(key in daysOfTheWeek.keys){
    print("$key is to ${daysOfTheWeek[key]} ") // 출력은 1 is to Monday 2 is to Tuesday 3 is to Wednesday 
}

 

#4 배열 리스트(Array List)

◎ 배열 리스트는 동적 배열을 생성하는 것이며, 컬렉션의 일종이다.

- 배열 리스트는 동적 배열을 만들어주므로 크기가 특정 크기에 제한되지 않는다.

- 배열 리스트는 읽기용과 쓰기용으로 둘 다 가능하다. 

- 배열 리스트는 삽입 시퀀스 순서를 따른다. 뭔가를 추가할 때 중요한 부분이다.

- 배열 리스트는 동기화되지 않아 중복 요소를 허용한다. 즉, 같은 값을 입력하는 것은 제한되지 않는다.

 

◎ 배열 리스트 생성자

- ArrayList<E>() : 비어 있는 배열 리스트를 만들 때 사용되는 생성자 

- ArrayList(capacity: Int) : 용량을 정할 수 있는 생성자 즉, 요소의 최대량을 정할 수 있는 것이다.

- ArrayList(elements: Collection<E>) : 컬렉션을 기반으로 배열 리스트를 생성할 수 있다. 컬렉션 요소로 채우고 필요할 때 사용 가능

 

◎ 배열 리스트의 함수

- open fun add(element: E): Boolean : add 함수는 특정 요소를 컬렉션에 추가 가능

- open fun clear() : clear 함수는 컬렉션에서 모든 요소를 제거함

- open fun get(index: Int): E : get 함수는 특정 인덱스값의 정보를 돌려줌

- open fun remove(element: E) : Boolean : remove 함수는 컬렉션에서 특정 요소의 한 예시를 제거함

 

#5 람다식

◎ 람다 표현식은 고급 기능을 가진 코드를 간결하고 짧게 정리해준다. 

◎ 람다 표현식과 익명 함수는 '함수 리터럴'이다. 예를 들어 선언되지 않고 곧바로 표현식으로 전달된 함수이다.

◎ 람다는 중괄호로 정의되고, 매개변수와 함수 바디로 변수를 받는다. 매개변수로 변수를 받아도 되지만, 꼭 그런 것은 아니다. 

◎ 함수 바디는 변수 뒤에 화살표와 연산자와 함께 쓰인다.( -> 이것이 람다 연산자)

◎ 문법 : { 변수 -> 람다 바디}

sum1: (Int, Int) -> Int = { a: Int, b: Int -> a + b }
println(sum1(10, 5))
// 더 짧게 표현 가능
val sum2={a:Int,b:Int->println(a+b)}
sum2(10,5)

 

#6 접근 제한자

◎ 접근 제한자는 코틀린에서 클래스, 인터페이스, 프로퍼터를 제한하는 데 사용하는 키워드이다. 접근 제한자는 클래스 헤더나 메소드 바디 등 여러 곳에서 사용된다. 

 

◎ public

- 공개적으로 수정된 요소는 프로젝트 어디서든 접근 가능하다.

- 코틀린에서 기본 제한자이고, 따로 명시되지 않는다면 요소는 자동으로 공개이다.

 

◎ private

- 이는 프로퍼터, 필드 등이 선언된 블록에서만 요소에 접근할 수 있게 해준다. 이는 최상위에 선언된다.

- private 제한자 선언은 스코프 밖으로의 접근을 막는다. 따라서 private 패키지는 그 특정 파일 내에서만 접근 가능하다.

 

◎ internal

- internal 제한자는 자바에 없는 코틀린만의 기능이다.

- internal 제한자는 시행된 모듈 안에서만 필드가 보이게 된다.

 

◎ open keyword

- 코틀린에서 모든 클래스는 자동으로 최종값이다. 즉, 자동으로 상속받을 수 없는 것이다. (자바랑은 반대-모든 클래스가 상속할 수 있기 때문에 최종이라고 명시해야 함)

- 상속을 사용하려면, 클래스를 open으로 만들어야 한다. 아니면 오류가 난다.

 

◎ protected

- protected 제한자는 그 안의 클래스 또는 서브 클래스에 보이도록 해준다. 서브 클래스 안의 오버라이딩 한

protected 선언은 변경을 명시하지 않는 한 보호받는다.- protected 제한자는 최상위에 선언될 수 없다. 즉, 패키지는 보호받을 수 없다.

open class Base(){
    var a=1 //public by default
    private var b=2 //private to Base class
    protected open val c=3 //visible to the Base and the Derived class
    internal val d=4 //visible inside the same module
    protected fun e(){} //visible to the Base and the Derived class
}
class Derived: Base(){
    //a,c,d,and e() of the Base class are visible
    //b is not visible
    override val c=9//c is protected
}
fun main(args: Array<String>){
    val base=Base()
    //base.a and base.d are visible
    //base.b, base.c and base.e() are not visible
    val derived=Derived()
    //derived.c is not visible
}

 

#6 중첩, 내부 클래스

◎ 다른 클래스 안에 생성된 클래스 vs 키워드 inner를 사용한 다른 클래스 안의 클래스

 

◎ 중첩 클래스 : 다른 클래스 안에 생성되어 자동으로 정적이다.

- 그 데이터 멤버와 멤버 함수는 클래스 객체를 생성하지 않고도 접근할 수 있다.

- 또한 중첩 클래스는 외부 클래스의 데이터 멤버에 접근할 수 있다. (일방적인 관계)

 

◎ 내부 클래스 : 키워드 inner로 다른 클래스 안에 만들어진 클래스이다.

- 중첩 클래스와 차이점은 내부 클래스는 인터페이스 안에 또는 내부 중첩 클래스가 아닌 곳에 선언될 수 없다는 것이다.

- 장점은 private이더라도 외부 클래스 멤버에 접근 가능하다.

- 내부 클래스는 외부 클래스 객체의 참조를 저장한다.

class OuterClass{
    private var name: String="Mr X"
    inner class InnerClass{
        var description:String="code inside inside class"
        private var id: Int=101
        fun foo(){
            println("name is ${name}") //외부 클래스의 멤버가 private이지만 접근 가능하다. (중첩 클래스에서는 불가능)
            println("Id is ${id}")
        }
    }
}

fun main(args:Array<String>){
    println(OuterClass().InnerClass().description) //내부 클래스의 프로퍼터에 접근 가능
    var obj=OuterClass().InnerClass() //객체 생성
    obj.foo() //멤버 함수에 접근
}

출력 :

code inside inside class
name is Mr X
Id is 101

 

#7 Safe Cast, Unsafe Cast 연산자

◎ 특정 타입의 것을 다른 타입으로 캐스트할 때 사용

 

◎ Unsafe cast

- 키워드 as가 사용된다.

- 어떤 때는 변수를 캐스트하지 못하고 예외 처리된다. 그것이 바로 불완전 캐스트이다.

fun main(args: Array<String>){
    val obj:Any?=null
    val str: String=obj as String
    println(str)
}

출력 :

Exception in thread "main" java.lang.NullPointerException: null cannot be cast to non-null type kotlin.String

- 물음표가 있는 널러블 스트링은 널러블 스트링이 아닌 걸로 캐스트될 수 없다. 이는 예외 처리된다.

- 예시에서 any 널러블 타입의 객체의 값이 null로 되어있는데, obj 객체를 스트링으로 캐스트하고, 만든 스트링을 출력하려 하니까 예외 처리가 된다.

 

◎ Safe cast

- 키워드 as?가 사용된다. 이는 한 타입으로 안전하게 캐스팅 하도록 도와준다. 불가능하다면, null만 돌려준다.

fun main(args: Array<String>){
    val location: Any="Kotlin"
    val safeString: String?=location as?String
    val safeInt: Int?=location as?Int
    println(safeString) // 출력은 Kotlin
    println(safeInt) // 출력은 null
}

- safeInt는 int 널러블이고 location을 정수로 받으려고 한다. 하지만 "Kotlin"은 정수가 될 수 없기 때문에 안전한 캐스팅이 되어 null이 출력된다.

 

#8 Try-Catch 문으로 예외 처리하기

◎ Exception이란?

: 프로그램의 런타임 문제고, 프로그램의 종료를 초래한다. 핸드폰에서는 앱이 반응하지 않는 것이다. 

예를 들어, 저장 공간 부족, out of bound 배열, 0으로 나눈 조건이 있다.

-> 프로그램 실행에서 이런 문제를 처리하기 위해 예외 처리를 한다. 이는 런타임 문제를 처리하고 프로그램의 원활한 실행을 지속시켜 준다. 

 

◎ 예외 처리에서 4개의 키워드 : try, catch, finally, throw

 

- try : try 블록은 예외를 발생시킬 수 있는 구문 세트를 포함한다. catch나 finally, 아니면 둘 다 꼭 뒤에 따라와야 한다. 이는 더 많은 오류, 예외를 만들 수 있는 코드이다. 예를 들어, 인터넷 연결이나 배열 검토하는 것.

- catch : catch 블록이 try 블록에서 던져진 예외를 잡는 것이다. try 블록에 예외가 있으면, catch 블록이 실행되고 아니면 실행되지 않는다. 예를 들어, 인터넷이 연결되지 않으면 catch 블록이 실행된다.

- final : final 블록은 예외가 처리되든지 말든지 실행된다. 그래서 중요한 코드 구문을 실행하는 데 사용된다. 예로는 인터넷 연결을 처리하는 버퍼를 닫을 때 실행된다.

- throw : 이는 명료하게 예외를 던지게 해준다. 이는 오류를 일으키기 위해 입력하는 것이다. 오류가 어디서 나는지 테스트할 때 매우 유용하다.

 

◎ Unchecked Exception

- Unchecked 예외는 코드 실수 때문에 던져지는 예외이다.

- Unchecked 예외는 실행 버튼을 눌러 앱을 컴파일할 때가 아닌, 앱이 실행되는 런타임에 확인된다. 이는 런타임 예외 클래스에서 확장한 것이다.

ex)- Arithmetic exception : 숫자를 0으로 나눴을 때 발생함.

- ArrayIndexOutOfBoundExceptions : 틀린 인덱스 값으로 배열을 확인할 때 발생함.

- SecurityException : 보안 위반일 때 발생함. 예를 들어, GPS를 사용하려 하는데, GPS 기능을 사용할 권리를 주지 않아 접근할 수 없을 때

- NullPointerException : Null Pointer Exception은 null 객체에 메소드나 프로퍼터를 호출할 때 발생함.

 

◎ Checked Exception

- Checked Exeption은 컴파일 타임에 확인되는 예외이다. 이는 Throwable 클래스로 확장된다. Throwable 클래스는 예외 함수를 처리한다.

ex)- IOException- SQLException

 

◎ try catch : 코드에서 예외 처리에 사용된다.

- 문법 : 

try{
   //code that may throw the exception
}catch(e:SomeException){
   //code that handles the exception
}

- 예시 :

fun main(){
    val str=getNumber("10.5")
    println(str)
    fun getNumber(str: String):Int{
        return try{
            Integer.parseInt(str)
        }catch (e:ArithmeticException){
            0
        }
    }
} // 출력은 0

◎ Nested try-catch block

- 중첩된 try-catch 블록은 코드 블록이 예외를 발생시키거나 블록 내의 다른 코드가 예외를 발생시킬 때 nested try-catch 블록이 필요하다.

- 문법 :

try{
   //code block
    try{
        //code block
    }catch (e:SomeException){
        //exception
    }
}catch (e:SomeException){
    //exception
}

◎ finally Block : 예외가 처리되든 말든 실행되는 블록이다.

- 문법:

try{
    //code block
}catch (e:SomeException){
    //exception
}finally {
    //code block
}

◎ throw keyword : 분명한 예외를 던지는 데 사용된다.

- 커스텀 예외를 던지는 데도 사용된다.

- 코드가 올바르게 됐는지 확인하고 싶을 때 매우 유용하다. 코드를 고장 낼 오류를 던져서 문제 발생 원인을 이해한다.

현실에서는 앱을 확인할 대 필요하다. 사용자들이 할 수 있는 잠재적인 잘못된 입력값 또는 데이터를 인터넷 등에서 받았을 때 발생할 수 있는 문제를 확인하는 데 필요하다.

- throw 구문은 앱이 고장나게 하므로 많은 throw 구문이나 오류를 가진 앱을 출시하지 말아야 한다.

'Kotlin' 카테고리의 다른 글

코틀린-퀴즈 앱  (0) 2022.11.03
XML 사용법과 UI 생성법 배우기  (0) 2022.10.31
Kotlin 개발 완전 정복(1)  (0) 2022.09.27
Comments