[Android/Flutter 교육] 11일차

MSU·2024년 1월 10일

Android-Flutter

목록 보기
11/85
post-thumbnail

코틀린 교육은 오늘로 종료

과제 제출하는데 클래스에 lateinit을 사용해보려고 자동차 객체 프로퍼티에 lateinit을 붙여줬는데 lateinit은 생성자나 init블럭이 아닌 메서드에서 나중에 값을 할당할때 사용하는거라 사실 필요없는 부분이었다. 너무부끄럽다...

대부분의 언어에서
순서를 가진 값의 묶음은 [ ] 대괄호로
순서가 없는 값의 묶음은 { } 중괄호로 표현됨
국제 표준은 아니지만 대부분 이 규칙을 따르고 있음

컬렉션 중 set은 생략했음

몽키테스트

알파테스트 - 기획된 기능 테스트
베타테스트(내부)
베타테스트(클로즈) - 버그 테스트
베타테스트(오픈) - 홍보 목적이 큼(버그가 거의 없어야 함)

유튜버에 클로즈베타 테스트 비용 2~3천 많으면 5천 이상~
일반 홍보비용보다 더 싸게 먹힌다고 함

문자열

  • " "로 묶어서 관리하는 문자열
  • 코틀린은 문자열을 자바에 동일하게 String 클래스의 객체를 생성해서 관리
  • 자바와 거의 동일하게 제공되며 몇가지 메서드가 추가됨

문자열 생성

  • String 클래스의 생성자에 StringBuffer, StringBuilder, ByteArray, CharArray를 넣어주면 가지고 있는 글자 데이터를 이용해 문자열을 생성한다.
fun main() {
    // 문자열 생성

    // String 클래스의 생성자에
    // StringBuffer, StringBuilder, ByteArray, CharArray
    // 를 넣어주면 가지고 있는 글자 데이터를 이용해
    // 문자열을 생성한다.
    val array1 = CharArray(5){
        'a'
    }
    val str1 = String(array1)
    println("str1 : $str1")
    
    // ""로 묶어준 것도 String 객체를 생성한 것이다.
    val str2 = "안녕하세요"

    // 원하는 n번째의 글자를 가져올 수 있다.
    println("str2[0] : ${str2[0]}")
    println("str2[1] : ${str2[1]}")
    
    // 원하는 n번째의 글자를 변경하는건 불가
    // str1[0] = 'A'

    // 원하는 부분의 글자들을 추출하여 새로운 문자열로 생성한다.
    // 순서값을 지정한다.
    val str3 = str2.substring(1..3) // 두번째~네번째
    println("str3 : $str3")
}
str1 : aaaaa
str2[0] : 안
str2[1] : 녕
str3 : 녕하세

문자열 비교

  • == : 자바에서는 문자열 객체의 주소값을 비교하지만 코틀린에서는 문자열 값 자체를 비교함
fun main() {
    // 문자열 비교
    val str4 = "Hello World"
    val str5 = "hello world"
    val str6 = "Hello World"
    
    // == : 자바에서는 문자열 객체의 주소값을 비교하지만
    // 코틀린에서는 문자열 값 자체를 비교함(코틀린에서 == 연산자를 사용 시 equals 메서드가 호출됨)
    if(str4 == str5){
        println("str4와 str5는 같습니다")
    }else{
        println("str4와 str5는 다릅니다")
    }

    if(str4 == str6){
        println("str4와 str6는 같습니다")
    }else{
        println("str4와 str6는 다릅니다")
    }
}
str4와 str5는 다릅니다
str4와 str6는 같습니다
  • compareTo : 문자열을 비교하는 메서드
    문자열을 구성하는 글자의 코드값을 합산하고 그걸 뺀 결과를 반환한다.
fun main() {
    // 문자열 비교
    val str4 = "Hello World"
    val str5 = "hello world"
    val str6 = "Hello World"
    
    println(str4.compareTo(str5))
    println(str4.compareTo(str6))
    
    // compareTo의 두 번째 매개변수에 true 를 넣어주면
    // 모두 소문자로 변환하여 계산해준다.
    println(str4.compareTo(str5,true))


}
-32
0
0
  • compareTo와 동일하게 equals메서드에도 대소문자 구분 옵션을 넣어줄 수 있다.
fun main() {
    // 문자열 비교
    val str4 = "Hello World"
    val str5 = "hello world"
    val str6 = "Hello World"
    
    // equals 메서드의 두 번째 매개변수애 true를 넣어주면 대소문자를 무시하고 같은지 비교해준다.
    if(str4.equals(str5, true)){
        println("두 문자열은 대소문자를 무시하면 같습니다.")
    }


}
두 문자열은 대소문자를 무시하면 같습니다.

문자열 나누기

  • 구분자를 기준으로 문자열을 나눌 수 있다.
fun main() {
    // 구분자를 기준으로 문자열을 나눈다.
    val str7 = "ab_cd ef_gh"

    // 띄어쓰기를 기준으로 나눈다.
    val r6 = str7.split(" ")
    println("r6 : $r6")

    for(temp6 in r6){
        println(temp6)
    }
}
r6 : [ab_cd, ef_gh]
ab_cd
ef_gh

대소문자 변경

  • uppercase : 소문자를 대문자로 하는 문자열을 생성한다.
  • lowercase : 대문자를 소문자로 하는 문자열을 생성한다.
fun main() {
    // uppercase : 소문자를 대문자로 하는 문자열을 생성한다.
    // lowercase : 대문자를 소문자로 하는 문자열을 생성한다.
    val str8 = str4.uppercase()
    val str9 = str4.lowercase()

    println("str8 : $str8")
    println("str9 : $str9")
}
str8 : HELLO WORLD
str9 : hello world

시작과 끝 문자열 여부

  • startsWith : ~로 시작하는지
  • endsWith : ~로 끝나는지
fun main() {
    // startsWith : ~로 시작하는지
    // endsWith : ~로 끝나는지
    val r10 = str4.startsWith("H")
    val r11 = str4.startsWith("A")
    val r12 = str4.endsWith("d")
    val r13 = str4.endsWith("A")

    println("r10 : $r10")
    println("r11 : $r11")
    println("r12 : $r12")
    println("r13 : $r13")
}
r10 : true
r11 : false
r12 : true
r13 : false

글자수 개수 반환

fun main() {
    // 글자의 개수를 반환한다.
    println("str4의 글자수 : ${str4.length}")
}
str4의 글자수 : 11

문자열 공백 제거

  • trim : 문자열 좌우 공백을 제거
fun main() {
    // 문자열 좌우 공백을 제거
    val str20 = "   aaa   "
    println("[${str20}]")
    println("[${str20.trim()}]")
}
[   aaa   ]
[aaa]

List

  • 리스트 : 0부터 1씩 증가하는 순서값을 가지고 객체를 관리한다.
  • 배열과 다르게 관리하는 객체의 수를 늘리거나 줄일 수 있다.
  • 코틀린에서는 ArrayList 객체로 생성되며, 리스트를 불변형과 가변형으로 제공한다.
  • 불변형은 추가, 수정, 삭제 등이 불가능하다. 가변형에 비해 메서드나 프로퍼티의 수가 더 적어 메모리를 적게 차지하고 데이터를 가져오는데 속도가 더 빠르다.(느껴지지 못하는 차이)

불변형 리스트

  • 리스트 생성 이후 값의 추가, 수정, 삽입, 삭제 등이 불가능하다.
fun main() {
    // 리스트 생성
    // 불변형 리스트
    // 리스트 생성 이후 값의 추가, 수정, 삽입, 삭제 등이 불가능하다.
    val list1 = listOf(10, 20, 30, 40, 50)
    println("list1 : $list1")

    val list2 = listOf("문자열1", "문자열2", "문자열3")
    println("list2 : $list2")

    // 타입이 달라도 된다.
    val list3 = listOf(100, 11.11, "문자열", true)
    println("list3 : $list3")
}
list1 : [10, 20, 30, 40, 50]
list2 : [문자열1, 문자열2, 문자열3]
list3 : [100, 11.11, 문자열, true]

수정 가능한 리스트

  • 수정 가능한 리스트는 ArrayList로 생성된다.
  • 나중에 객체를 추가해줄 수 있는 텅 비어있는 리스트를 생성할 수 있다.
  • 다양한 타입의 값을 넣을 경우 제네릭을 Any로 설정하면 된다.
fun main() {
    // 수정 가능한 리스트 ArrayList로 생성된다.
    // 텅 비어있는 수정 가능한 리스트를 생성 : 나중에 객체를 추가할 수 있게
    val list4 = mutableListOf<Int>()
    // 생성시 관리할 객체를 지정할 수 있다.
    val list5 = mutableListOf("문자열1","문자열2","문자열3")
    println("list4 : $list4")
    println("list5 : $list5")
}
list4 : []
list5 : [문자열1, 문자열2, 문자열3]

비어있는 수정 불가능한 리스트

  • 의미 없지만 코틀린에서 제공하고 있음
fun main() {
    // 비어있는 수정 불가능한 리스트
    val list6 = emptyList<Int>()
    println("list6 : $list6")
}
list6 : []

null이 포함된 수정 불가능한 리스트

fun main() {
    // null이 있을 경우(수정 불가능)
    // null 포함
    val list7 = listOf(10, 20, null, 40, null, 60, 70)
    // null 포함하지 않음
    val list8 = listOfNotNull(10, 20, null, 40, null, 60, 70)

    println("list7 : $list7")
    println("list8 : $list8")
}
list7 : [10, 20, null, 40, null, 60, 70]
list8 : [10, 20, 40, 60, 70]

for문 사용

  • 순서값을 갖고 있는 모든 요소들은 for문과 같이 사용이 가능하다.
fun main() {
	val list1 = listOf(10, 20, 30, 40, 50)

    // for 문 사용
    for(item in list1){
        println("item : $item")
    }
}
item : 10
item : 20
item : 30
item : 40
item : 50

리스트 접근

관리하는 객체의 개수

fun main() {
	val list1 = listOf(10, 20, 30, 40, 50)

    // 관리하는 객체의 개수
    println("list size : ${list1.size}")
}
list size : 5

관리하는 객체에 접근

fun main() {
	val list1 = listOf(10, 20, 30, 40, 50)

    // 관리하는 객체에 접근한다.
    // [ ] 연산자를 통해 순서값(0부터 1씩 증가)를 지정하여 접근한다.
    println("list1 0 : ${list1[0]}")
    println("list1 1 : ${list1[1]}")
    
    val list9 = listOf(10, 20, 30, 10, 20, 30)

    // 지정한 객체가 앞에서 부터 몇 번째에 있는가
    val index1 = list9.indexOf(20)
    println("index1 : $index1")
    
    // 지정한 객체를 뒤에서부터 찾아서 앞에서 부터 몇번째에 있는가
    val index2 = list9.lastIndexOf(20)
    println("index2 : $index2")
    
    // indexOf, lastIndexOf 모두 없는 것을 지정하면 -1을 반환한다.
    val index3 = list9.indexOf(100)
    println("index3 : $index3")
    
    // 일부를 발췌하여 새로운 리스트를 생성한다.
    // 순서값 1 ~ 3-1 까지
    val list10 = list9.subList(1, 3)
    println("list10 : $list10")
}
list1 0 : 10
list1 1 : 20
index1 : 1
index2 : 4
index3 : -1
index4 : -1
list10 : [20, 30]

객체 추가

  • add : 추가할 객체(의 주소값)를 넣어줌, 리스트 뒤에 추가됨
  • addAll : 배열을 넣어줌
fun main() {
    val list21 = mutableListOf(10, 20, 30)

    // 객체를 추가한다.
    // 리스트 뒤에 추가된다.
    list21.add(40)
    list21.add(50)
    list21.addAll(listOf(60,70,80,90,100))
    println("list21 : $list21")
}
list21 : [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
  • 수정 불가능한 리스트에 추가
    추가, 수정, 삭제, 삽입 등과 관련된 메서드 자체가 없다.
fun main() {
    val list20 = listOf(10, 20, 30)

    // 수정 불가능한 리스트에 추가
    // 추가, 수정, 삭제, 삽입 등과 관련된 메서드 자체가 없다.
    list20.add(40) // 에러
}

객체 삽입

  • add 메서드를 이용할 때 위치를 지정하면 그 위치에 삽입된다.
  • add(순서값, 객체) : 순서값에 해당하는 위치에 객체를 삽입하고 그 이후의 객체들은 뒤로 밀린다.
fun main() {
    val list21 = mutableListOf(10, 20, 30)

    // 삽입
    // add 메서드를 이용할 때 위치를 지정하면 그 위치에 삽입된다.
    // add(순서값, 객체) : 순서값에 해당하는 위치에 객체를 삽입하고 그 이후의 객체들을 뒤로 밀린다.
    list21.add(1, 100)
    println("list21 : $list21")
}
list21 : [10, 100, 20, 30]
  • 삽입할 데이터가 다수라면 addAll을 사용한다.
fun main() {
    val list21 = mutableListOf(10, 20, 30)
    
    list21.add(1, 100)

    // 삽입할 데이터가 다수라면 addAll을 사용한다.
    list21.addAll(3, listOf(2000,3000,4000,5000))
    println("list21 : $list21")
}
list21 : [10, 100, 20, 2000, 3000, 4000, 5000, 30]

객체 수정

  • set 메서드를 사용하거나 [ ]로 접근하여 수정할 수 있다.
fun main() {
    val list21 = mutableListOf(10, 20, 30)
    
    // 값을 수정한다.
    // 두 번째 값을 1000으로 덮어 씌운다.
    list21.set(1, 1000)
    println("list21 : $list21")

    list21[1] = 10000
    println("list21 : $list21")
}
list21 : [10, 1000, 30]
list21 : [10, 10000, 30]

객체 제거

  • remove : 지정한 값을 제거
fun main() {
    val list21 = mutableListOf(10, 20, 30)

    list21[1] = 10000
    
    // 제거
    // 지정한 값을 제거한다.
    list21.remove(10000)
    println("list21 : $list21")
    
    // 없는 객체를 제거할 경우
    // 오류가 발생하지 않고 아무런 일도 일어나지 않음
    list21.remove(50000)
    println("list21 : $list21")
}
list21 : [10, 30]
list21 : [10, 30]
  • removeAll : 리스트를 인자값으로 전달받아 여러 객체를 지정하여 제거
fun main() {
    val list21 = mutableListOf(10, 20, 30)

    // 여러 객체를 지정하여 제거한다.
    list21.removeAll(listOf(10, 30))
    println("list21 : $list21")
}
list21 : [20]
  • removeAt : 위치를 지정하여 제거
fun main() {
    val list21 = mutableListOf(10, 20, 30)

    // 위치를 지정하여 제거한다.
    // 두 번째 객체를 제거한다.
    list21.removeAt(1)
    println("list21 : $list21")
}
list21 : [10, 30]
  • clear : 모두 삭제
fun main() {
    val list21 = mutableListOf(10, 20, 30)

    // 모두 삭제
    list21.clear()
    println("list21 : $list21")
}
list21 : []

객체 추출

  • toMutableList : list안에 저장되어 있는 객체를 추출하여 새로운 mutable list를 생성한다.
fun main() {
    val list100 = listOf(10, 20, 30, 40, 50)

    // list안에 저장되어 있는 객체를 추출하여 새로운 mutable list를 생성한다.
    val list200 = list100.toMutableList()
    list200.add(60)
    println("list200 : $list200")
}
list200 : [10, 20, 30, 40, 50, 60]
  • toList : mutable list 안에 저장되어 있는 객체를 추출하여 새로운 list를 생성한다.
fun main() {
    val list100 = listOf(10, 20, 30, 40, 50)

    val list200 = list100.toMutableList()
    list200.add(60)

    // mutable list 안에 저장되어 있는 객체를 추출하여 새로운 list를 생성한다.
    val list300 = list200.toList()
    // list300.add(70) // mutable이 아니므로 add 사용 불가
    println("list300 : $list300")
}
list300 : [10, 20, 30, 40, 50, 60]

Map

  • map : 객체를 이름을 통해 관리하는 요소
  • 순서에 대한 개념은 없다.
  • 이름 to 객체 형태로 지정한다. (이름은 문자열이 아니어도 된다.)
  • 다양한 타입의 값을 담을 수 있다.

수정 불가능한 map

fun main() {

    // 이름 to 객체 형태로 지정한다.
    // 수정 불가능한 map
    val map1 = mapOf("key1" to 10, "key2" to 20, "key3" to 30)
    println("map1 : $map1")
    
    // 이름은 문자열이 아니어도 된다.
    val map2 = mapOf(10 to "문자열1", 20 to "문자열2", 30 to "문자열3")
    println("map2 : $map2")
}
map1 : {key1=10, key2=20, key3=30}
map2 : {10=문자열1, 20=문자열2, 30=문자열3}

수정 가능한 map

fun main() {

    // 수정 가능한 맵
    val map3 = mutableMapOf("key1" to 10, "key2" to 20, "key3" to 30)
    println("map3 : $map3")
}
map3 : {key1=10, key2=20, key3=30}

다양한 타입의 값을 담을 수 있다.

fun main() {

    // 다양한 타입의 값을 담을 수 있다.
    val map4 = mapOf("key1" to 10, "key2" to 11.11, "key3" to "문자열")
    println("map4 : $map4")
}
map4 : {key1=10, key2=11.11, key3=문자열}

제네릭을 설정할 수 있다.

  • map은 제네릭을 설정하지 않아도 되지만 딱 한 경우에 무조건 설정해야 한다.
  • <이름으로 사용할 객체의 클래스타입, 저장할 객체의 클래스타입>
fun main() {

    // 제네릭을 설정할 수 있다
    // map은 제네릭을 설정하지 않아도 되지만 딱 한 경우에는 무조건 설정해야 한다.

    // 한가지 타입의 객체를 담는 맵
    // <이름으로 사용할 객체의 클래스타입, 저장할 객체의 클래스타입>
    val map5 = mapOf<String, Int>("key1" to 10, "key2" to 20, "key3" to 30)
    println("map5 : $map5")
    
    // 다양한 타입의 객체를 담는 맵
    val map6 = mapOf<String, Any>("key1" to 10, "key2" to 11.11, "key3" to "문자열")
    println("map6 : $map6")
    
    // 텅 비어있는 맵을 만들때는 반드시 제네릭을 설정해야 한다.
    val map7 = mapOf<String, Int>()
    val map8 = mutableMapOf<String, Any>()
}
map5 : {key1=10, key2=20, key3=30}
map6 : {key1=10, key2=11.11, key3=문자열}

객체 추출

  • get 메서드 사용
fun main() {

    // 관리하고 있는 객체를 추출한다.
    val map9 = mapOf("key1" to 10, "key2" to 20, "key3" to 30)
    val map10 = mutableMapOf("key1" to 10, "key2" to 20, "key3" to 30)

    // get 메서드 사용
    println("map9 key1 : ${map9.get("key1")}")
    println("map10 key1 : ${map10.get("key1")}")
}
map9 key1 : 10
map10 key1 : 10
  • [ ] 대괄호로 사용(get 메서드 호출과 동일)
fun main() {

    // 관리하고 있는 객체를 추출한다.
    val map9 = mapOf("key1" to 10, "key2" to 20, "key3" to 30)
    val map10 = mutableMapOf("key1" to 10, "key2" to 20, "key3" to 30)

    // [ ] 사용
    println("map9 key1 : ${map9["key1"]}")
    println("map10 key1 : ${map10["key1"]}")
}
map9 key1 : 10
map10 key1 : 10

Map 메서드

fun main() {

	val map1 = mapOf("key1" to 10, "key2" to 20, "key3" to 30)

    // 관리하는 객체의 개수
    println("map1 size : ${map1.size}")
    // 이름들을 가져온다.
    println("map1 keys : ${map1.keys}")
    // 관리하는 객체들을 가져온다.
    println("map1 values : ${map1.values}")
    
    // 이 이름으로 저장된 객체가 있는지
    val chk1 = map1.containsKey("Key1")
    val chk2 = map1.containsKey("Key100")
    println("chk1 : $chk1")
    println("chk2 : $chk2")
}
map1 size : 3
map1 keys : [key1, key2, key3]
map1 values : [10, 20, 30]
chk1 : false
chk2 : false
chk3 : true
chk4 : false

객체 추가

fun main() {

    val map12 = mutableMapOf("a1" to 10, "a2" to 20)
    println("map12 : $map12")

    // 추가
    map12.put("a3", 30)
    println("map12 : $map12")

    // 없는 이름으로 객체를 넣어주면 추가된다.
    map12["a4"] = 40
    println("map12 : $map12")
}
map12 : {a1=10, a2=20}
map12 : {a1=10, a2=20, a3=30}
map12 : {a1=10, a2=20, a3=30, a4=40}

객체 수정

fun main() {

    val map12 = mutableMapOf("a1" to 10, "a2" to 20)
    println("map12 : $map12")

    // 수정
    // 있는 이름으로 객체를 넣어준다
    map12["a2"] = 400
    println("map12 : $map12")
}
map12 : {a1=10, a2=20}
map12 : {a1=10, a2=400}

Map은 순서에대한 개념이 없기 때문에 삽입이 없다

객체 삭제

fun main() {

    val map12 = mutableMapOf("a1" to 10, "a2" to 20)
    println("map12 : $map12")

    // 삭제
    map12.remove("a2")
    println("map12 : $map12")
}
map12 : {a1=10, a2=20}
map12 : {a1=10}

Map 변경

mapOf -> mutableMapOf

fun main() {

    // mapOf -> mutableMapOf
    val map13 = mapOf("a1" to 10, "a2" to 20, "a3" to 30)

    val map14 = map13.toMutableMap()
    map14["a4"] = 40
    println("map14 : $map14")
}
map14 : {a1=10, a2=20, a3=30, a4=40}

mutableMap -> map

fun main() {

    val map13 = mapOf("a1" to 10, "a2" to 20, "a3" to 30)

    // mutableMap -> map
    val map15 = map13.toMap()
    // map15["a5"] = 50 // 에러
    println("map15 : $map15")
}
map15 : {a1=10, a2=20, a3=30}

ForEach

  • 컬렉션들이 관리하는 객체들을 하나씩 추출하면서 반복할 수 있도록 제공되는 메서드

Array

fun main() {

    // 배열
    var array1 = arrayOf(10, 20, 30, 40, 50)

    // for
    // 배열이 관리하는 객체의 수 만큼 반복하면서
    // 반복하는 n번째의 객체를 v1에 담아준다.
    for(v1 in array1){
        println("array1 v1 : $v1")
    }
    
    println()

    // 배열이 관리하는 데이터의 개수 만큼 람다식을 반복한다.
    // it에는 반복하는 n번째의 데이터가 들어온다.
    array1.forEach {
        println("array1 it : $it")
    }
}
array1 v1 : 10
array1 v1 : 20
array1 v1 : 30
array1 v1 : 40
array1 v1 : 50

array1 it : 10
array1 it : 20
array1 it : 30
array1 it : 40
array1 it : 50

List

fun main() {

    // list
    val list1 = listOf(10, 20, 30, 40, 50)

    list1.forEach {
        println("list1 it : $it")
    }
}
list1 it : 10
list1 it : 20
list1 it : 30
list1 it : 40
list1 it : 50

Map

  • 순서가 없어도 forEach 사용 가능
  • 순서가 없기때문에 순서와 관련된 내용은 수행할 수 없음
fun main() {

    // map
    val map1 = mapOf("a1" to 10, "a2" to 20)

    map1.forEach{
        println("map1 key : ${it.key}")
        println("map1 value : ${it.value}")
    }
}
map1 key : a1
map1 value : 10
map1 key : a2
map1 value : 20

예외처리

  • 프로그램 실행 중 예측이 가능한 오류들을 예외라고 부른다.
  • 예외가 발생하면 코드의 수행이 중단된다.(정확히 말하자면 오류가 발생하기 전에 강제 중단시킴)
  • 예외처리는 예외가 발생했을 때 프로그램이 수행되는 것을 막고 예외 발생 시 동작해야 하는 코드를 수행시켜 프로그램이 문제없이 동작하게 하기 위한 목적을 가지고 있다.
  • 자바에서는 예외 상황에 대한 것들을 클래스로 만들어 제공하고 있다.
  • 예외가 발생하면 발생된 예외와 관련된 클래스의 객체를 생성하여 개발자에게 전달해준다.
    이 객체에는 오류와 관련된 정보가 담겨져 있다.
  • 발생한 오류의 정보에 따라서 처리할 수 있는 코드를 개발자가 작성해줘야 한다.
try {
	예외가 발생할 가능성이 있는 코드
} catch (e:예외클래스) {
 	예외가 발생했을때 수행할 코드
} finally {
  	예외 발생 여부에 관계없이 수행해야 하는 코드
}
  • try : 개발자가 구현하는 코드 부분

  • catch : try 부분에서 예외가 발생했을 때 동작하는 코드

  • try 부분에서 예외가 발생되면 try 부분의 수행은 중단되고 catch부분으로 넘어간다.

  • 예외가 발생되면 VM은 프로그램을 강제 종료시킨다.

  • 예외 처리의 목적은 예외 발생 시 프로그램이 강제 종료되지 않도록 하고 catch에 작성한 코드가 동작될 수 있도록 함에 있다.

  • 오류가 나는 경우

fun main() {

    val a1 = 10 / 0

    val str:String? = null
    println(str!!.length)

    val str2 = "안녕하세요"
    val a2:Int = str2.toInt()
}
  • 오류가 나는 구문을 try catch 구문으로 감싸주면 아래의 println문이 정상적으로 출력된다
fun main() {

    try {
        // val a1 = 10 / 0

        // val str:String? = null
        // println(str!!.length)

        val str2 = "안녕하세요"
        val a2:Int = str2.toInt()
    }catch(e:Exception){
        e.printStackTrace()
    }

    println("이 부분이 수행 될까요?")
}
java.lang.NumberFormatException: For input string: "안녕하세요"
	at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
	at java.base/java.lang.Integer.parseInt(Integer.java:668)
	at java.base/java.lang.Integer.parseInt(Integer.java:784)
	at MainKt.main(main.kt:25)
	at MainKt.main(main.kt)
이 부분이 수행 될까요?
  • 예외 종류별로 처리해주기
    맨 처음 발생하는 오류에 대하여 처리하기 때문에 ArithmeticException 예외처리 부분만 실행된다.
fun main() {

    try {
        val a1 = 10 / 0

        val str:String? = null
        println(str!!.length)

        val str2 = "안녕하세요"
        val a2:Int = str2.toInt()
    }catch(e:ArithmeticException){ // 10을 0으로 나눴을 때의 예외 처리
        // e.printStackTrace()
        println("수학오류가 발생하였습니다")
    }catch (e:NullPointerException){ // null을 가진 변수를 통해 객체에 접근하려고 했을 때의 예외 처리
        println("NULL 접근 오류가 발생하였습니다")
    }catch (e:NumberFormatException){ // 숫자로 변환할 수 없는 문자열을 숫자로 변환하고자 할 때의 예외 처리
        println("숫자 양식 오류가 발생하였습니다")
    }catch (e:Exception){ // 그 밖의 모든 예외에 대한 처리
        println("그 밖의 오류가 발생하였습니다")
    }

    println("이 부분이 수행 될까요?")
}
수학오류가 발생하였습니다
이 부분이 수행 될까요?

데이터 저장 종류

  • 크게 3가지로 나뉨
  • 메모리
  • 로컬 파일
  • 서버 파일
  • 주 기억 장치 -> 램
    보조 기억 장치 -> 천공카드, 자기 테이프, 디스크(MD, 플로피디스크, 하드디스크), ROM(CD-ROM, DVD-ROM, Bluray-ROM), SSD(반도체, 휘발성, 6개월 이상 전력없으면 데이터 날라감, 작은 배터리가 포함됨), M-RAM(주기억장치와 보조기억장치의 중간정도), 저장장치용 유리(차세대저장장치, 실험단계), 기타 등등

메모리

  • CPU가 직접 가져다 쓰는 공간(주 기억 장치)
  • 프로그램에서 사용되어지는 모든 것들은 전부 메모리에 저장되어야 한다.
  • 프로그램이 종료되면 저장된 데이터는 소멸된다.
  • 전력 공급이 중단되면 저장된 데이터는 모두 소멸함(휘발성)

로컬 파일

  • 디스크에 저장하는 것. 영구 저장
  • 프로그램이 종료되거나 전력 공급이 중단되어도 소멸되지 않는다.
  • 프로그램 종료 후 다음에 실행할 때 사용할 데이터를 파일에 저장한다.
    그러나 CPU 사용하려면 파일에서 데이터를 읽어서 메모리에 저장하는 작업을 해줘야 한다.

서버 파일

  • 서버의 디스크에 저장하는 것. 영구 저장
  • 사용자 컴퓨터나 스마트폰에 저장된 파일은 삭제될 수 있다.
  • 서비스 운영에 매우 중요한 데이터를 사용자가 삭제하지 못하도록 하기위해 서버에 저장한다.
  • 서버에 저장된 데이터는 서버에 접속이 가능한 모든 클라이언트가 사용할 수 있도록 제공할 수 있다.
    데이터 센터 여러개를 만들어 한 곳이 문제가 발생하면 바로 다른 곳을 사용할 수 있게 대비함
    k사 메신저 화재는 화재로 전력 차단 시 대신 전력을 공급해줄 UPS실에서 화재가 난 사건임
    마이크로소프트가 부산에 데이터 센터를 만들어놓음(아시아 지역 마이크로소프트 서버는 부산 데이터 센터에 있음)

개발 패턴

개발 패턴
개발 프레임워크라고 부르기도 한다.
개발과 유지보수를 용이하게 하기 위해 각 파일마다 역할을 지정하고
그 역할에 맞는 기능을 구현하도록 하는 것

MVC 패턴

M (Model)

  • 데이터를 저장하고 관리하는 요소
  • Model을 여러가지 역할로 나누기도 한다.
  • Model(VO, Value Object) - 순수 데이터만 저장하고 반환하는 역할만 수행한다.
  • DAO(Data Access Object) - Model이 가지고 있는 데이터를 외부(파일, 서버 등등)에 저장하고 외부에 저장되어 있는 데이터를 Model에 담아주는 등의 역할을 수행한다.
  • Repository - Model과 DAO의 중간에 위치한다. DAO가 읽어온 데이터를 Repository에 전달하고 Repository가 Model에 저장한다.
    Model에 저장된 데이터를 Repository가 읽어들여 DAO로 보내면 DAO가 저장소에 저장한다.

V (View)

  • Model이 가지고 있는 데이터를 이용해 사용자에게 보여줄 화면을 구성한다.
  • V 를 더 확장하여 P 로 지정하는 MVP 패턴이 있고
  • V와 M을 더 확장하여 사용하는 MVVM 패턴도 있다.

C (Controller)

  • 프로그램 전체의 흐름을 제어하는 역할을 수행한다.

첫 번째 미니 프로젝트

학생 정보를 관리하는 프로그램

처음 시작하면 메뉴를 보여준다.
[ 메인 메뉴 ]
1. 학생 정보 입력
2. 학생 정보 검색
3. 학생 정보 전체 출력
4. 각 과목별 총점과 평균 확인
5. 종료
번호를 입력해주세요 :

메인 메뉴에서 1번을 선택하면
현재 입력된 학생 수 : 10명
학생 이름 :
학생 나이 :
국어 점수 :
영어 점수 :
수학 점수 :

입력이 완료되면 메인 메뉴를 보여준다.

메인 메뉴에서 2번을 선택하면
검색할 학생 이름 :
학생 이름 : 0000
학생 나이 : 0000
국어 점수 : 0000
영어 점수 : 0000
수학 점수 : 0000

메인 메뉴를 보여준다.

메인 메뉴에서 3번을 선택하면
학생 이름 : 0000
학생 나이 : 0000
국어 점수 : 0000
영어 점수 : 0000
수학 점수 : 0000

위와 같은 형태로 모든 학생들의 정보를 보여주고 메인 메뉴를 보여준다.

메인 메뉴에서 4번을 선택하면
국어 총점 : 0000
영어 총점 : 0000
수학 총점 : 0000
국어 평균 : 0000
영어 평균 : 0000
수학 평균 : 0000

메인 메뉴를 보여준다.

메인 메뉴에서 5번을 입력하면
"프로그램이 종료되었습니다." 를 보여주고 프로그램 종료한다.

학생들의 정보는 모두 파일로 저장한다.

패키지와 클래스 설명

com.lion.project1.controller : 컨트롤러를 모아놓은 패키지
com.lion.project1.model : Model 들을 모아놓은 패키지
com.lion.project1.view : View 들을 모아놓은 패키지
com.lion.project1.dao : 데이터를 저장하고 읽어오는 클래스들을 모아놓은 패키지
com.lion.project1.activity : 각 상태에 대한 클래스들을 모아놓은 패키지
com.lion.project1.util : 기타 역할을 수행하는 클래스나 인터페이스를 모아놓은 패키지




※ 출처 : 멋쟁이사자 앱스쿨 2기, 소프트캠퍼스 
profile
안드로이드공부

0개의 댓글