본문 바로가기
IT/git

[Kotlin] 자주 쓰는 문법

by 저당단 2025. 11. 27.

 

사이드 프로젝트에서 백엔드 개발언어가 코틀린으로 정해짐.

코틀린으로 개발해본게 이미 2-3년 전이라 다시 학습을 해야하는 상황..

백엔드 개발자분이 자주 쓰는 문법을 설명해주신 것들 + 개인적으로 찾아본 것들을 정리함.

 

타입스크립트와 굉장히 유사한 부분이 많다.

 

  • 구조 분해 할당 가능
// data class에서의 구조분해 할당
data class User(val id: Long, val name: String)

val user = User(1, "SK")
val (id, name) = user
// 함수 구조분해 할당 (Pair가 data class임)
fun coordinate(): Pair<Int, Int> {
    return 10 to 20
}

val (x, y) = coordinate()
// Map의 구조분해 할당 (iterate할때 편함)
val map = mapOf("a" to 1, "b" to 2)

for ((key, value) in map) {
    println("$key => $value")
}
  • String.format() 같은거 안 써도 되며 문자열 템플릿 사용 가능
val name = "SK"
val age = 28

val msg = "이름: $name, 나이: ${age + 1}"
println(msg)
  • 의존성 주입 방법
// private val 붙이면 필드 + 생성자 주입 동시에 해결.
// @RequiredArgsConstructor나 @Autowired 안 붙여도 됨.
// 만약 private를 빼면 외부에서 필드에 getter로 접근 가능. (Config 등)

@Service
class UserService(
    private val userRepository: UserRepository,
    private val eventPublisher: ApplicationEventPublisher,
) {
    fun findUser(id: Long): User =
        userRepository.findById(id).orElseThrow()
}
  • null safety, assertion 문법
var s1: String = "abc"
// s1 = null   // 컴파일 에러

var s2: String? = "abc"
s2 = null      // 가능

val len = s2?.length  // s2가 null이면 len도 null

// elvis 연산자(?:) -> 타입스크립트의 ??와 비슷한듯
val len = s2?.length ?: 0

// assertion
val len = s2!!.length   // null이면 런타임에 NPE
  • 상속 / 구현 문법
// 일반 클래스 상속
open class Parent {
    open fun speak() {
        println("parent")
    }
}

class Child : Parent() {
    override fun speak() {
        println("child")
    }
}
// ---

// 추상 클래스 상속
abstract class Creature {
    abstract fun sound()

    fun info() = println("생명체")
}

class Dog : Creature() {
    override fun sound() = println("멍멍")
}
// ---

// 인터페이스 구현
interface Animal {
    fun sound()
    fun move() = println("move!")   // 디폴트 메서드 가능
}

class Dog : Animal {
    override fun sound() = println("멍멍")
}
// ---
  • 단일 표현식일 때 타입스크립트처럼 return 생략 가능.
fun sum(a: Int, b: Int) = a + b
  • class 대신 object를 쓰면 싱글턴 보장해줌. (유틸 클래스)
// 생성자 호출 불가능

object JwtUtils {
    fun sign(payload: String): String {
        return "signed-$payload"
    }

    fun verify(token: String): Boolean {
        return token.startsWith("signed-")
    }
}
  • mutableList, map
// 기본적인 List와 Map은 요소 변경이 안되므로 mutable로 선언해야 함.

val mutable = mutableListOf("a", "b")
mutable.add("c")

val map = mapOf(
    "admin" to 1,
    "user" to 2
)
  • 컨트롤러 예시
data class CreateUserRequest(
    val name: String,
    val email: String,
)

data class UserResponse(
    val id: Long,
    val name: String,
    val email: String?,
)

@RestController
@RequestMapping("/users")
class UserController(
    private val userService: UserService
) {

    @PostMapping
    fun create(@RequestBody req: CreateUserRequest): ResponseEntity<UserResponse> {
        val user = userService.create(req)
        return ResponseEntity.ok(
            UserResponse(
                id = user.id,
                name = user.name,
                email = user.email
            )
        )
    }
}