JEP's Diary

2. 자바와 비교해 보는 코틀린 2 본문

Development/Kotlin

2. 자바와 비교해 보는 코틀린 2

지으니88 2018. 11. 11. 18:36

2. 자바와 비교해 보는 코틀린 2


자료/자료형의 확인 및 변환


- 자료의 동일성 확인: ==, === 연산자

: == 연산자는 객체냐 객체의 값이냐를 구분할 필요 없이 ==연산자를 사용한다. 또한 비교하는 값의 널 여부를 함께 확인한다.

: === 연산자는 객체 자체가 동일한지 여부에 대한 비교 연산자이다.


- 자료형 확인: is 연산자

: is연산자는 자료형을 확인하기 위해 사용한다. (자바의 instanceOf)

: !is 연산자는 자료형이 아닌지는 확인할때 사용한다.


- 자료형 변환: as 연산자

1
2
3
fun processNumger(number: Number) {
    val foo : Int = number as Int
}
cs


- 스마트 캐스트

: 자료형 추론이 가능할 경우 캐스팅 없이 해당하는 자료형으로 객체를 사용할 수 있도록 스마트 캐스트 기능을 지원한다.

: 값을 검사하는 시점과 사용하는 시점에 값이 변하지 않았다는 것이 보장되었을 경우에만 지원되므로, var변수는 지원하지 않는다.

1
2
3
4
5
6
7
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
    if (holder is PhotoHolder) {
        holder.setImageUrl(mImageUril)
    } else if (holder is Textholder) {
        holder.setText(mText)
    }
}
cs



흐름제어


- if-else문

: 자바와 사용법은 같지만 코틀린에서는 if-else 문은 값을 반환 할 수 있다.

: 따라서 자바의 삼항연산자를 대신할 수 있다.

1
2
val numger: Int = 20
val str: String = if (number % 2 == 0"Even" else "Odd"
cs

 

- when문

: 자바의 switch문을 대신한다. 또한 값을 반환 할 수 있다.

: 조건을 표현식으로 작성 할 수 있다.


- while문

: 자바의 while문과 do while문과 같다.


- for문

: for-each 형태만 지원한다.

: for문 내에서 현재 항목의 인덱스가 필요할때는 Collection.indicies 프로퍼티를 사용한다.

1
2
3
4
5
val names: List<String> = ...
 
for (i in names.indicies) {
    Log.e("Name","name=${names[i]}")
}
cs


- 범위

: 특정 범위를 순환하거나 해당 범위 내에 특정 항목이 포함 되어 있는지 확인 할 때 사용한다.

: .. 연산자를 사용하여 정의한다.

: 0...10 의 경우는 시작과 끝을 포함하는 범위를 정의한다. 0 until 10 의 경우는 가장 마지막 값을 포함하지 않는 범위를 정의한다.

: in 연산자는 범위 내에 특정 항목이 있는지를 알수 있다.

: downTo() 함수는 반대로 정렬된 범위를 생성할 수 있다. 

1
2
3
for ( i in 5 downTo 1) {
    System.out.print(i)
}
cs



제네릭

: 제네릭은 인자로 사용하는 타입에 따라 구체화되는 클래스나 인터페이스이다.


- 제네릭 클래스의 인스턴스 생성 및 사용

: 꺽쇠<> 안에 타입을 넣어 표현한다.


- 제네릭 클래스/인터페이스 정의

: 예제

1
2
3
4
5
6
7
8
9
10
11
class Car {}
 
interface Container<T> {
    fun put(item: T)
    fun take() : T
}
 
class Garage: Container<Car> {
    override fun put(item: Car) {}
    override fun take() : Car {}
}
cs


: Container 인터페이스가 받을 수 있는 타입은 Car 클래스 및 하위 클래스로 제한하는 예제

1
2
3
4
5
interface Container<T: Car> {
    fun put(item: T)
    fun take() : T
}
 
cs


: 자바의 '?  super T' (정해지는 타입 및 그 하위 타입을 받음) ->  코틀린에서는 in T

: 자바의 '? extends T'(정해지는 타입 및 그 상위 타입을 받음) -> 코틀린에서는 out T


예외

: 코틀린의 예외는 자바와 거의 동일하며, 예외를 발생시키려면 throw 키워드를 사용한다.

: try-catch , finally 문은 값을 반환 할 수 있다.


널 안전성

- 널 허용 여부 표기

: 널 값을 가질 수 있도록 하려면 명시적으로 타입 뒤에 ?를 붙여주어야 한다.

fun checkNullable() {
val nullableString: String? = null
val nonNullString: String = "Foo"
}


널 값을 대신하는 방법 : 엘비스(?:)연산자

- foo ?: bar

: foor 가 null이 아닐 경우에는 foo를, null이라면 bar를 반환 

@Test
fun test1() {
val postal: PostalCode = findPostalCode("test address") ?: PostalCode.None
// findPostalCode 에서 null일 경우 PostalCode.None 대입
Assert.assertNotNull(postal)
}

private fun findPostalCode(address: String) : PostalCode? {
return null
}

널 값 확인과 처리를 한번에: 안전한 호출(?.) 연산자

: 안전한 호출 연산자를 사용하여 널 값 확인과 값 접근/함수 호출을 한번에 할 수 있다.

: 객체가 널 값이 아닌 경우에 연산자 뒤의 문장을 수행한다. 널 값일 경우는 뒤에 문장을 수행하지 않고 널값을 반환한다.

fun test2() {
var bar: Bar? = null
// bar가 null이 아닐 경우에만 해당값을 대입, 그렇지않으면 null을 대입
val foo = bar?.baz

// bar가 null이 아닐 경우에만 bar()을 호출
bar?.bar()

Assert.assertNull(foo)
}

class Bar {
val baz = "bar"
fun bar() {}
}

안전한 자료형 변환: as? 연산자

: 안전한 변환 연산자는 자료형 변환이 실패할 경우에 예외를 발생시키는 대신 널 값을 반환한다. 따라서 반환되는 값을 통해 변환 결과를 바로 확인 할 수 있다.

fun convertTest() {
val foo: String = "foo"
// foo을 Int형으로 반환시 null반환이 되고, null일 경우 0으로 값 지정
var bar: Int = foo as? Int ?: 0
Assert.assertNotNull(bar)
}

널 값이 아님을 명시하기: 비 널 값 보증(!!)

: 널 값을 포함하지 않는다고 보증을 하는 연산자 !! 을 사용한다.

: 비 널 값 보증을 사용하였으나 실제 객체에 null값일 경우는 널포인터 예외가 발생한다.


나중에 초기화 되는 변수를 취해 : lateinit 키워드

: 코틀린은 널 값을 허용하지 않는 경우 초기화를 해주거나 생성자를 통해 값을 초기화하도록 강제하지만, lateinit 키워드를 사용하면 초기화 없이 변수만 선언할 수 있다.

: lateinit var api: Api

: 초기화를 하지 않은 상태로 사용하려하면 예외가 발생하니 유의해야한다.



참고 : 차세대 안드로이드 개발자를 위한 커니의 코틀린