반응형
해당 글에서는 Kotlin에 대해 이해하고 Java 언어와 비교하여서 특징 이해하고 “Kotlin이 Java 언어를 대체할 수 있을까”라는 주제로 작성하였습니다.
1) Kotlin의 기술동향
💡 개발자들을 대상으로 조사를 한 ‘Stack Overflow의 Developer Survey’와 ‘JetBrain의 Developer Ecosystem’을 통해서 Kotlin 언어에 대해서 개발자들은 어떻게 생각하고 사용하고 있는지에 대해서 기술적인 동향으로 확인합니다.
1. Stack Overflow Survey
💡 매년 Stack Overflow 내에서 Developer Survey로 ‘Most popular technologies’를 투표로 결정합니다.
이는 매년 가장 인기 있는 기술에 대해서 투표하는 내용이며 해당 글에서는 2021년과 2022년을 비교하는 내용만 언급하였습니다.
💡 미비한 비교지만 Java의 사용량은 35.35% → 33.27%로 줄었고, Kotlin의 경우 8.32% → 9.16%로 상승하였습니다.
(이는 모바일 환경이 아닌 웹 환경만 비교가 된 사항입니다.)
💡 해당 Survey에서는 급격하게 Java 언어를 사용하지 않고 Kotlin을 사용하고 있다라고 이야기할 수 없는 비교 자료이긴 하지만 요즘 개발자들은 어떤 것에 더 관심을 갖는지 확인할 수 있는 자료가 됩니다.
2021년 가장 인기있는 기술들(Most popular technologies)
2022년 가장 인기있는 기술들(Most popular technologies)
2. JetBrain Developer Ecosystem
💡 매년 JetBrain에서 개발자 커뮤니티 현황을 파악하기 위해 실시한 제6회 연례 설문조사의 결과입니다. 해당 정보는 2022년 5월~7월에 본 설문조사에 참여한 전 세계 개발자 29,269명의 응답을 기반으로 작성되었습니다.
💡 아래에는 2022년 해당 설문조사 내용에서 Kotlin의 새로운 언어를 사용할 계획으로 선택되었으며 선호도가 가장 높은 언어로 Kotlin이 언급되었다고 확인을 해볼 수 있는 부분입니다.
[출처] The State of Developer Ecosystem in 2022 : JetBrain
2) Kotlin
1. Kotlin 이란?
💡 Kotlin 이란
- 2011년 JetBrain 사에서 공개한 오픈소스 프로그래밍 언어이며 ‘자바 및 기타 JVM 언어와 호환되는 새로운 언어’이며 프로그래밍 언어입니다.
- Kotlin은 ‘타입 추론’을 지원하는 ‘정적 언어'입니다. 그렇기에 코드가 컴파일될 때 타입이 결정되며 런타임 중에는 타입 변경을 할 수 없습니다.
2. Kotlin의 동작원리
1. *.kt 파일의 소스코드는 Kotlin Complier(kotlinc)를 통해서 컴파일이 됩니다.
2. 컴파일이 수행되면 *. class의 바이트 코드 파일로 생성이 됩니다.
3. 바이트 코드 형태의 파일은 JVM을 통해서 수행이 됩니다.
[ 더 알아보기 ]
💡 .class 파일
- Java와 Kotlin에서 각각의 소스코드들은 컴파일러를 통해서 *.class 파일로 변환이 되며 해당 파일은 바이트코드로 구성이 되어 있습니다.
💡 코틀린 컴파일러(kotlinc)
- Kotlin 코드를 컴파일하는 데 사용되며 kotlinc.bat 또는 kotlinc.sh로 실행됩니다.
💡JVM(Java Virtual Machine) 이란?
- 자바 프로그램을 실행시키기 위한 가상 머신입니다. 자바 언어로 작성된 소스 코드는 컴파일러를 통해 바이트 코드로 변환되고 JVM에서 실행됩니다. JVM은 운영체제와 자바 프로그램 사이에서 중개자 역할을 하며 자바 프로그램이 운영체제에 구애받지 않고 독립적으로 실행될 수 있도록 합니다.
3) Kotlin 특징 : Java 언어와 비교
💡 웹 서버를 개발하는데 가장 많이 사용이 되고 있는 Java 언어와 Kotlin을 비교하면서 Kotlin의 특징에 대해서 확인을 합니다.
1. Kotlin과 Java 언어와의 비교 요약
분류 | Java | Kotlin |
컴파일러 | javac | kotlinc |
컴파일 결과물 | 바이트코드(.class) | 바이트코드(.class) |
문법 | 복잡한 문법 | 간결한 문법 |
실행 환경 | JVM | JVM |
타입체크 | 타입 체크가 적음 | 더 엄격한 타입 체크 |
null 처리 | null 처리가 어려움 | null 안전성 제공 |
제네릭 | 제한적인 타입 추론 | 자동 타입 추론 |
람다식 | 지원 | 지원 |
확장 함수 | 지원하지 않음 | 지원 |
데이터 클래스 | 지원하지 않음 | 지원 |
코루틴 | 지원하지 않음 | 지원 |
2. Java 언어와의 호환성을 지원합니다.
💡 Kotlin 소스코드는 Java와 동일하게 JVM에 의해 컴파일 되어 수행이 되므로 Kotlin 프로젝트 내에서 Java 언어와 병행하여 사용이 가능하며 서로 호출을 하여 사용이 가능합니다.
💡 간단한 설정을 한다면 Kotlin → Java / Java → Kotlin 언어를 사용할 수 있습니다.
2.1. Kotlin에서 Java를 호출 (Kotlin → Java)
💡 Java 코드를 실행하기전에 build.gradle 파일 내에 java코드에 대한 plugins와 sourceSets로 경로를 지정해야 합니다.
plugins {
id 'java'
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
[ 더 알아보기 ]
💡 sourceSets이 무엇인가?
- sourceSets는 Gradle 빌드 스크립트에서 사용되는 요소 중 하나입니다. sourceSets는 프로젝트의 소스 코드 디렉터리를 구성하기 위한 요소입니다.
- 소스 셋이 구성되면, Gradle은 소스 코드를 컴파일하고 실행 가능한 바이너리를 생성할 때 이를 고려합니다.
💡 Kolitn 프로젝트 내에서 Java 파일로 CommonUtils.kt를 생성하였습니다.
💡 Kotlin 프로젝트에서 java 클래스의 메서드를 호출하여 UUID를 생성하였습니다.
2.2. Java에서 Kotlin을 호출(Java → Kotlin)
💡 Kotlin 코드를 실행하기 전에 build.gradle 파일 내에 kotlin 코드에 대한 plugins와 sourceSets로 경로를 지정하며, 라이브러리 추가와 컴파일러를 추가합니다.
plugins {
id 'org.jetbrains.kotlin.jvm' version '1.8.20-RC'
}
sourceSets {
main.kotlin.srcDirs += 'src/main/java'
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
}
compileKotlin {
kotlinOptions {
jvmTarget = "1.8"
}
}
compileTestKotlin {
kotlinOptions {
jvmTarget = "1.8"
}
}
💡 Kolitn 프로젝트 내에서 Java 파일로 CommonUtils.java를 생성하였습니다.
💡 Java 프로젝트에서 Kotlin 클래스의 메서드를 호출하여 UUID를 생성하였습니다.
3. 간결하게 작성 가능합니다.
💡 Kotlin은 Java보다 간결하고 직관적인 문법을 가지고 있습니다. 불 필요한 “세미콜론”이나 “타입 선언” 등을 줄여 코드의 가독성을 높입니다.
Kotlin
Java
[참고] var와 val의 차이점
구분 | var | val |
의미 | 변수(Variable) | 값(Value) |
특징 | 값을 변경할 수 있음 : 가변 타입(mutable type) | 값을 변경할 수 없음 : 불변 타입(immutable type) |
선언 방법 | var 변수명: 타입 = 값 | val 변수명: 타입 = 값 |
사용 예시 | var age: Int = 30 age = 31 // success |
val name: String = "John" name = "Jane" // error |
4. 널 안정성(Null safety)을 가지고 있습니다.
💡 Nullable 타입과 Non-nullable 타입을 구분하여 컴파일러가 NullPointException을 런타임에서 방지할 수 있습니다.
💡 Kotlin은 null에 대해 안정성을 지원하는 언어로 컴파일을 수행할 때 null 참조를 방지하여 런타임 중에 발생할 수 있는 NullPointException을 방지할 수 있습니다.
💡“?” 연산자를 사용하여 변수가 null 일 수 있다는 것을 나타냅니다.
4.1. Nullable 타입
💡 변수의 값이 null이 될 수도 있고 아닐 수도 있다는 Nullable은 “?“ 를 이용하여 구성합니다.
var nullableString: String? = "Hello, world!"
nullableString = null // This is allowed
if (nullableString != null) {
println(nullableString.length)
} else {
println("nullableString is null")
}
4.2. Not-nullable 타입
💡 변수의 값이 null 일수 없다는 Not-nullable은 “?” 연산자를 제외하면 됩니다.
💡 이를 통해 컴파일 단계에서 null에 대한 방지를 할 수 있으며 런타임에서 발생하는 NullPointException을 방지할 수 있습니다.
var nullStr: String = "hello, world!"
nullStr = null // error
5. 확장 함수(Extension function) & 확장 프로퍼티(Extension property)
💡 Kotlin에서는 확장 함수와 확장 속성을 지원하여 기존의 클래스의 함수나 속성을 재구성하여 사용함으로써 코드의 재사용성과 가독성 증가합니다.
5.1. 확장 함수(Extension function)
💡 확장 함수(Extension function)란?
- 기존 클래스를 수정하지 않고도 새로운 기능을 추가할 수 있도록 해줍니다.
- 이를 통해 코드의 가독성을 높일 수 있고 코드 중복을 줄이며 유지보수성을 높일 수 있습니다.
- 확장 함수를 사용하면 이미 존재하는 클래스에 새로운 함수를 추가할 수 있지만 확장 함수는 해당 클래스의 내부 구조나 멤버 변수에 직접적인 접근이 불가능합니다. 즉, 해당 클래스에서 사용 가능한 함수들만 사용할 수 있습니다.
/**
* 확장 함수(Extension function)를 구성합니다.
* String.toTitleCase()의 경우 첫글자만 대문자로 바꾸는 함수입니다.
* 이를 이용하여 스페이스바를 기준으로 첫번째 문자를 대문자로 변경하고 반환하는 함수를 재 구성합니다.
*/
fun String.toTitleCase(): String {
return this.split(" ").joinToString(" ") { it.capitalize() }
}
/**
* 확장 함수를 출력합니다.
*/
@GetMapping("/extendFunc")
fun extensionFunc(): String {
val str = "hello world"
println(str.toTitleCase()) // 출력: "Hello World"
return "hello"
}
[ 더 알아보기 ]
💡 String.toTitleCase()
- 문자열의 각 단어의 첫 글자를 대문자로 바꾸는 함수입니다.
💡 String.capitalize()
- 문자열의 첫 문자를 대문자로 변경하는 함수입니다.
5.2. 확장 속성(Extension property)
💡 확장 프로퍼티(Extension property)란?
- 기존의 클래스에 “확장 속성”을 추가하여 기존 클래스의 속성을 확장할 수 있습니다.
- 이를 통해 기존 클래스의 기능을 확장하거나 수정할 수 있는 강력한 방법입니다.
val <T> T.property: <return_type>
get() = <getter>
set(value) = <setter>
////////////////////////////////////////////
val {확장할 클래스명}.{프로퍼티명}: {타입}
get() = {프로퍼티 게터}
set(value) {프로퍼티 세터}
/**
* 1. 확장 프로퍼티(Extension property)를 구성합니다. : 짝수인지 여부를 판단하는 함수
*/
val Int.isEven: Boolean
get() = this % 2 == 0
/**
* 확장 함수를 출력합니다.
*/
@GetMapping("/extendFunc")
fun extensionFunc(): String {
val num = 4
if (num.isEven) {
println("$num is even")
} else {
println("$num is odd")
}
return "hello"
}
/**
* 2. 확장 프로퍼티(Extension property)를 구성합니다. : 첫번쨰와 마지막 요소 값을 가져오는 함수
*/
val <T> MutableList<T>.firstElement: T
get() = this[0]
val <T> MutableList<T>.lastElement: T
get() = this[this.size - 1]
/**
* 확장속성을 이용하기 위한 리스트를 구성하고 첫번째 요소와 마지막 요소를 가져옵니다.
*/
val list = mutableListOf(1, 2, 3, 4, 5)
val first = list.firstElement // 1
val last = list.lastElement // 5
6. 코루틴(Couroutine)을 지원합니다.
💡 코루틴(Couroutine)이란?
- 코루틴은 비동기적으로 실행되는 경량 스레드입니다.
- 코루틴은 스레드보다 더 가볍고 효율적인 방식으로 비동기 코드를 작성할 수 있도록 도와줍니다.
- 일반적인 스레드와 달리 코루틴은 자체적으로 CPU 자원을 소비하지 않기 때문에 오버헤드가 적습니다. 또한, 코루틴은 멀티태스킹을 가능하게 하여 동시에 여러 작업을 수행할 수 있습니다.
💡 프로세스 내에서 1000개의 스레드를 생성하여 실행하는 경우 많은 CPU 자원을 소비하는 반면에 1000개의 코루틴을 실행하는 경우 적은 CPU 자원을 소비합니다.
💡 코루틴의 경우 하나의 Thread에 수천 개의 코루틴이 수행될 수 있습니다. 코루틴은 Thread 없이는 수행이 불가능 하지만 Thread를 옮겨가면서 수행할 수 있습니다.
💡 결론적으로 여러 개의 Thread를 수행하는 경우 CPU자원을 소비하지 않기 때문에 오버헤드가 적고 동시에 여러 작업을 할 수 있다(동시성 작업)는 장점이 있습니다.
[ 더 알아보기 ]
💡 스레드(Thread)란?
- 하나의 프로세스 내에서 실행되는 작은 실행단위를 의미하며 스레드를 사용하여 여러 작업을 동시에 수행할 수 있습니다. 이는 멀티태스킹을 가능하게 하여 프로그램의 성능을 향상하는 데에 사용됩니다.
💡스레드가 한 번에 여러 번 수행하는 경우 뭐가 안 좋은가?
- 여러 스레드가 많이 수행되면 CPU 자원을 많이 사용하게 되어 시스템 성능에 영향을 줄 수 있습니다. 또한, 스레드 간의 자원 공유 문제나 동기화 문제가 발생할 수도 있습니다. 이를 해결하기 위해 적절한 스레드 관리와 동기화 기술이 필요합니다.
💡 그럼 웹에서 코루틴을 사용하고자 하면 어떻게 해야 하는가?
- 대표적으로 Spring 프레임워크에서는 Spring WebFlux 모듈을 사용하여 코루틴을 지원합니다. 이를 통해 비동기 작업을 더 효율적으로 처리할 수 있습니다.
7. Kotlin은 Javascript로도 컴파일이 가능합니다.
💡 Kotlin은 JVM(Java Virtual Machine)에서 실행되는 언어이지만 JavaScript로도 컴파일할 수 있습니다. 따라서 Node.js 환경에서도 kotlin 코드를 컴파일하여 실행할 수 있습니다.
💡 Kotlin 컴파일러는 자바스크립트 코드를 생성하기 위해 필요한 모든 파일을 생성하며 이 파일들은 Node.js 환경에서 실행될 수 있습니다. 또한, Kotlin은 Node.js의 모든 기능을 사용할 수 있습니다.
💡 따라서, Kotlin 언어를 사용하여 Node.js 애플리케이션을 개발할 수 있습니다.
💡 Node.js의 Express.js와 함께 Restful API 형태로 구성이 가능합니다. 이를 위해서 Kotlin에서 Node.js의 http 모듈을 사용하여 서버를 만들어서 Express.js를 사용하여 라우팅 처리를 합니다. 이러한 방식으로 Kotlin 코드를 사용하여 Node.js 애플리케이션을 개발할 수 있습니다.
import http.*
import express.*
fun main(args: Array<String>) {
val app = express()
app.get("/", { req, res ->
res.send("Hello, World!")
})
http.createServer(app).listen(3000)
println("Server listening on port 3000")
}
8. 대화형 셸(Interactive shell)
💡 Kotlin은 대화형 셸을 지원하여 코드 작성 시간을 줄이고 코드 테스트를 쉽게 할 수 있습니다. 또한 이를 이용하면 환경 구축을 하지 않고도 코드를 빠르게 실행하고 즉시 결과를 확인할 수 있습니다.
8.1. IntelliJ KotlinREPL을 이용한 사용방법
💡 도구(tool) - Kotlin - KotlinREPL을 선택합니다.
8.2. Terminal을 이용한 사용방법
💡 homebrew를 통하여서 kotlin을 설치합니다.
# kotlin을 확인합니다.
$ brew search kotlin
# kotlin을 설치합니다.
$ brew install kotlin
💡 kotlinc를 통하여 코틀린 컴파일러를 수행합니다.
💡 실제 함수를 수행시켜 봅니다.
fun main() {
println("Hello, World!")
}
main()
9. 상속과 인터페이스(Extends and interfaces)로 다중상속 효과를 구성할 수 있습니다.
💡 Kotlin은 다중상속을 지원하지 않지만 인터페이스를 이용하여 다중상속의 효과를 얻을 수 있습니다.
💡 해당 예시에서는 인터페이스 A, B를 구성하고 각각의 인터페이스 함수인 a(), b()를 구성하였습니다. 그리고 클래스 C에서 실제 A, B의 구현체로 구성을 하였습니다. 최종 main() 함수에서 구성된 C 클래스의 인스턴스를 구성하고 각각의 함수를 호출하여 다중상속 효과를 구성합니다.
interface A {
fun a()
}
interface B {
fun b()
}
class C : A, B {
override fun a() {
println("A")
}
override fun b() {
println("B")
}
}
fun main(args: Array<String>) {
val c = C()
c.a()
c.b()
}
오늘도 감사합니다. 😀
반응형
'Kotlin > 이해하기' 카테고리의 다른 글
[Kotlin] Kotlin 기본 문법 이해하기 -1 : 주요 특징 및 문법 이해(변수 및 데이터 타입, 캐스팅, Null) (0) | 2024.11.22 |
---|---|
[Kotlin] 앱 아키텍처 패턴(MVC, MVP, MVVM) 이해하기 (0) | 2022.09.20 |
[Kotlin] 소스코드 스타일 / 명명 규칙 이해하기 (0) | 2022.09.19 |