안녕하세요.
개발을 하다 보면 다양한 예외 상황에 직면하게 돼요. 이러한 예외는 프로그램의 흐름을 방해하고 예상치 못한 종료를 초래할 수 있기 때문에, 각 예외의 특성을 이해하고 적절히 처리하는 것이 중요해요.
오늘은 개발 중 자주 발생하는 Exception과 그 처리 방법에 대해 알아볼게요.
1. NullPointerException
NullPointerException은 null 객체의 속성이나 메서드를 호출하려고 할 때 발생해요. Kotlin은 기본적으로 null-safety를 지원하지만, 자바 라이브러리와의 상호작용 등으로 인해 발생할 수 있어요.
val str: String? = null
val length = str!!.length // NullPointerException 발생
이를 방지하기 위해서는 안전 호출 연산자(?.)를 사용하거나, non-null 확인(!!)을 지양하는 것이 좋아요.
val length = str?.length ?: 0 // 안전하게 처리
2. IllegalArgumentException
잘못된 인자가 함수나 메서드에 전달될 때 발생해요. 예를 들어, 예상 범위 밖의 값을 전달하거나, 필수 인자를 null로 전달할 때 발생해요.
fun checkAge(age: Int) {
require(age > 0) { "Age must be positive" }
}
checkAge(-5) // IllegalArgumentException 발생
함수나 메서드를 호출하기 전에 인자의 유효성을 검사하고, require나 check 등의 Kotlin 표준 함수를 사용하여 명시적으로 조건을 확인해요.
fun checkAge(age: Int) {
require(age > 0) { "Age must be positive" }
}
3. IndexOutOfBoundsException
리스트, 배열 등의 인덱스가 유효 범위를 벗어날 때 발생해요.
val list = listOf(1, 2, 3)
val element = list[3] // IndexOutOfBoundsException 발생
항상 인덱스 범위를 확인하는 습관을 기르세요.
if (index in list.indices) {
val element = list[index]
}
4. ClassCastException
객체를 잘못된 타입으로 캐스팅하려고 할 때 발생해요.
val obj: Any = "String"
val num = obj as Int // ClassCastException 발생
타입을 안전하게 캐스팅하려면 as? 연산자를 사용하세요.
val num = obj as? Int
5. NumberFormatException
숫자 형식이 아닌 문자열을 숫자로 변환하려고 할 때 발생해요.
val number = "abc".toInt() // NumberFormatException 발생
변환 전 문자열이 유효한지 확인하는 것이 좋아요.
val number = "123".toIntOrNull() ?: 0
6. IOException
입출력 작업 중에 발생하는 예외로, 파일 읽기/쓰기 또는 네트워크 작업에서 문제가 생길 때 발생해요 .
try {
val input = File("file.txt").inputStream()
} catch (e: IOException) {
e.printStackTrace()
}
입출력 작업을 수행할 때는 항상 예외 처리를 통해 오류에 대비해야 해요. 또한, 파일이나 네트워크 자원을 사용할 때는 적절한 자원 해제를 보장하기 위해 use 블록을 사용하면 좋아요.
try {
File("file.txt").inputStream().use { input ->
// 파일 읽기 작업
}
} catch (e: IOException) {
e.printStackTrace()
}
7. FileNotFoundException
파일을 찾을 수 없을 때 발생하는 예외예요.
try {
val input = File("non_existent_file.txt").inputStream()
} catch (e: FileNotFoundException) {
e.printStackTrace()
}
파일을 열기 전에 해당 파일이 존재하는지 확인하고, 파일 경로가 올바른지 검사하는 것이 중요해요.
val file = File("non_existent_file.txt")
if (file.exists()) {
file.inputStream().use { input ->
// 파일 읽기 작업
}
} else {
println("File not found")
}
8. OutOfMemoryError
메모리가 부족할 때 발생하는 예외예요. 큰 이미지를 처리하거나 메모리를 많이 사용하는 작업을 할 때 발생할 수 있어요.
try {
val bitmap = BitmapFactory.decodeFile("large_image.jpg")
} catch (e: OutOfMemoryError) {
e.printStackTrace()
}
이미지를 처리할 때는 적절한 크기로 리사이즈하거나, 메모리 사용량을 줄이기 위해 BitmapFactory.Options를 사용하여 이미지를 샘플링하는 것이 좋아요.
val options = BitmapFactory.Options().apply {
inSampleSize = 4 // 원본 크기의 1/4로 축소
}
val bitmap = BitmapFactory.decodeFile("large_image.jpg", options)
9. ConcurrentModificationException
컬렉션을 반복하는 동안 해당 컬렉션을 수정하려고 할 때 발생해요.
val list = mutableListOf(1, 2, 3)
for (item in list) {
list.add(4) // ConcurrentModificationException 발생
}
컬렉션을 안전하게 수정하려면 Iterator를 사용하세요.
val iterator = list.iterator()
while (iterator.hasNext()) {
val item = iterator.next()
iterator.remove()
}
10. SQLiteException
SQLite 데이터베이스 작업 중에 발생하는 예외예요.
try {
val db = SQLiteDatabase.openDatabase("non_existent.db", null, SQLiteDatabase.OPEN_READWRITE)
} catch (e: SQLiteException) {
e.printStackTrace()
}
데이터베이스 작업을 수행하기 전에 데이터베이스 파일의 경로가 올바른지 확인하고, 데이터베이스가 존재하는지 확인해야 해요. 또한, 데이터베이스 작업을 예외 처리 블록으로 감싸서 오류 발생 시 적절히 대응할 수 있도록 해요.
try {
val db = SQLiteDatabase.openOrCreateDatabase("my_database.db", null)
// 데이터베이스 작업 수행
} catch (e: SQLiteException) {
e.printStackTrace()
}
11. SecurityException
보안 권한이 없을 때 발생하는 예외예요.
try {
val location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
} catch (e: SecurityException) {
e.printStackTrace()
}
필요한 권한을 사전에 요청하고, 권한이 허용되었는지 확인한 후에 작업을 수행해야 해요. 안드로이드에서는 런타임 권한 요청을 통해 사용자에게 필요한 권한을 요청할 수 있어요.
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
val location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
} else {
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), REQUEST_LOCATION_PERMISSION)
}
12. NetworkOnMainThreadException
네트워크 작업을 메인 스레드에서 수행하려고 할 때 발생해요. 안드로이드에서는 네트워크 작업을 백그라운드 스레드에서 수행해야 해요.
try {
val url = URL("https://www.example.com")
val connection = url.openConnection() as HttpURLConnection
connection.inputStream // NetworkOnMainThreadException 발생
} catch (e: NetworkOnMainThreadException) {
e.printStackTrace()
}
백그라운드 스레드에서 네트워크 작업을 수행하려면 AsyncTask나 Coroutine을 사용하세요.
CoroutineScope(Dispatchers.IO).launch {
val url = URL("https://www.example.com")
val connection = url.openConnection() as HttpURLConnection
connection.inputStream
}
'Android > 기본' 카테고리의 다른 글
[Android] 앱 아키텍처 가이드 (0) | 2024.11.12 |
---|---|
[Android]안드로이드 스튜디오 로그(Log) 가이드 (0) | 2024.11.10 |
[Android] Android 자동 테스트 작성 및 유형 (0) | 2024.09.06 |
[Android] Deep Link 딥링크 (0) | 2024.03.18 |
[Android] MVVM 패턴(Model-View-ViewModel) (1) | 2024.03.14 |
[Android] Retrofit2와 RxJava의 통신 실패 관리 (0) | 2024.03.13 |
[Android] Activity Lifecycle 액티비티 생명주기 (0) | 2024.03.08 |
[Android] App components 앱 구성요소 (0) | 2024.03.06 |