kotlin Getters/Setterss에 대해서 정리합니다.

코틀린 문서 properties 부분에 정리되어 있는 Getters and Setters의 내용을 참고하시면 되겠습니다.


Getters/Setters

Getters/Setters을 java에서는 직접 구현해야 합니다.

annotations을 이용하여 get/set을 자동으로 생성할 수도 있지만 과거 Android에서는 성능 이슈로 클래스에 대한 get/set을 만들지 않는 것을 권장하였습니다.(현재는 큰 차이가 없습니다.)

그래서 아래와 같이 작성합니다.

class User {
  public String name;
  public String age;
}

위와 같이 public 변수를 선언해서 직접 접근하고, 이를 get/set을 처리합니다.

또는 아래와 같이 get/set을 직접 구현합니다.

class User {
  private String name;
  private String age;

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public String getAge() {
    return age;
  }

  public void setAge(String age) {
    this.age = age;
  }
}

이를 통해 캡슐화(encapsulation)를 구현하고, 값에 대한 validation을 처리할 수 있습니다.

코틀린에서도 이를 제공합니다. kotlin에서 사용할 때와 java에서 사용할 때는 kotlin 클래스의 접근 방법은 조금 다릅니다.

예를 들면 다음의 kotlin data class를 생성하고,

data class User(var name: String, val age: String)

java에서는 get/set을 자동으로 만들어주기 때문에 다음과 같이 User 클래스를 생성하고, get/set을 통해서 접근 가능합니다.

class Sample {

  public void test() {
    User user = new User("name", "age");
    user.setName("name");
    user.getName();
    user.getAge();
  }
}

코틀린에서는 get/set이 아닌 직접 접근 방법으로 접근합니다.

class Sample {
  fun test() {
    val user = User("name", "age")
    user.name = "name" // 설정
    user.name // 출력
    user.age // 출력
  }
}


Kotlin에서의 data class 장점

  • equals()/hashCode() 생성
  • toString() : “User(name=John, age=42)” 출력
  • componentN() functions 아래와 같이 componentN을 통해서 접근이 가능하며,
val name = person.component1()
val age = person.component2()

또는 다음과 같이 a/b 변수 선언으로 처리도 가능합니다.

for ((a, b) in collection) { ... }
  • copy() function


Getters and Setters

var 타입의 원형은 아래와 같습니다.

propertyName: type = default 값으로 구성되고, getter/setter을 추가할 수 있습니다.

var <propertyName>: <PropertyType> [= <property_initializer>]
    [<getter>]
    [<setter>]

getter/setter을 각각 구성할 수 있는데 먼저 java에서는 다음과 같이 구성할 수 있습니다.

미리 validation을 통해 검증을 하고, 안전하게 처리할 수 있습니다.

class Test {
  private String name;

  public void setName(String name) {
    if (TextUtils.ieEmpty(name) == false) {
      this.name = name;
    } else {
      this.name = "";
    }
  }

  public String getName() {
    return TextUtils.isEmpty(name) == false ? name : "";
  }
}

이를 코틀린에서는 아래와 같이 처리할 수 있습니다.

별도의 get/set 메소드를 생성하는 것이 아닌 선언과 동시에 값을 validation 하고, 이에 따른 결과를 처리할 수 있습니다.

class Test {
var name: String = ""
  get() = if (field.length > 0) field else "name"
  set (value) {
      if (value.length > 0) field = value else ""
  }
}


Backing Fields

위에서 적은 field는 Backing Fields라고 합니다. 바로 위와 같이 정리하였듯 validation을 처리해야 하는 경우가 발생합니다.

이때 위와 같이 Backing field를 이용하여 처리함으로 값에 대한 validation 후 값을 초기화하거나, return 할 수 있습니다.

class Test {
  var count: Int = 0
    set(value) {
      if (value > 0) {
        field = value
      }
    }
}

위의 코드는 count에 set 한 값이 0 보다 큰 경우를 체크합니다.


private 변수 만들기

예를 들면 변수를 설정할 때는 private으로 정의하고, 읽을 때는 public으로 정의해야 하는 경우가 있습니다.

이럴 경우에는 java에서는 아래와 같이 할 수 있습니다.

class Test {
  private String name = "userName";

  public String getName() {
    return name;
  }
}

위와 같이 클래스 내부에서만 초기화할 수 있고, 외부에서는 초기화할 수 없어야 하는 경우에는 java에서는 위와 같이 할 수 있습니다.

이를 kotlin으로 작업하면 다음과 같이 간단한 코드로 초기화 가능합니다.

class Test {
  var name: String = "userName"
    private set()
}

private set()으로 간단하게 초기화가 가능하고, 이 변수는 내부에서는 접근이 불가능한 private setters를 가집니다.


Custom getters/setters

변수이지만 함수 자체로서의 getter/setter도 정의할 수 있습니다.

java에서는 별도의 함수를 정의해서 특정 값의 boolean을 체크하거나, size를 체크하거나 하지만

public class Test {
  private int count = 0;

  public boolean isEmpty() {
    return count == 0;
  }
}

kotlin에서는 간단하게 아래와 같이 특정 변수의 크기를 확인할 수 있습니다.

class Test {
  var count = 0
  var isEmpty: Boolean
    get() = this.count == 0
}

get()을 통해서 Test 클래스의 count를 체크하고, boolean을 리턴하게 됩니다.

또는 setters를 통해 다른 값을 초기화할 수도 있습니다.

class Test {
  var name: String = ""
  var userName: String
    set (value) {
      updateName(name)
    }

  fun updateName(name: String) {
    // 생략
  }
}


마무리

커스텀 getter/setters의 경우는 SAM conversions 또는 higher-order-functions을 구현해볼 수도 있습니다.

기존 글에서 다루었던 lateinit은 getter/setter와 함께 사용하지 못합니다. validation을 적용해야 한다면 lateinit 없이 사용하거나 Custom gatter/setter을 사용할 수 있습니다.


kotlin 관련 글 더 보기


Tae-hwan

Android, Kotlin .. Create a content development.