137

In Java, for example, I can write getters on my own (generated by IDE) or use Annotations like @Getter in lombok - which was pretty simple.

Kotlin however has getters and setters by default. But I can't understand how to use them.

I want to make it, lets say - similar to Java:

private val isEmpty: String
        get() = this.toString() //making this thing public rises an error: Getter visibility must be the same as property visibility.

So how do getters work?

Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
nutella_eater
  • 3,393
  • 3
  • 27
  • 46

8 Answers8

213

Getters and setters are auto-generated in Kotlin. If you write:

val isEmpty: Boolean

It is equal to the following Java code:

private final Boolean isEmpty;

public Boolean isEmpty() {
    return isEmpty;
}

In your case the private access modifier is redundant - isEmpty is private by default and can be accessed only by a getter. When you try to get your object's isEmpty property you call the get method in real. For more understanding of getters/setters in Kotlin: the two code samples below are equal:

var someProperty: String = "defaultValue"

and

var someProperty: String = "defaultValue"
    get() = field
    set(value) { field = value }

Also I want to point out that this in a getter is not your property - it's the class instance. If you want to get access to the field's value in a getter or setter you can use the reserved word field for it:

val isEmpty: Boolean
  get() = field

If you only want to have a get method in public access - you can write this code:

var isEmpty: Boolean
    private set 

due to the private modifier near the set accessor you can set this value only in methods inside your object.

succcubbus
  • 874
  • 1
  • 7
  • 24
Cortwave
  • 4,747
  • 2
  • 25
  • 42
  • 34
    `In your case the private access modifier is redundant` How? Kotlin doc's say default modifier is public. https://kotlinlang.org/docs/reference/visibility-modifiers.html –  May 24 '17 at 20:33
  • @Nothing yes it seems like public field, but under hood you call getter method – Cortwave May 24 '17 at 22:02
  • The `val isEmpty: Boolean` will not compile as isEmpty is not yet initialized, right? Just starting to learn Kotlin. Also, what is happening with `get() = field`? – Shubham A. Sep 30 '17 at 13:19
  • great explanation, imho the Kotlin docs are hard to understand unless you're already familiar with the language... – Jason Jul 29 '20 at 15:21
  • Why doesn't Kotlin make use of private modifiers more often. Seems to be like all libraries' variables are public. – Yash Jain Aug 27 '20 at 19:06
  • What about if you want to use an observable with a private setter? ie: so you can perform some reactive logic when the value is set? – Marchy Sep 28 '20 at 19:34
  • This is not equal to the code you mentioned. The generated getter/setter are final, which makes difference in the case when accessors get overridden in the extended proxy class. E.g. Hibernate uses this approach a lot. – aleksey.stukalov May 19 '21 at 11:13
  • downvote for object wrapper `Boolean` in Java, it should be primitive `boolean` (unless nullable, of course) – Ievgen Lukash Jan 28 '23 at 01:09
36

The rules about property accessors visibility modifiers are the following:

  • Getter visibility of var and val property should be exactly the same to the visibility of the property, thus you can only explicitly duplicate the property modifier, but it is redundant:

    protected val x: Int
        protected get() = 0 // No need in `protected` here.
    
  • Setter visibility of var property should be the same or less permissive than the property visibility:

    protected var x: Int
        get() = 0
        private set(x: Int) { } // Only `private` and `protected` are allowed.
    

In Kotlin, properties are always accessed through getter and setter, thus there's no need in making a property private with public accessors like in Java -- its backing field (if present) is already private. So, visibility modifiers on property accessors are only used to make setter visibility less permissive:

  • For a property with backing field and default accessors:

    var x = 0 // `public` by default
        private set
    
  • For a property without backing field:

    var x: Int // `public` by default
        get() = 0
        protected set(value: Int) { }
    
hotkey
  • 140,743
  • 39
  • 371
  • 326
  • Can one set and get different types ? Setting `x` equal to some `"Some String"` and returning say the length, `11`, of the string ? – Carel Feb 01 '19 at 13:09
  • @Carel, no, as of now, this use case is not supported: the accessors of a property should operate with exactly the type of the property. Using a different type is covered by using a [separate backing property](https://kotlinlang.org/docs/reference/properties.html#backing-properties) – hotkey Feb 01 '19 at 14:16
  • Darn, Kotlin is so very close to Python that you think it'll just work when you get reminded it's typed... and cut your own throat. – Carel Feb 01 '19 at 15:42
  • Thanks for access modifiers. I removed `private` from a variable, and it became accessible from another class with getter. – CoolMind Mar 27 '19 at 07:21
  • I get a "Private setters are not allowed for open properties" when using the "var x//private set" combination. Resolved by declaring as "final var x" – Tom Oct 11 '19 at 07:39
27

1) Example default setter and getter for property firstName in Kotlin

class Person {
    var firstName: String = ""
            get() = field       // field here ~ `this.firstName` in Java or normally `_firstName` is C#
            set(value) {
                field = value
            }

}

Using

val p = Person()
p.firstName = "A"  // access setter
println(p.firstName) // access getter (output:A)

IF your setter or getter is exactly same above, you can remove it because it is unnecessary

2) Example custom setter and getter.

const val PREFIX = "[ABC]"

class Person {

    // set: if value set to first name have length < 1 => throw error else add prefix "ABC" to the name
    // get: if name is not empty -> trim for remove whitespace and add '.' else return default name
    var lastName: String = ""
        get() {
            if (!field.isEmpty()) {
                return field.trim() + "."
            }
            return field
        }
        set(value) {
            if (value.length > 1) {
                field = PREFIX + value
            } else {
                throw IllegalArgumentException("Last name too short")
            }
        }
}

Using

val p = Person()
p.lastName = "DE         " // input with many white space
println(p.lastName)  // output:[ABC]DE.
p.lastName = "D" // IllegalArgumentException since name length < 1

More
I start learn Kotlin from Java so I am confusing about field and property because in Java there is no property.
After some search, I see field and property in Kotlin look like C# (What is the difference between a field and a property?)

Here is some relevant post which talk about field and property in Java and Kotlin.
does java have something similar to C# properties?
https://blog.kotlin-academy.com/kotlin-programmer-dictionary-field-vs-property-30ab7ef70531

Correct me if I am wrong. Hope it help

Linh
  • 57,942
  • 23
  • 262
  • 279
10

Getter in kotlin is by default public, but you can set the setter to private and set the value by using one method inside a class. Like this.

/**
* Created by leo on 17/06/17.*/

package foo
class Person() {
var name: String = "defaultValue"
               private set

fun foo(bar: String) {
    name = bar // name can be set here
       }
}

fun main(args: Array<String>) {
  var p = Person()
  println("Name of the person is ${p.name}")
  p.foo("Jhon Doe")
  println("Name of the person is ${p.name}")
}
Lalit Behera
  • 534
  • 8
  • 18
9

If you have a Var then you can:

var property: String = "defVal"
              get() = field
              set(value) { field = value }

But in the case of Val, you can not set it once assigned, so there won't be a setter block:

val property: String = "defVal"
              get() = field

or if you don't want setter then:

val property: String = "defVal"
              private set
Ali Nawaz
  • 2,016
  • 20
  • 30
  • Be careful when converting from Java to Kotlin as the AI engine will often move the setter and getter of Java a variable to its own function in Kotlin, such as getProperty(). This will cause all sorts of bugs. You need to implement the solution posted by Ali. – Michael N Dec 13 '21 at 10:25
6

You can see this tutorial for more info:

Yet Another Kotlin Tutorial for Android Developers

Properties

In Kotlin world, classes cannot have fields, just properties. var keyword tells us the property is mutable, in contrast to val. Let’s see an example:

class Contact(var number: String) {

   var firstName: String? = null
   var lastName: String? = null
   private val hasPrefix : Boolean
       get() = number.startsWith("+")

}

There is not much code, but lots of things are happening behind the scenes. We will go through it step by step. First of all, we created a public final class Contact.

This is the primary rule we have to face: if not specified otherwise, classes are public and final by default (by the way, the same is for class methods). If you want to inherit from class, mark it with open keyword.

Pluto65
  • 188
  • 3
  • 15
0

Here's a practical, real world example of a Kotlin getter and setter (See more details here):

// Custom Getter
val friendlyDescription get(): String {
    val isNeighborhood = district != null
    var description = if (isNeighborhood) "Neighborhood" else "City"
    description += " in"
    if (isNeighborhood) {
        description += " $city,"
    }
    province?.let {
        if (it.isNotEmpty()) {
            description += " $it,"
        }
    }
    description += " $country"
    return description
}

print(myLocation.friendlyDescription) // "Neighborhood in Denver, Colorado, United States"


// Custom Setter
enum class SearchResultType {
    HISTORY, SAVED, BASIC
}

private lateinit var resultTypeString: String

var resultType: SearchResultType
    get() {
        return enumValueOf(resultTypeString)
    }
    set(value) {
        resultTypeString = value.toString()
    }

result.resultType = SearchResultType.HISTORY
print(result.resultTypeString) // "HISTORY"

Ricky Padilla
  • 226
  • 5
  • 7
0

A bit disagree with @Cortwave top answer. Kotlin member fields by default are final, not private. You have to write private modifier to make it encapsulated within the class.

The answer I was looking for here is does kotlin autogenerate getters and setters for private member fields or you have to do it on your own? Straightforward implementation in Android Studio shows you need to write it by yourself.

Joe Dow
  • 583
  • 1
  • 3
  • 12