https://twitter.com/AndroidDev 에서 #31DaysOfKotlin 태그로 3월 1일부터 글이 올라오고 있다.
어디에 정리할까하다가 버려둔 여기가 생각났다.
Day 1. Elvis operator
엘비스 연산자를 사용하면 다음과 같이 null 을 처리 할수 있다.
kotlin에서 return 과 throw는 expressions 이므로 엘비스 연산자 우측에 사용할 수 있다.
val name: String = person.name ?: "unknown"
val age = person.age ?: return
Day 2. String templates
'$' 를 사용하면 쉽게 문자열을 만들 수 있다.
val language = "Kotlin"
// "Kotlin has 6 characters"
val text = "$language has ${language.length} characters"
Day 3. Destructuring Declarations
AndroidKTX. 에서는 구조 분해 선언을 사용하여 아래와 같은 구문을 사용할 수 있다.
data 클래스로 선언하는 경우 주 생성자에 대하여 componentN 함수가 자동으로 생성된다.
data 클래스가 아닌 경우 operator 키워드를 사용하여 직접 함수를 구현하여야 한다.
// now with prisms
val (red, green, blue) = color
// destructuring for squares
val (left, top, right, bottom) = rect
// or more pointedly
val (x, y) = point
// 기존에 존재하는 클래스를 구조 분해 선언을 사용하고자 하는 경우
class Person(val name: String, val age: Int)
inline operator fun Person.component1() = this.name
inline operator fun Person.component2()= this.age
Day 4. When Expression
코틀린에는 switch 문이 없다. when을 사용하여 JAVA의 switch 보다 더 다양하게 사용할 수 있다.
class Train(val cargo: Number?) {
override fun toString(): String {
return when (cargo) {
null, 0 -> "empty"
1 -> "tiny"
in 2..10 -> "small"
is Int -> "big inty"
else -> "$cargo"
}
}
}
Day 5. Ranges, Destructuring Declarations
- https://kotlinlang.org/docs/reference/ranges.html
- https://kotlinlang.org/docs/reference/multi-declarations.html#destructuring-declarations
// iterating in the range 1 to 100
for(i in 1..100) { println(i) }
// iterating backwards, in the range 100 to 1
// 100..1 로 쓰면 안된다.
for(i in 100 downTo 1) { println(i) }
// iterating over an array, getting every other element
// until을 사용하면 '미만'이다.
// step 단위로 증가한다.
// 아래는 1이 출력된다. 1부터 2까지 step 2로 증가다.
val array = arrayOf("a", "b", "x")
for(i in 1 until array.size step 2 ) { println(i) }
// iterating over an array with the item index and destructuring
for((index, element) in array.withIndex()) { println("$index : $element") }
// iterating over a map
val map = mapOf(1 to "one", 2 to "two")
for((key, value) in map) { println("$key : $value") }
Day 6. Properties
Kotlin에서 Property는 getter/setter를 통해 접근한다. 'val' 는 변경 불가능한 변수이므로 setter가 생성되지 않는다.
'field' 를 통해 setter에서 변수의 값을 수정할 수 있다.
class User {
// properties
val id: String = "" // immutable. just getter
var name: String = "" // default getter and setter
var surname: String = "" // custom getter, default setter
get() = surname.toUpperCase() // custom getter declaration
var email: String = "" // default getter, custom setter
set(value) {
// "value" = name of the setter parameter
// "field" = property's backing field; generated
if(isEmailValid()) field = value
}
}
Day 7. Data class, Equality
- https://kotlinlang.org/docs/reference/data-classes.html#data-classes
- https://kotlinlang.org/docs/reference/equality.html
data 클래스를 생성하면 equals(), hashCode(), toString(), copy(), componentN() 함수가 자동으로 생성된다.
코틀린에서 == 연산자는 자바의 equals 함수로 대치된다. 심지어 널체크도 된다.
(cf. 0.0과 -0.0은 서로 다른 값이다. -0.0은 0.0보다 작은 값이다.)
data class User(val name: String, val email: String)
fun main(args: Array<String>) {
val user1 = User("Kim", "[email protected]")
val user2 = User("Kim", "[email protected]")
val user3 = null
println("${user1 == user2}") // true
println("${user3 == user2}") // false
}
Day 8. Visibility Modifiers
코틀린의 기본 visivility는 public 이다. 또한 코틀린은 자바와 다르게 클래스 선언 없이도 변수와 함수를 파일에 선언할 수 있다.
// example.kt
// public by default
val isVisible = true
// only in the same file
private val isHidden = true
// internal to compilation 'module'
// internal은 생소한 녀석인데, 함께 컴파일 되는 모듈 안에서만 visible이 true이다.
// 그러나 자바에서는 해당 visibility가 없기 때문에, public 으로 컴파일 된다고 한다.
internal val almostVisible = true
class Foo {
// public by default
val isVisible = true
// visible to my subclasses
protected val isInheritable = true
// only in the same class
private val isHidden = true
}
Day 9. Default Arguments
코틀린에서 기본 인수를 사용하면 코드를 좀 더 깔끔하고 읽기 쉽게 만들 수 있다. 쓸데없이 수 많은 오버로드 메서드를 만들지 않아도 된다.
// parameters with default values
class BulletPointSpan(
private val bulletRadius: Float = DEFAULT_BULLET_RADIUS,
private val gapWidth: Int = DEFAULT_GAP_WIDTH,
private val color: Int = Color.BLACK
) { /* ... */ }
// useing only default values
val bulletPointSpan = BulletPointSpan()
// 첫 번째 파라메터는 resource에서 얻은 값을 사용하고, gapWidth와 color값은 기본 값을 사용
val bulletPointSpan2 = BulletPointSpan(resource.getDimension(R.dimen.radius))
// 이름 있는 인수를 사용하여 첫 번째와 두 번째 인수는 기본 값을 사용하고 컬러는 레드를 사용
val bulletPointSpan3 = BulletPointSpan(color = Color.RED)
Day 10. Sealed Classes (3/3)
Sealed 클래스 첫 번째 시간.
Sealed 클래스를 사용하면 쉽게 에러 데이터를 다룰 수 있다. LiveData와 함께 사용하면 하나의 LiveData로 성공과 실패를 모두 나타낼 수 있다. 2개의 변수를 사용하는 것 보다 낫다.
sealed class NetworkResult
data class Success(val result: String) : NetworkResult()
data class Failure(val error: Error) : NetworkResult()
// one observer for success and failure
viewModel.data.observe(this,
Observer<NetworkResult> { data ->
data ?: return@Observer // skip nulls
when (data) {
is Success -> showResult(data.result) // smart cast to Success
is Failure -> showError(data.error) // smart cast to Failure
}
})
- Sealed 클래스 두 번째 시간.
RecyclerView adapter에 sealed classes를 사용할 수 있습니다. ViewHolders에 딱 맞는데 각각의 홀더에 명시적으로 매칭되는 모든 타입을 깔끔하게 나타낼 수 있습니다. Sealed 클래스를 사용하면 모든 타입에 매칭되지 않으면 컴파일 에러가 발생합니다.
// use Sealed classes as ViewHolders in a RecyclerViewAdapter
override fun onBindViewHolder(holder: SealedAdapterViewHolder, position: Int) {
return when (holder) { // compiler enforces handling all types
is HeaderHolder -> holder.displayHeader(items[position]) // smart cast here
is DetailHolder -> holder.displayDetails(items[position]) // smart cast here
}
}
- Sealed 클래스 마지막 시간.
RecyclerView Item에 많은 콜백 함수가 있는 경우(상세 클릭, 공유 액션, 삭제 액션), sealed classes를 사용할 수 있습니다.
하나의 콜백에서 모든 액션을 처리 할 수 있습니다.
sealed class DetailItemClickEvent
data class DetailBodyClick(val section: Int): DetailItemClickEvent()
data class ShareClick(val platform: String): DetailItemClickEvent()
data class DeleteClick(val confirmed: Boolean): DetailItemClickEvent()
class MyHandler : DetailItemClickInterface {
override fun onDetailClicked(item: DetailItemClickEvent) {
return when (item) { // compiler enforces handling all types
is DetailBodyClick -> expandBody(item.section)
is ShareClick -> shareOn(item.platform)
is DeleteClick -> if (item.confirmed) doDelete() else confirmDelete()
}
}
}
Day 11. Lazy
Lazy 를 사용하면 property 초기화를 사용하는 시점까지 미룰 수 있다. 이후 사용되어 초기화 된 값은 저장되어 다음 호출 시 사용된다.
val preference: String by lazy { sharedPreferences.getString(PREFERENCE_KEY) }
Day 12. Late initialized properties and variables
안드로이드에서는 onCreate 또는 다른 콜백에서 객체를 초기화 합니다. 코틀린에서 non-null 변수는 반드시 초기화 되어야 합니다. lateinit을 사용하면, 이 상황을 해결할 수 있습니다.
class MyActivity : AppCompatActivity() {
lateinit var recyclerView: RecyclerView // non-null, but not initialized
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//..
recyclerView = findViewById(R.id.recycler_view) // initialized here
}
}
Hey dude great post. Keep it up. I upvoted your post.
You can follow me on https://steemit.com/@manashjyoti
Downvoting a post can decrease pending rewards and make it less visible. Common reasons:
Submit
와우 이게 코틀린이군요. 자바 유저인 저에겐 참 신기한 문법들입니다. ㅎㅎㅎ 익숙해지면 편하겠네요.
Downvoting a post can decrease pending rewards and make it less visible. Common reasons:
Submit
코틀린에 관심이 있으시면, "Kotlin in Action" 책 추천드립니다. 자바와 비교하며 설명하고 있어서 좋아요~!
Downvoting a post can decrease pending rewards and make it less visible. Common reasons:
Submit