코틀린 자동차 경주

June·2022년 10월 28일
0

코틀린

목록 보기
1/1
post-thumbnail

코틀린을 빠르게 학습해야 하는데 책을 처음부터 읽기에는 시간이 부족했다. 그래서 예전에 학습해서 도메인 부담이 없는 간단한 프로그램들을 만들면서 하나씩 확장해 나가보기로 했다.

코틀린 자동차 경주를 구현하면서 나왔더 키워드들을 정리한다.

코틀린 공식문서

1. val, var

val은 read-only일 경우에 사용하고, 딱 한번만 할당할 수 있다고 한다. 자바에서 final과 비슷한 역할을 하는 것 같다. 반대로 가변변수들은 var를 쓰면된다.

정말 자바의 final과 비슷한 것이 val로 선언한 컬렉션이 있다면, 컬렉션 자체는 재할당 불가능하지만 그 안의 원소들은 바뀔 수 있다.

2. 생성자, init, getter/setter

생성자

위 코드는 로마한테 코드 리뷰를 받고 수정됐다.

이렇게 주생성자의 디폴트 값을 넣어 줄 수 있기 때문에 디폴트 값을 넣기 위한 용도로 부생성자를 쓸 필요는 없다.

코틀린을 처음 쓰면서 낯설었던 부분 중 하나이다. 코틀린에서 주생성자는 부생성자와 위치가 다르다. 주생성자는 클래스명 옆에 constructor()라는 이름으로 붙는다. constructor라는 키워드는 생략할 수도 있다.

자바를 쓰면서 생성자에서 필드를 검증하는 것에 대해 취향이 나뉘고는 했는데, 코틀린에서는 주생성자가 어떤 코드도 가질 수 없다. 검증하는 것은 init{} 부분에서 해주면 된다.

부생성자들은 constructor(파라미터): this(주생성자 파라미터) 이런식으로 사용해주면 된다.

getter/setter

주생성자에서 필드에 val을 붙이는지, var를 붙이는지, 아무것도 안붙이는지에 따라 차이가 난다.

클래스gettersetter
class Person(name: String)xx
class Person(var name: String)oo
class Person(val name: String)ox

getter/setter를 저절로 붙여줄 수 있다는 것에 주의하자. 나도 모르게 setter를 열어둘 수도 있다는 뜻이다.

class Rectangle(val width: Int, val height: Int) {
    val area: Int
        get() = this.width * this.height
}

getter/setter 역시 조금 특이한데 기본 getter가 아닌 커스텀 getter를 만들고 싶다면 이런식으로 작성해줘야 한다. 근데 굳이 getter를 커스텀해서 쓸 필요가 있나 싶다. getter/setter는 규약대로 쓰고 다른 메서드명으로 명확히 하는게 더 나을 것 같다.

생성자에 노출되지 않고 내부에서만 쓸 필드는 그럼 어떻게 getter만 허용하고 setter는 막을까?

(검색했더니 애쉬 블로그가 나왔다)

backing properties를 이용하는 방법도 있다는데 다음에 정리해본다.

코틀린에서 프로퍼티는 자바와 조금 다르다. getter/setter, 필드 모두 가지고 있는것을 프로퍼티라 부르는 것 같다.

차리의 프로퍼티 정리 블로그

backing field

보통 자바에서 필드들을 private으로 많이 두고 사용했다. 하지만 var number를 주생성자에 두면 밖에서 caluclator.number = 10과 같이 외부에서 변경이 가능하다. 이런 경우 backing property를 활용할 수 있다.

이렇게하면 number에 setter는 닫혀있는 셈이다.

3. object, companion object

1. object

자바와 동일한 키워드지만 완전히 다르게 사용되고 있었다.

  1. 클래스 앞에 object 키워드가 붙으면 싱글톤으로 처리해준다. The initialization of an object declaration is thread-safe and done on first access. 심지어 스레드 세이프하고 lazy initialization까지 지원해준다고 한다.

이런것들을 고려해봤을 때 자바에서 static class와 비슷한 것 같다.

2. companion object

이건 static 메서드와 비슷하다고 생각했다. 따라서 정적팩토리 메서드를 만들때 아래와 같이 활용할 수 있을 것 같다.

참고: https://www.bsidesoft.com/8187

4. 바로 fun

자바와 달리 어떤 객체에서 메서드를 정의하는 것이 아니라 그냥 파일에서 바로 함수를 정의할 수 있다.

5. 상속, 인터페이스와 구현체

상속을 할 때는 클래스 뒤에 : 를 붙이고 상속 대상을 적으면 된다. 타입을 나타낼 때는 콜론을 붙여쓰고, 상속을 의미할 때는 한칸 띄어쓰는 것이 컨벤션이라한다.

코틀린에서 override는 어노테이션이 아니기 때문에 이제 선택이 아닌 필수가 됐다.

자바의 클래스와 메서드는 기본적으로 상속에 대해 열려있지만 코틀린의 클래스와 메서드는 기본적으로 final이 닫혀있다. 어떤 클래스의 상속을 허용하려면 클래스 앞에 open 변경자를 붙여야 한다. 그와 더불어 오버라이드 하고 싶은 메서드나 프로퍼티 앞에도 open 변경자를 붙여야 한다. - 코틀린 인 액션 p.147-

6. data class, eq/hc ...

사실 적절하게 쓴 것인지는 잘 모르겠지만, 주된 목적이 데이터를 들고 있는 클래스의 경우 쓰면 좋다고 한다. 코틀린에서는 클래스 앞에 data 키워드를 붙이면 eq/hc, toString 등을 자동으로 재정의해준다.

주생성자에 선언된 필드를 기준으로만 eq/hc, toString 같은 것들이 재정의 되니까, 만약 제외하고 싶다면 위에 처럼 따로 선언하면 된다.

equals 관련해서 좀 재밌었던 것은 코틀린에선 비교 연산자를 사용하면 자동으로 compareTo를 호출해준다. 자바에서는 값객체를 쓸 때 불편했던 점이 position1.isBiggerThan(position2) 이런 코드를 작성해야 했기 때문인데 이제 position1 > position2가 가능하게 된 것이다.

7. nullable

코틀린에서는 디폴트가 변수에 null이 들어갈 수 없다. null이 들어갈 수도 있으면 자바에서 Optional을 써줬듯이 여기서도 표시를 해줘야 한다.

타윕뒤에 물음표를 붙이면 null이 가능하다는 것인데, Optional과 비슷하게 아예 다른 타입으로 취급을 한다.

safe call

str은 String?이 타입이므로 null일 수 있다. 따라서 바로 내장함수를 쓸 수 없다. safe call은 null이 아니면 실행하고, null이면 실행하지 않는다.

Elvis 연산자

null일 경우에 대체값을 주는 것이다.

이런식으로 자바의 orElseThrow()를 대체해서 사용할 수 있었다.

8.테스트 코드

Junit5가 아닌 kotest가 따로 있다. 이것도 시간될 때 조금씩 찾아보면서 써보자.
제이슨의 kotest

  • 테스트 코드에서 함수명을 백틱으로 감쌀 수 있다. 그럼 예전처럼 언더바로 띄어쓰기를 대체할 필요가 없어 편하다.

  • shouldThrow로 예외처리를 나타내줄 수도 있고 assertThrows도 있다.

  • 배열을 나타내는 것이 []로 바뀌었음에 따라 ValueSource에서도 바뀌었다.

마무리

아직 다루지 못한 문법들이 엄청 많지만 간단하게 프로그램들을 만들어보면서 필요한 위주로 학습을 해야할 것 같다. 또 스프링에서도 달라질 것들이 있을 것 같아 그것도 학습을 해보려 한다.

0개의 댓글