Kotlin
[Kotlin] ์ฝํ๋ฆฐ ๋ฌธ๋ฒ ๊ธฐ์ด 2
soogoori
2024. 7. 8. 10:05
์์ธ์ฒ๋ฆฌ
๋ชจ๋ ์์ธ ํด๋์ค๋ ์ต์์ ์์ธ ํด๋์ค์ธ Throwable์ ์์ํจ
- ์๋ฐ์์ checked exception์ ์ปดํ์ผ ์๋ฌ๊ฐ ๋ฐ์ํ๊ธฐ ๋๋ฌธ์ ๋ฌด์กฐ๊ฑด try-catch๋ก ๊ฐ์ธ๊ฑฐ๋ throws ์์ธ๋ฅผ ์ ํํด์ผํ๋, ์ฝํ๋ฆฐ์ checked exception์ ๊ฐ์ X
- ์ฝํ๋ฆฐ์์ try-catch๋ ํํ์
val a = try {
"1234".toInt()
} catch (e: NumberFormatException) {
println("catch ๋์")
}
println(a) // 1234
- ์ฝํ๋ฆฐ์์ exception์ ๋ฐ์์ํค๋ ค๋ฉด throw ์ฌ์ฉ
fun failFast(message: String): {
throw IllegalArgumentException(message)
}
- Nothing ํ์ ์ ์ฌ์ฉํ๋ฉด ์ปดํ์ผ๋ฌ๋ ํด๋น ์ฝ๋ ์ดํ์๋ ์คํ๋์ง ์๋๋ค๋ ๊ฒฝ๊ณ ๋ณด์ฌ์ค
fun failFast(message: String): Nothing {
throw IllegalArgumentException(message)
}
failFast("์๋ฌ๋ฐ์!")
// Unreachable code
println("์ด ๋ฉ์์ง๋ ์ถ๋ ฅ๋ ๊น?")
- ์๋น์ค ์ฐ์ฐ์์ Nothing ํ์ ์ ์ฌ์ฉํ๋ฉด null ์์ ์ฝ๋๋ฅผ ์์ฑํ์ง ์์๋ ๋จ ๐ null์ด ๋์ฌ ์ ์๋ค๊ณ ์ธ์ํ๊ธฐ ๋๋ฌธ
fun main() {
val a: String? = null
val b: String = a ?: failFast("a is null ")
println(b.length) // b?.length๋ก ์์ฑํ์ง ์์๋ ๋จ
}
ํด๋์ค์ ํ๋กํผํฐ
๐ท Class
- class ํค์๋ ์ฌ์ฉํ์ฌ ์ ์ธ
- ์์ฑ์๋ ๊ธฐ๋ณธ์์ฑ์์ ํ๋ ์ด์์ ๋ณด์กฐ ์์ฑ์ ์กด์ฌ ๊ฐ๋ฅ
class Coffee constructor(val name: String)
class Coffee(val name: String) // ๊ธฐ๋ณธ ์์ฑ์๋ constructor ์๋ต ๊ฐ๋ฅ
- ํด๋์ค์ ํ๋กํผํฐ ์ ์ธํ ๋ trailing comma (ํํ์ผํ) ์ฌ์ฉ ๐ ์ด์ ์ ๋ง์ง๋ง ์ค์ ์์ ํ์ง ์๊ณ ํ๋กํผํฐ ์ฝ๊ฒ ์ถ๊ฐ ๊ฐ๋ฅํ๋ฏ๋ก git์์ diff ๋ฑ์ผ๋ก ์ฝ๋๋ฅผ ๋น๊ตํ์ ๋ ๋ณ๊ฒฝ์ฌํญ ๋ช ํํ ์ ์ ์์
class Coffee(
val name: String,
val price: Int, // trailing comma
)
๐ท ํ๋กํผํฐ
- val, var ํค์๋ ๋ชจ๋ ์ฌ์ฉ ๊ฐ๋ฅ
class Coffee(
var name: String = "", // ๊ธฐ๋ณธ ๊ฐ ์ถ๊ฐ
var price: Int = 0,
)
- ํ๋กํผํฐ ์์ ํ๊ฑฐ๋ ์ฌ์ฉํ๋ ค๋ฉด ์ฐธ์กฐ ์ฌ์ฉ
fun main() {
val coffee = Coffee()
coffee.name = "์์ด์ค ์๋ฉ๋ฆฌ์นด๋
ธ"
coffee.price = 2000
println("${coffee.name} ๊ฐ๊ฒฉ์ ${coffee.price}")
}
๐ท getter, setter
- var๋ก ์ ์ธ๋ ํ๋กํผํฐ๋ getter, setter๋ฅผ ์๋์ผ๋ก ์์ฑ
- val๋ก ์ ์ธ๋ ํ๋กํผํฐ๋ getter๋ง ์กด์ฌ
- ์ปค์คํ getter ๋ง๋ค ์ ์์
class Coffee(
var name: String = "",
var price: Int = 0, // trailing comma
) {
val brand: String
get() = "์คํ๋ฒ
์ค" // ์ปค์คํ
getter
}
fun main() {
val coffee = Coffee()
coffee.name = "์์ด์ค ์๋ฉ๋ฆฌ์นด๋
ธ"
coffee.price = 2000
// brand๋ฅผ ํฌํจํด ์ถ๋ ฅ
println("${coffee.brand} ${coffee.name} ๊ฐ๊ฒฉ์ ${coffee.price}")
}
- var๋ก ์ ์ธ๋ ํ๋กํผํฐ์ ํํ์ฌ ์ปค์คํ setter ์์ฑ ๊ฐ๋ฅ
class Coffee(
var name: String = "",
var price: Int = 0, // trailing comma
) {
val brand: String
get() {
return "์คํ๋ฒ
์ค"
}
var quantity: Int = 0
set(value) { // ์ปค์คํ
setter
if (value > 0) { // ์๋์ด 0 ์ด์์ธ ๊ฒฝ์ฐ์๋ง ๊ฐ์ ํ ๋น
field = value
}
}
}
fun main() {
val coffee = Coffee()
coffee.name = "์์ด์ค ์๋ฉ๋ฆฌ์นด๋
ธ"
coffee.price = 2000
coffee.quantity = 1 // ์ฃผ๋ฌธ ์๋ ์ถ๊ฐ
// ์๋์ ํฌํจํด ์ถ๋ ฅ
println("${coffee.brand} ${coffee.name} ๊ฐ๊ฒฉ์ ${coffee.price} ์๋์ ${coffee.quantity}")
}
field ์๋ณ์ ์ฌ์ฉํด ํ๋์ ์ฐธ์กฐ์ ์ ๊ทผ = Backing Field
๐ field ๋์ quantity๋ก ์ง์ ํ ๋นํ๋ค๋ฉด ๋ฌดํ์ฌ๊ท ๋ฐ์ (StackOverflow)
- ํ๋กํผํฐ๋ ๊ฐ์ฒด์งํฅ์ ๐ ํ์๋ ๋ฉ์๋๋ก ํํ, ์ํ๋ ํ๋กํผํฐ๋ก ํํ
class Coffee(
var name: String = "",
var price: Int = 0, // trailing comma
var iced: Boolean = false,
){
val brand: String
get(){
return "์คํ๋ฒ
์ค"
}
var quantity: Int = 0
set(value) {
if(value > 0){
field = value
}
}
}
fun main(){
val coffee = Coffee()
coffee.name = "์์ด์ค ์๋ฉ๋ฆฌ์นด๋
ธ"
coffee.price = 2000
coffee.quantity = 1
coffee.iced = true
if(coffee.iced){ // ํ๋กํผํฐ
println("์์ด์ค ์ปคํผ")
}
println("${coffee.brand} ${coffee.name} ๊ฐ๊ฒฉ์ ${coffee.price} ์๋์ ${coffee.quantity}")
}
์์
๐ท ์์
์์์ ๋ชฉ์ ์ผ๋ก ๋ง๋ ํด๋์ค๊ฐ ์๋๋ผ๋ฉด ๋ชจ๋ final๋ก ์์ฑํ๋ ๊ฒ์ด ์ข์
- ์๋ฐ์ ๋ชจ๋ ํด๋์ค ์กฐ์ = Object
- ์ฝํ๋ฆฐ์์ ๋ชจ๋ ํด๋์ค ์กฐ์ = Any
- Any์๋ equals, hashCode, toString์ด ์กด์ฌํ๊ณ ๋ชจ๋ ํด๋์ค๋ก ์๋ ์์๋จ
- open ํค์๋๋ก ์์ ํ์ฉ
open class Dog
- ํ์ํด๋์ค์์ ์์ ํด๋์ค๋ฅผ ํ์ฅํ๋ ค๋ฉด ํด๋์ค ๋ค์ : ์ถ๊ฐํ๊ณ ์์ ํด๋์ค ์์ฑ
class Bulldog : Dog()
- ํจ์๋ ํ๋กํผํฐ๋ฅผ ์ฌ์ ์ํ ๋๋ open ํค์๋๋ก ์ค๋ฒ๋ผ์ด๋์ ๋ํด ํ์ฉ
open class Dog{
open var age: Int = 0
open fun bark() {
println("๋ฉ๋ฉ")
}
}
// ์ฌ์ ์ -> Dog ํด๋์ค ์์๋ฐ์
class Bulldog : Dog() {
override var age: Int = 0
override fun bark(){
println("์ปน์ปน")
}
}
// ๊ธฐ๋ณธ์์ฑ์๋ฅผ ์ฌ์ฉํด ์ค๋ฒ๋ผ์ด๋
class Bulldog(override var age: Int = 0) : Dog() {
override fun bark(){
println("์ปน์ปน")
}
}
fun main(){
val dog = Bulldog(age = 2)
println(dog.age)
dog.bark()
}
- override๋ ํจ์๋ ํ๋กํผํฐ๋ ๊ธฐ๋ณธ์ ์ผ๋ก open๋์ด ์์ผ๋ฏ๋ก ํ์ํด๋์ค์์ ์ค๋ฒ๋ผ์ด๋๋ฅผ ๋ง๊ธฐ ์ํด final์ ์์ ๋ถ์
open class Bulldog(final override var age: Int = 0) : Dog() {
final override fun bark() {
println("์ปน์ปน")
}
}
class childrenBulldog : Bulldog(){
override var age: Int = 0 // ์ปดํ์ผ ์ค๋ฅ
override fun bark() {} // ์ปดํ์ผ ์ค๋ฅ
}
- ํ์ ํด๋์ค์์ ์์ ํด๋์ค์ ํจ์๋ ํ๋กํผํฐ๋ฅผ ์ ๊ทผํ ๋ super ํค์๋ ์ฌ์ฉ
open class Bulldog(final override var age: Int = 0) : Dog(){
final override fun bark(){
super.bark()
}
}
๐ท ์ถ์ํด๋์ค
- abstract ํค์๋ ์ฌ์ฉ ๐ ํ์ํด๋์ค์์ ๊ตฌํํด์ผํ๋ ํ๋กํผํฐ๋ ํจ์ ๋ํ abstract ํค์๋ ์ฌ์ฉ
abstract class Developer {
abstract var age: Int
abstract fun code(language: String) // abstract ํค์๋ ๋ถ์ ๊ฒ ๋ฐ๋์ ๊ตฌํ
}
class BackendDeveloper(override var age: Int) : Developer(){
override fun code(language: String){
println("I code with $language")
}
}
fun main(){
val backendDeveloper = BackendDeveloper(age=20)
println(backendDeveloper.age)
backendDeveloper.code("Kotlin")
}
// I code with Kotlin
์ธํฐํ์ด์ค
- interface ํค์๋ ์ฌ์ฉ
- ์ธํฐํ์ด์ค ๋ด๋ถ์ ์ถ์ํจ์์ ๊ตฌํ์ ๊ฐ์ง ํจ์ (๋ํดํธ ๋ฉ์๋) ๋ชจ๋ ์ ์ ๊ฐ๋ฅ
class Product(val name: String, val price: Int)
interface Wheel{ // ์์ ์ธํฐํ์ด์ค
fun roll()
}
interface Cart : Wheel {
var coin: Int // ๋ฐ๋์ ๊ตฌํํด์ผํ๋ ์ถ์ ํ๋กํผํฐ
val weight: String
get() = "20KG" // backing field ์ฌ์ฉ X
fun add(product: Product) // ์ถ์ ํจ์
fun rent(){
if(coin > 0){
println("์นดํธ๋ฅผ ๋์ฌํฉ๋๋ค")
}
}
override fun roll(){
println("์นดํธ๊ฐ ๊ตด๋ฌ๊ฐ๋๋ค")
}
}
interface Order{
fun add(product: Product){
println("${product.name} ์ฃผ๋ฌธ์ด ์๋ฃ๋์์ต๋๋ค")
}
}
class MyCart(override var coin: Int): Cart, Order{
override fun add(product: Product) {
if(coin <= 0) println("์ฝ์ธ์ ๋ฃ์ด์ฃผ์ธ์")
else println("$(product.name)์ด(๊ฐ) ์นดํธ์ ์ถ๊ฐ๋์ต๋๋ค")
// ์ฃผ๋ฌธํ๊ธฐ
super<Order>.add(product)
}
}
fun main(){
val cart = MyCart(coin = 100)
cart.rent()
cart.roll()
cart.add(Product(name = "์ฅ๋๊ฐ", price = 1000))
// ์นดํธ๋ฅผ ๋์ฌํฉ๋๋ค
// ์นดํธ๊ฐ ๊ตด๋ฌ๊ฐ๋๋ค
// ์ฅ๋๊ฐ์ด(๊ฐ) ์นดํธ์ ์ถ๊ฐ๋์ต๋๋ค
// ์ฅ๋๊ฐ ์ฃผ๋ฌธ์ด ์๋ฃ๋์์ต๋๋ค
val cart2 = MyCart(coin = 0)
cart2.rent()
cart2.add(Product(name = "์ฅ๋๊ฐ", price = 1000))
// ์ฝ์ธ์ ๋ฃ์ด์ฃผ์ธ์
}
- ์ธํฐํ์ด์ค ๊ตฌํ ์ :์ ๋ถ์ด๊ณ ์ธํฐํ์ด์ค์ ์ด๋ฆ ์ ์
- ์ธํฐํ์ด์ค ์์ฒด์์ backing field ์ ๊ทผ ๋ถ๊ฐ
- ์์๊ณผ ๋ค๋ฅธ ์ ๐ () ์์ฑ์ ํธ์ถ์ด ์์
- ํด๋์ค๋ ํ๋ ์ด์์ ์ธํฐํ์ด์ค ๊ตฌํ ๊ฐ๋ฅ
- Order์๋ add๊ฐ ๊ตฌํ์ด ์๋ ๋ํดํธ ํจ์์ด๊ณ , Cart๋ abstract ํจ์์
- ๋์ผํ ์ด๋ฆ์ ๊ฐ์ง ํจ์๊ฐ ์๋ ๊ฒฝ์ฐ super<์ธํฐํ์ด์ค>๋ฅผ ์ฌ์ฉํด ํธ์ถ ๊ฐ๋ฅ ๐ ์ฌ์ ์ ์ถฉ๋ ํด๊ฒฐ
- ๋ ์ธํฐํ์ด์ค์ ๊ตฌํ์ ๊ฐ์ง ๋์ผํ ๋ํดํธ ํจ์๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ ์ปดํ์ผ ์ค๋ฅ ๋ฐ์
interface Cart : Wheel {
fun printId() = println("1234")
}
interface Order {
fun printId() = println("5678")
}
// ์ปดํ์ผ ์ค๋ฅ ๋ฐ์
class MyCart(override var coin: Int) : Cart, Order
class MyCart(override var coin: Int) : Cart, Order {
override fun printId() {
super<Cart>.printId()
super<Order>.printId()
}
}
- ํ์ ํด๋์ค์์ ์ง์ ๊ตฌํํด์ ์ธํฐํ์ด์ค์ ๋ํดํธ ํจ์ ์ฌ์ฉํ๋ฉด ๋จ
์ด๊ฑฐํ
๐ท enum class ์ฌ์ฉ
enum class PaymentStatus {
UNPAID, PAID, FAILED, REFUNDED
}
- ํด๋์ค์ด๋ฏ๋ก ์์ฑ์์ ํ๋กํผํฐ ์ ์ ๊ฐ๋ฅ
enum class PaymentStatus(val label: String) {
UNPAID("๋ฏธ์ง๊ธ"),
PAID("์ง๊ธ์๋ฃ"),
FAILED("์ง๊ธ์คํจ"),
REFUNDED("ํ๋ถ")
}
println(PaymentStatus.PAID.label)
// ์ง๊ธ์๋ฃ
- ์ ์๋ ์์ ๋ชฉ๋ก ๋ค์ ํจ์ ์ ์ํ ๊ฒฝ์ฐ ; (์ธ๋ฏธ์ฝ๋ก ) ์ฌ์ฉ
enum class PaymentStatus(val label: String) {
UNPAID("๋ฏธ์ง๊ธ"),
PAID("์ง๊ธ์๋ฃ"),
FAILED("์ง๊ธ์คํจ"),
REFUNDED("ํ๋ถ");
fun isPayable(): Boolean = false
}
- ๊ฒฐ์ ์ํ์ ๋ฐ๋ผ isPayable ์ํ ๋ค๋ฅด๊ฒ ๊ตฌํ ๐ abstract ํจ์๋ฅผ ๊ฐ์ง ์ ์๊ณ ๊ฐ๊ฐ์ ์์๋ ์ต๋ช ํด๋์ค ํํ๋ก abstract ํจ์ ๊ตฌํ ๊ฐ๋ฅ
enum class PaymentStatus(val label: String) {
UNPAID("๋ฏธ์ง๊ธ") {
override fun isPayable() = true
},
PAID("์ง๊ธ์๋ฃ") {
override fun isPayable() = false
},
FAILED("์ง๊ธ์คํจ") {
override fun isPayable() = false
},
REFUNDED("ํ๋ถ") {
override fun isPayable() = false
};
abstract fun isPayable(): Boolean
}
fun main() {
if(PaymentStatus.UNPAID.isPayable()){
println("๊ฒฐ์ ๊ฐ๋ฅ ์ํ")
}
// ๊ฒฐ์ ๊ฐ๋ฅ ์ํ
}
- enum ํด๋์ค์์ ์ธํฐํ์ด์ค ๊ตฌํ ๊ฐ๋ฅ
enum class PaymentStatus(val label: String) : Payable {
UNPAID("๋ฏธ์ง๊ธ") {
override fun isPayable() = true
},
PAID("์ง๊ธ์๋ฃ") {
override fun isPayable() = false
},
FAILED("์ง๊ธ์คํจ") {
override fun isPayable() = false
},
REFUNDED("ํ๋ถ") {
override fun isPayable() = false
};
}
interface Payable {
fun isPayable(): Boolean
}
- valueOf(value:String) : String ์ ์ฌ์ฉํด์ enum ํด๋์ค ์์ฑ ๊ฐ๋ฅ
val paymentStatus = PaymentStatus.valueOf("PAID")
println(paymentStatus.label)
// ์ง๊ธ์๋ฃ
- ๋๋ฑ์ฑ ๋น๊ต ๐ == ์ฌ์ฉ
if (paymentStatus == PaymentStatus.PAID) {
println("๊ฒฐ์ ์๋ฃ ์ํ")
}
// ๊ฒฐ์ ์๋ฃ ์ํ
- enum ํด๋์ค์ ์์ ๋์ด ๐ values() : Array<EnumClass> ์ฌ์ฉ
for (status in PaymentStatus.values()) {
println("[$status](${status.label})")
}
// [UNPAID](๋ฏธ์ง๊ธ)
// [PAID](์ง๊ธ์๋ฃ)
// [FAILED](์ง๊ธ์คํจ)
// [REFUNDED](ํ๋ถ)
- ์์๋ ์ ๊ณตํ๋ 2๊ฐ์ ํ๋กํผํฐ ์ฌ์ฉํด ์ด๋ฆ์ ์ป๊ฑฐ๋ ์์ ์ป์ ์ ์์
val name: String
val ordinal: Int
for (status in PaymentStatus.values()) {
println("[${status.name}](${status.label}) : ${status.ordinal}")
}
// [UNPAID](๋ฏธ์ง๊ธ) : 0
// [PAID](์ง๊ธ์๋ฃ) : 1
// [FAILED](์ง๊ธ์คํจ) : 2
// [REFUNDED](ํ๋ถ) : 3