Kotlin & springboot
Spring java to Kotlin
코틀린이란?
- 코틀린( Kotlin )은 2011년 7월 JetBrains사가 공개한 JVM에서 동작하는 프로그래밍 언어로서, 간결하고 실용적이며 자바코드와의 상호운용성( interoperability )를 중시한 언어이다.
주요 특성
- 코틀린의 주목적은 현재 자바가 사용되고 있는 대부분의 곳에 변환이 가능하며 간결하고, NullSafe하게 코드 작성을 가능하게 만들어 준다.
자바 에서 코틀린으로 변경한 이유
처음엔 신규프로젝트를 생성할때는 Java로 셋팅 하였으나 프로젝트 사이즈가 크게 크지 않아서 코틀린으로 변경을 해보고 싶어 진행을 해보았으나 생각보다 편하게 작성이 가능해서 좋았습니다.
특히 NullSafe라는게 어떤의미인지 한번 겪어 볼 수 있었습니다. 기본적으로 JPA에서 <Optional>Type으로 작성을 통해 사용하는곳에서는 JPA.getAttendance().orElseThrow()를 사용하게 되는데 이걸 굳이 할 필요가 없어서 좋았습니다.
변경 전
// Optional 사용 예시 Optional<Entity> entity = repository.findById(id); Entity result = entity.orElseThrow(() -> new IllegalArgumentException("Entity not found"));변경 후
// Nullable 타입 사용 예시 val entity = repository.findByIdOrNull(id) ?: throw IllegalArgumentException("Entity not found")언어 자체에서 Null-Safety를 제공하므로
Optional클래스가 불필요.간결하고 읽기 쉬운 코드 작성 가능.
| 특징 | Java (Optional) | Kotlin (Nullable) |
| Null 처리 방식 | Optional 클래스를 통해 명시적으로 처리 | 언어 차원의 Nullable 타입 (?) 사용 |
| 추가 클래스 필요 여부 | 필요 (Optional) | 불필요 (Kotlin 기본 기능 활용) |
| 주요 메서드 | .orElse, .orElseThrow, .ifPresent 등 | 엘비스 연산자(?:), let, 확장 함수 등 |
| 코드 간결성 | 비교적 장황함 | 더 간결하고 직관적 |
- 단점
| 비교 항목 | Java | Kotlin |
| 빌드 시간 (bootJar) | 약 2초 | 2-3초 |
| 애플리케이션 실행 시간 | 약 17초 | 22-23초 |
전반적으로 코틀린으로 변환 후의 성능 차이는 크지 않았으며, 주목할 만한 단점은 발견되지 않았습니다. 다만 SpringApplication 실행 시간에서 약간의 차이가 있었습니다.
변환 준비
변환 준비과정
변환을 계획할때 가장 중요하게 생각한건 라이브러리 (Open-Api, jjwt, Security, Spring 디펜던시 등등) 사용하고 있는 모든 라이브러리 들이 kotlin과 호환이 되는지 체크를 우선 하였습니다.
다행이 현재 셋팅한 프로젝트 대부분은 코트린과 호환이 되는 상태라 그대로 진행해도 되었습니다.
변환 과정
Config(Common) 패키지 내의 java 코드들을 우선 Kotlin으로 변환을 진행하였습니다. 첫번째로 선택한 이유는 SpringProjcet에 전체적인 영향을 가는 부분이기 때문에 해당 설정에서 터질경우 마이그레이션 진행을 보류 하기 위해 진행하였습니다. SecurityConfig, JwtConfig, SwaggerConfig etc…
마이그레이션을 진행하며 첫번째 문제는 코틀린은 생성자 정의 방식이 다르다는 점입니다.
<aside> 💡
Java의 생성자
클래스 이름과 동일한 메소드를 통해 정의
일반적으로 여러 생성자(Overloading)을 만들어 받는 인자 (파라미터)를 다르게 받을 수 있는 점
생성자 하나도 정의 하지 않으면 컴파일러가 자동으로 기본 생성자 (파라미터[인자]가 없는 생성자)를 제공 해줌
생성자는 반환 타입이 없음, 클래스 초기화와 함께 필드에 값을 할당하거나 초기화 로직이 필요함 </aside>
public class User {
private String name;
private int age;
// 기본 생성자
public User() {
// ...
}
// 파라미터가 있는 생성자
public User(String name, int age) {
this.name = name;
this.age = age;
}
// Getter/Setter, 기타 메서드...
}
<aside> 💡
Kotlin의 생성자
주 생성자 (Primary Constructor)와 보조 생성자(Secondary Construcctor)라는 개념을 가지고 있음.
클래스 헤더(Class 이름 옆)에 오는 생성자를 주 생성자 라고 부르며 , Constructor 키워드를 생략하거나 직접 사용해서 표시 할 수 있음 → 인텔리제이에서는 경고 표시로 생략을 권장함
주 생성자는 클래스의 프로퍼티(Property)를 직접 정의 할 수 있으며, 생성자 파라미터에
val또는var를 붙이면 자동으로 해당 클래스의 프로퍼티가 됨.추가적인 생성 로직이 필요한 경우,
init {…}블록을 사용해 초기화 코드를 작성함- 필요하다면 보조 생성자를
constructor(...):this(...){...}형태로 여러 개 선언 할수도 있지만, 보통 Kotlin에선 기본값을 사용하는 것이 일반적이어서 자주 이지는 않음 </aside>
- 필요하다면 보조 생성자를
// (1) 주 생성자(Primary Constructor) + init 블록 예시
class User(val name: String, var age: Int) {
// init 블록: 주 생성자 호출 시 실행되는 초기화 로직
init {
println("User Created with name = $name, age = $age")
}
}
// (2) 보조 생성자(Secondary Constructor) 예시
class Person {
var name: String
var age: Int
constructor(name: String) {
this.name = name
this.age = 0
}
constructor(name: String, age: Int) {
this.name = name
this.age = age
}
}
주요 차이점 정리
주 생성자 개념
코틀린은 클래스 선언부에 작성되는 ‘ 주 생성자’ 가 핵심
Java에서는 모든 생성자가 클래스 몸체 내부에 선언되며. ‘주 생성자’ 개념이 존재 하지 않음
프로퍼티 선언과 생성자 파라미터 동시정의
코틀린은
class User(val name: String, var age: Int)와 같이 생성자 파라미터에valvar를 붙임으로써 클래스 프로퍼티를 동시에 정의 할 수 있음Java에서는 필드를 따로 선언하고, 생성자 내부에서는 할당 패턴을 사용해야함
init블록코틀린에서는 주 생성자 안에 직접 로직을 넣지않고,
init블록을 통해 초기화 로직을 수행함Java는 생성자 본문에 초기화 로직을 작성함
기본값 지원
코틀린은 파라미터에 기본값을 부여할 수 있음
- ex)
fun greet(name:String ="Guest")
- ex)
이로인해 생성자 오버로딩 대신에 기본값 파라미터를 자주 사용하는 경향이 있음
자바에서는 생성자 오버로딩으로 같은 효과를 내야함
보조 생성자
코틀린에서는 여러 보조 생성자를 둘 수 있지만, 자주 안쓰임 (오버로딩 보다 기본값 할당이 더간단)
자바에서는 오버로드된 생성자를 통해 여러 파라미터 버전을 제공함
자동 기본 생성자 제공 여부
자바 : 생성자를 아예 안 만들면 파라미터가 없는 기본 생성자를 자동으로 제공, 하나라도 생성자를 정의하면 자동 기본 생성자가 만들어 지지 않음
코틀린: 파라미터가 없는 생성자가 필요하면, 직접 정의하거나 파라미터 기본값을 주어야함
가시성(Visibility)제어
코틀린의 주 생성자에 접근 제어자를 붙이려면
constructor키워드를 사용해야함class User private constructor(val name: String)자바도 생성자에
public / private / protected등을 붙이지만, 이는 문법적으로 동일한 메서드 선언의 형태임
데이터 클래스
코틀린에서는
data class를 사용해 DTO(또는 VO, Entity 등 )용 클래스를 매우 간단하게 정의 가능합니다.data class User(val name : String, val age: Int)자동으로
equals(),hashCode(),toString(),copy()등을 생성해주어 보일러 플레이트가 크게 줄어듭니다보일러플레이트?
보일러플레이트
보일러플레이트(Boilerplate)는 소프트웨어 개발에서 반복적으로 사용되는 코드, 템플릿, 또는 설정을 의미하며, 프로젝트의 기본 구조를 정의하여 개발 효율성을 높입니다.
주요 특징 및 사용 이유
기본 구조 제공: 프로젝트의 초기 설정과 구조를 미리 정의하여 빠른 개발을 지원합니다.
시간 절약: 반복 코드의 재사용으로 개발 시간을 단축합니다.
일관성 유지: 코드 스타일과 구조를 표준화합니다.
학습 참조: 새로운 개발자나 프레임워크 학습에 활용됩니다.
보일러플레이트의 예
웹 개발: HTML 기본구조, Express.js 서버 설정 등
javascriptimport express from 'express'; const app = express(); app.get('/', (req, res) => res.send('Hello World!')); app.listen(3000, () => console.log('Server running on port 3000'));객체 지향 프로그래밍(OOP): 클래스와 메서드 선언
javapublic class Customer { private String name; public String getName() { return name; } public void setName(String name) {this.name= name; } }React-Native: 기본 컴포넌트 구조
javascriptimport React from 'react'; import { Text, View } from 'react-native'; const App = () => ( <View> <Text>Hello, World!</Text> </View> ); export default App;
어원 및 의미
산업 분야의 금속판에서 유래하여, 현재는 소프트웨어 개발, PR, 마케팅 등에서 표준화된 구성을 의미합니다.
장점과 단점
장점
빠른 프로젝트 초기화
코드 표준화 및 유지보수 용이
학습 자료로 활용 가능
단점
과도한 의존 시 불필요한 코드 증가
프로젝트 복잡도 상승 가능성
특정 상황에 맞지 않는 경우 수정 필요
보일러플레이트는 효율적인 개발 도구이나, 적절한 활용이 중요합니다.
Java 16 이상부터
record클래스가 도입되어 유사 기능을 제공하지만, 코틀린 만큼 다양한 문법적 편의성을 갖추지는 않음- 코틀린 컴파일 시의 자바 클래스 구조
코틀린 클래스 역시 JVM 바이트코드로 컴파일 되므로, 생성자 구조가 자바 클래스 파일과 다른 형태로 생성될 수도 있다.
코틀린 디폴트 파라미터는 문법적 설탕(synatacic sugar)이므로 실제로 여러 bridge 메서드가 생성되어 구현됨
- 싱글턴 패턴 구현
코틀린은
objcet키워드로 손쉽게 싱글턴을 만들 . 수있으나, 자바에서는private contructor+static factory method를 조합해 직접 구현해야함