1. ์ฝํ๋ฆฐ ์ดํดํ๊ธฐ
1. ์ฝํ๋ฆฐ์ ํ์ฌ์ ๋ฏธ๋
์ฝํ๋ฆฐ์ ๋ฐฐ์์ผ ํ๋ ์ด์
- Jetbrains์์ ๋ง๋ ์ธ์ด
- โ ์๋์์ฑ, ์ฝํ๋ฆฐ ๋ณํ, ์ฝ๋ฃจํด๋ฑ ๊ด๋ จ ํธ์ ๊ธฐ๋ฅ์ ์ง์ํ๋ค.
- ์๋ฐ๋ ๋ฐํ๋์ง 20๋ ์ด ๋์์ง๋ง ์ฝํ๋ฆฐ, ์ค์ํํธ์ ๊ฐ์ ํ๋์ธ์ด์ ๋นํด ๊ธฐ๋ฅ์ด ๋ถ์กฑํ๋ค.
- ์๋ฐ์์ best-practice๋ก ๋ถ๋ฆฌ๋ ๊ธฐ๋ฒ๋ค์ ์ธ์ด์ ์ฐจ์์์ ๊ธฐ๋ณธ์ ์ผ๋ก ์ ๊ณตํ๋ค.
- ex) ์ดํํฐ๋ธ ์๋ฐ, ๋์์ธํจํด ๋ฑ
- ์๋ฐ์ ๋นํด ๋ฌธ๋ฒ์ด ๊ฐ๊ฒฐ โ ๊ฐ๋ ์ฑ, ์์ฐ์ฑ์ด ๋๊ณ ์ค๋ฅ ๊ฐ๋ฅ์ฑ์ด ์ ๋ค.
// equals(), hashCode(), toString() ์๋์ผ๋ก ์์ฑ
data class Person(
val name: String,
val age: Int,
val email: String
)
// ๊ฐ๋จํ๊ฒ ์ฑ๊ธํด ๊ฐ์ฒด๋ฅผ ์์ฑ
object MyCompany {
const val name: String = "MyCompany"
}
// ํ๋ ๋ฒจ ํจ์๋ก ํด๋์ค ์ธ๋ถ์์ ํจ์๋ฅผ ์์ฑํ๋ค.
fun main() {
//new ํค์๋ ์์ด ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ค
val person = Person(" ", 35, "a@gmail.com")
println(person)
}
data class๋ฅผ ์ฌ์ฉํ๋ฉด equals, hashCode, toString ํจ์๋ฅผ ์๋์ผ๋ก ์์ฑํ๋ค.
object ํค์๋๋ ์ฑ๊ธํด ๊ฐ์ฒด๋ฅผ ์๋์ผ๋ก ์์ฑํ๋ค.
fun์ ์ด์ฉํด ํจ์๋ฅผ ํ๋ ๋ฒจ์ ์์น์์ผ ๋ณ๋์ ํด๋์ค ์์ด ํจ์๋ฅผ ์์ฑํ ์ ์๋ค. ๋ํ new ํค์๋ ์์ด ๊ฐ์ฒด๋ฅผ ์์ฑํ ์ ์๋ค.
- ์๋ฐ์ ์ํธ ์ด์ฉ์ด ๊ฐ๋ฅํ๊ธฐ ๋๋ฌธ์ ๊ธฐ์กด ์๋ฐํ๋ก์ ํธ์ ์ฝ๊ฒ ์ ์ฉํ ์ ์๋ค.
- ์ฝํ๋ฆฐ์ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ฉํฐ ํ๋ซํผ ์ธ์ด๋ก์จ, ๋ชจ๋ฐ์ผ์ฑ(์๋๋ก์ด๋, ios), ํ๋ก ํธ(js)๋ฑ ๋ชจ๋ ๋ถ์ผ์์ ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค.
2. ์ฝํ๋ฆฐ ํ์๋ผ์ธ
- 2016๋ ์ฝํ๋ฆฐ 1.0 ๋ฆด๋ฆฌ์ฆ
- 2017๋ ์คํ๋ง ํ๋ ์์ํฌ 5.0๋ถํฐ ์ฝํ๋ฆฐ ๊ณต์ ์ง์
- 2017๋ ๊ตฌ๊ธ io์์ ์๋๋ก์ด๋ ๊ณต์ ์ง์ ์ธ์ด๋ก ๋ฐํ
- 2019๋ ๊ตฌ๊ธ io์์ ์๋๋ก์ด๋ ๊ฐ๋ฐ์ ์ต์ฐ์ ์ธ์ด๋ก ์ฝํ๋ฆฐ ๋ฐํ
- ์คํ ์ค๋ฒํ๋ก์ฐ ํธ๋ ๋์์ ์ฝํ๋ฆฐ ์ธ๊ธฐ๊ฐ ๊ณ์ ์์นํ๊ณ , ์๋ฐ๋ ๊ฐ์ํ๋๊ฒ์ ํ์ธํ ์ ์์.
- ์ ๋ช
์คํ์์ค ํ๋ก์ ํธ์ ์ฝํ๋ฆฐ ์ง์ ํํฉ
- ์คํ๋ง ํ๋ ์์ํฌ
- ๊ณต์ ๋ฌธ์ ์์ ์ ์๋ฐ์ ์ฝํ๋ฆฐ 2๊ฐ์ง ํญ์ด ๋๋์ด์์
- gradle์ ๊ธฐ์กด์ groovy๋ฌธ๋ฒ๋ง ์ง์ํ์๋๋ฐ, ์์ฆ์ kotlin dsl์ ์ง์ํ๊ธฐ ๋๋ฌธ์ ์๋์์ฑ, ์ปดํ์ผ ๊ฒ์ฌ๋ฅผ ๋ฐ์ ์ ์์.
- ์คํ๋ง ํ๋ ์์ํฌ
3. ์๋ฐ์ ์ฝํ๋ฆฐ์ ์ฐจ์ด์
โ ์๋ฐ์๋ ์์ง๋ง ์ฝํ๋ฆฐ์๋ ์๋ ๊ธฐ๋ฅ
- ์ฒดํฌ๋ ์ต์
์
(Checked Exception)
- ์๋ฐ๋ ์ต์ ์ ๊ณ์ธต์ผ๋ก ๊ตฌ์ฑ
Error
: ์์คํ ์์ ์๋ฌ๊ฐ ๋ฐ์ํด์ ๋ณต๊ตฌ๊ฐ ์ด๋ ค์ด ์ํฉ(OOM, StackOverFlow Error)Exception
CheckedException
: ์์คํ ์์ ํฌ์ฐฉ ๊ฐ๋ฅํ์ฌ ๋ณต๊ตฌ ๊ฐ๋ฅ, ์์ธ์ฒ๋ฆฌ๋ฅผ ๊ฐ์ ํ๋ค. (IOException, FileNotFoundException)RuntimeException
: ๋ฐํ์์์ ๋ฐ์, ์์ธ์ฒ๋ฆฌ ๊ฐ์ ํ์ง ์์(NullPointerException, ArrayIndexOutOf`BoundsException, Unchecked Exception)
- ์๋ฐ์์ checked exception์ ์ปดํ์ผ ์๋ฌ๊ฐ ๋ฐ์ํ๊ธฐ ๋๋ฌธ์ ๋ฌด์กฐ๊ฑด try-catch๋ก ๊ฐ์ธ๊ฑฐ๋ throws๋ก ์๋ฌ๋ฅผ ์ ํํด์ผ ํ๋ค.
- โ ์๋ฏธ์๋ ์ฒ๋ฆฌ์ ๋ฐ๋ณต์ด ์ผ์ด๋๋ค.
try {
File file = FileUtils.get(filename);
} catch (FileNotFoundExcepition e) { //checked exception์ด ๋ฐ์ํ์ง๋ง ์๋ฏธ์๋ ์์
์ฒ๋ฆฌ๊ฐ ์์
//์ฒ๋ฆฌ?
}
- ์ฝํ๋ฆฐ์ checked exception์ ๊ฐ์ ํ์ง ์๋๋ค. try-catch๋ฌธ์ ์๋ตํด๋ ์ปดํ์ผ ์๋ฌ๊ฐ ๋ฐ์ํ์ง ์๋๋ค.
- ๊ธฐ๋ณธ ์๋ฃํ
- ์๋ฐ๋ ์์ ์๋ฃํ๊ณผ ๋ ํผ๋ฐ์ค ํ์ ๋ชจ๋ ์ง์ํ๋ค.
int i = 0; // primitive type
Integer ii = 0; //reference type
- ์ฝํ๋ฆฐ์ ๋ ํผ๋ฐ์ค ํ์ ๋ง ์ง์ํ๋ค.
val i : Int = 0
val str : String = i.toString()
๋ ํผ๋ฐ์ค ํ์
์ ์ปดํ์ผ ํ ๋ **์ต์ ํ๋ ๋ฐฉ์์ผ๋ก ์ปดํ์ผ**ํ๋ค.
์์ ์์ ์์ ์ปดํ์ผ๋ ๋์๋ ์์ํ์
์ธ int๋ก, str์ String์ด ๋๋ค.
//์์ ์ฝ๋๊ฐ ์ปดํ์ผ ๋ ๋ ํด์๋๋ ๋ด์ฉ -> ์ต์ ํ๋ ์ฑ๋ฅ ๋ณด์ฅ
int i = 0;
String str = String.valueOf(i);
- ์ ์ ๋ฉค๋ฒ
- ์๋ฐ๋ static ํค์๋๋ก ์ ์ ๋ฉค๋ฒ๋ฅผ ์ ์ธํ์ง๋ง, ์ฝํ๋ฆฐ์ static์ด ์กด์ฌํ์ง ์๊ณ companion object๋ก ๋์ฒดํ๋ค.
class Kotlin {
companion object { //static๊ณผ ์ ์ฌํ ํค์๋, companion object
val i: Int = 0
fun function() {
}
}
}
- ์ผํญ ์ฐ์ฐ์
- ์๋ฐ์๋ ์ผํญ์ฐ์ฐ์๊ฐ ์กด์ฌํ์ง๋ง, ์ฝํ๋ฆฐ์ if-else๋ก ๋์ ํ๋ค.
val animalSound: String = if("ํธ๋์ด" == animal) "์ดํฅ" else "์ผ์น"
kotlin์ if-else๊ฐ **์**์ด ๋ ์ ์๋ค.(== ๊ฐ์ ๋ฆฌํดํ ์ ์๋ค)
- ์ธ๋ฏธ์ฝ๋ก (;)
- ์ฝํ๋ฆฐ์ ์ธ๋ฏธ์ฝ๋ก ์ด ํ์๊ฐ ์๋๋ค.
โ ์ฝํ๋ฆฐ์๋ ์์ง๋ง ์๋ฐ์๋ ์๋ ๊ธฐ๋ฅ
- ํ์ฅ
- ๊ฐ๋ฐ์๊ฐ ์์๋ก ๊ฐ์ฒด์ ํจ์๋ ํ๋กํผํฐ๋ฅผ ํ์ฅํด์ ์ฌ์ฉํ ์ ์๋ค.
//String ํจ์์ first๋ผ๋ ํ์ฅํจ์๋ฅผ ์ฌ์ฉ
fun String.first(): Char {
return this[0]
}
//String ํจ์์ addFirst๋ผ๋ ํ์ฅํจ์๋ฅผ ์ฌ์ฉ
fun String.addFirst(char: Char): String {
return char + this.substring(0)
}
fun main() {
println("ABCD".first()) //์ถ๋ ฅ : A
println("ABCD".addFirst('Z')) // ์ถ๋ ฅ : ZABCD
}
- ๋ฐ์ดํฐ ํด๋์ค
- ๋ฐ์ดํฐ๋ฅผ ๋ณด๊ดํ๊ฑฐ๋ ์ ๋ฌํ๋ ๋ชฉ์ ์ ๊ฐ์ง ๋ถ๋ณ๊ฐ์ฒด๋ก ์ฌ์ฉ
- DTO๋ก ์ฃผ๋ก ์ ์ฉํ๊ฒ ์ฌ์ฉํ๋ค.
// dataํค์๋๋ก ์ฌ์ฉ, hashCode(), equals(), toString(), copy(), componentN() ์๋์์ฑ
data class Person(val name: String, val age: Int)
- ๊ธฐ์กด ์๋ฐ์์๋ ์ฃผ๋ก lombok ํ๋ฌ๊ทธ์ธ์ ์ด์ฉํด ์๋์ผ๋ก ์์ฑํ๋ค. ์ฝํ๋ฆฐ์ ํ๋ฌ๊ทธ์ธ์ด ์๋ ์ธ์ด๋ ๋ฒจ์์ ์ง์์ ํด์ฃผ๊ธฐ ๋๋ฌธ์ ์ ์ฉํ๋ค.
- +) jdk 15์์ record๋ผ๋ ์ด๋ฆ์ผ๋ก ์ถ๊ฐ๋จ โ Data ํด๋์ค์ ๋์ผํ ๋ชฉ์ ์ผ๋ก ์ฌ์ฉ
- ๋ฌธ์์ด ํ
ํ๋ฆฟ
- ์ฝํ๋ฆฐ์ ๋ฌธ์์ด์ ๋ณ์๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
val text = "World"
val greeting = "Hello, **${text}**"
- ์ฝํ๋ฆฐ์ ์ฌ๋ฌ ํ์ผ๋ก ๋ ํ ์คํธ ๋ธ๋ก์ ๋ง๋ค ์ ์๋ค.
fun sql(nameIncluded: Boolean) =
"""
SELECT id, name, email, age
FROM users
WHERE id = :id
${
if(nameIncluded) {
"""
AND name = :name
"""
} else ""
}
"""
3๊ฐ์ ์๋ฐ์ดํ๋ฅผ ์ฌ์ฉํด ๋ฌธ์์ด ํ
ํ๋ฆฟ์ ๋ง๋ค ์ ์๋ค. ๋ค์ด๋๋ฏน ์ฟผ๋ฆฌ๋ฅผ ๋ง๋ค ๋ ์ฝํ๋ฆฐ์ผ๋ก string์ ๋ง๋ค๊ณ , ์์์ ๋ณ์๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
- ๋(Null) ์์ ์ฑ
- ์๋ฐ์์ ๊ฐ์ฅ ๋ง์ด ๋ฐ์ํ๋ ์์ธ๋ NPE (NullPointerException) ์ด๋ค.
null์ ๋ํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋๋ก Optional์ ์ ๊ณตํ๊ณ ๋ ์์ง๋ง, optional ๊ฐ์ฒด ์์ฑ์ ๋ฐ๋ฅธ ์ค๋ฒํค๋๊ฐ ๋ฐ์ํ๊ณ , ์ปดํ์ผ ๋จ๊ณ์์๋ Null ๊ฐ๋ฅ์ฑ์ ๊ฒ์ฌํ์ง ์๋๋ค.
- ์ฝํ๋ฆฐ์ ์ธ์ด์ฐจ์์์ NPE๊ฐ ๋ฐ์ํ ๊ฐ๋ฅ์ฑ์ ์ ๊ฑฐํ๋ค.
- ์๋ฐ์์ ๊ฐ์ฅ ๋ง์ด ๋ฐ์ํ๋ ์์ธ๋ NPE (NullPointerException) ์ด๋ค.
val a: String = null //์ปดํ์ผ์ค๋ฅ(nullable์ด ์๋๊ธฐ ๋๋ฌธ)
var b : String = "aabbcc"
b = null //์ง์ฐ์ด๊ธฐํ๋ก null์ ๋ฃ์์ ๊ฒฝ์ฐ ์ปดํ์ผ ์ค๋ฅ ๋ฐ์
var a: String? = null
a.length //์ปดํ์ผ ์ค๋ฅ ๋ฐ์
a?.length //?์ฐธ์กฐ๋ฅผ ์ด์ฉํด safe-call, null์ด ์๋๊ฒฝ์ฐ์๋ง ๋์
a!!.length //!!์ ์ด์ฉํด null์ด ์ ๋ ์๋ค์ด๊ฐ์ ํ์ ํ๋ค.
์ฝํ๋ฆฐ์์๋ NPE๋ฅผ ์์ฐ์ค๋ฝ๊ฒ ๋ฐฉ์งํ ์ ์๋ ๊ธฐ๋ฒ๋ค์ ์ ๊ณตํ๋ค.
- smart cast, sealed class, coroutine
4. ์คํ๋ง์ ์ฝํ๋ฆฐ ์ง์
Spring initializr
- ๊ธฐ๋ณธ ์ธ์ด๋ก ์ฝํ๋ฆฐ์ ์ ํํ ์ ์๊ณ , ์ฝํ๋ฆฐ์ ๊ฒฝ์ฐ gradle project๋ฅผ ์ ํํ๋ฉด ๋น๋ ์ค์ ์
kotlin DSL
๊ธฐ๋ฐ์ผ๋ก ์์ฑํด์ค๋ค. - ide์ ๋์์ ๋ฐ์ ์ ์๊ธฐ ๋๋ฌธ์ ์ฝ๊ฒ ์ค์ ํ์ผ์ ์ธํ ํ ์ ์๋ค.
์คํ๋ง ๋ถํธ
- ๋ณ๋ค๋ฅธ ๋ณ๊ฒฝ์ฌํญ ์์ด ์คํ๋ง๋ถํธ ์ดํ๋ฆฌ์ผ์ด์ ์ ์คํํ ์ ์๋ค.
@SpringBootApplication
class DemoApplication // ํด๋์ค๊ฐ ์๊ธด ํ์ง๋ง ์ค๊ดํธ๋ก ๋ฉ์ธ์ ๊ฐ์ธ๊ณ ์์ง ์์
//ํ-๋ ๋ฒจ ํจ์๋ก ํด๋์ค ๋ฐ๊นฅ์์ ํธ์ถํ๋ค.
fun main(args: Array<String>){
runApplication<DemoApplication>(args)
}
@ConfigurationProperties
- ์คํ๋ง์์ ์ง์ ํ ์ค์ ์ ๊ธฐ๋ฐ์ผ๋ก ์ค์ ํด๋์ค๋ฅผ ๋ง๋ค ๋,
@ConstructorBinding
์ ์ฌ์ฉํ๋ฉด setter๊ฐ ์๋ ์์ฑ์๋ฅผ ํตํด ๋ฐ์ธ๋ฉํ๋ฏ๋ก ๋ถ๋ณ๊ฐ์ฒด๋ฅผ ์ฝ๊ฒ ์์ฑํ ์ ์๋ค.
@ConstructorBinding
@ConfigurationProperties("example.kotlin")
data class KotlinExampleProperties(
val name: String,
val description: String,
val myService: MyService) {
data class MyService(
val apiToken: String,
val uri: URI
)
}
ํ ์คํธ ์ง์
- SpringMockK๋ผ๋ ์ฝํ๋ฆฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ด์ฉํด
@MockkBean
,@SpykBean
์ ์ฌ์ฉํ๋ค.
@ExtendWith(SpringExtension::class)
@WebMvcTest
class GreetingControllerTest {
@MockkBean
private lateinit var greetingService: GreetingService
@Autowired
private lateinit var controller: GreetingController
@Test
fun `should greet by delegating to the greeting service`() { // ํจ์๋ช
์ ๋์ด์ฐ๊ธฐ, ์์ฝ์ด ๋ชจ๋ ๊ฐ๋ฅ
// Mockk์์ ์ ๊ณตํ๋ ๊ธฐ๋ฅ
every { greetingService.greet("John") } returns "Hi John"
// When
assertThat(controller.greet("John")).isEqualTo("Hi John")
// Then
verify { greetingService.greet("John") }
}
}
ํ์ฅ ํจ์
- ์ฝํ๋ฆฐ api์ ๋๋ถ๋ถ์ ํ์ฅ๊ธฐ๋ฅ์ ์ฌ์ฉํด ๊ธฐ์กด api๋ฅผ ๊ฑด๋๋ฆฌ์ง ์๊ณ ์ฝ๊ฒ ์ฝํ๋ฆฐ api๋ฅผ ์ถ๊ฐํ๋ค.
// CrudRepositoryExtensions.kt
package org.springframework.data.repository
fun <T, ID> CrudRepository<T, ID>.findByIdOrNull(id: ID): T? {
return findById(id).orElse(null)
}
//MyService.kt
class MyService(
private val myRepository: MyRepository, ){
fun findById(id: Long): My? = myRepository.findByIdOrNull(id)
}
์ฝ๋ฃจํด
- ์ฝํ๋ฆฐ์์ ๋น๋๊ธฐ-๋ ผ๋ธ๋กํน ๋ฐฉ์์ ์ ์ธํ์ผ๋ก ๊ตฌํํ๋ค.
- ์คํ๋ง mvc, webflux ๋ชจ๋ ์ฝ๋ฃจํด์ ์ง์ โ ์์กด์ฑ๋ง ์ถ๊ฐํ๋ฉด ๋ฐ๋ก ์ฌ์ฉ ๊ฐ๋ฅํ๋ค.
- ๋น๋๊ธฐ-๋ ผ๋ธ๋กํน ์คํ์ผ์ ๊ตฌํ์ ์ฝ๊ฒ ํ ์ ์๋ค. (suspend ํค์๋, async, await)
์ฐธ๊ณ
์ ํํ ์ ๋ณด๋ฅผ ์ ๋ฌํ๊ณ ์ ์ต์ ์ ๋คํ์ง๋ง, ํ๋ฆฐ ๋ถ๋ถ์ด ์์ ์ ์์ต๋๋ค!
ํ๋ฆฐ ๋ถ๋ถ์ด ์์ ์ ์ง์ ํด์ฃผ์๋ฉด ๊ฐ์ฌํ ๋ฐ์ํ๊ฒ ์ต๋๋ค๐
'๐ค study > Kotlin' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
- 1. ์ฝํ๋ฆฐ์ ํ์ฌ์ ๋ฏธ๋
- 2. ์ฝํ๋ฆฐ ํ์๋ผ์ธ
- 3. ์๋ฐ์ ์ฝํ๋ฆฐ์ ์ฐจ์ด์
- โ ์๋ฐ์๋ ์์ง๋ง ์ฝํ๋ฆฐ์๋ ์๋ ๊ธฐ๋ฅ
- โ ์ฝํ๋ฆฐ์๋ ์์ง๋ง ์๋ฐ์๋ ์๋ ๊ธฐ๋ฅ
- 4. ์คํ๋ง์ ์ฝํ๋ฆฐ ์ง์
- Spring initializr
- ์คํ๋ง ๋ถํธ
- @ConfigurationProperties
- ํ ์คํธ ์ง์
- ํ์ฅ ํจ์
- ์ฝ๋ฃจํด
- ์ฐธ๊ณ