Chapters

Hide chapters

Kotlin Apprentice

Third Edition · Android 11 · Kotlin 1.4 · IntelliJ IDEA 2020.3

Before You Begin

Section 0: 4 chapters
Show chapters Hide chapters

Section III: Building Your Own Types

Section 3: 8 chapters
Show chapters Hide chapters

Section IV: Intermediate Topics

Section 4: 9 chapters
Show chapters Hide chapters

14. Methods
Written by Victoria Gonda

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

In the previous chapter, you learned about properties, which are constants and variables that are part of classes and objects. Methods, as you’ve already seen, are merely functions that reside inside a class or object.

In this chapter, you’ll take a closer look at methods. As with properties, you’ll begin to design more complex classes and objects. So, open the starter project and jump right in!

Method refresher

Consider ArrayList.removeAt(). It pops the item at a given index off an instance of an array list:

val numbers = arrayListOf(1, 2, 3)
numbers.removeAt(numbers.lastIndex)
println(numbers) // > [1, 2]

Methods like removeAt() help you control the data in the array list.

Comparing methods to getters and setters

With custom accessors, you saw in the last chapter that you could run code from inside a class within a property definition. That sounds a lot like a method. What’s the difference? It really comes down to a matter of style, but there are a few helpful thoughts to help you decide.

Turning a function into a method

To explore methods, you will create a simple model for dates called SimpleDate. Be aware that the various Kotlin platforms, such as the JVM and JS, contain production-ready Date classes that correctly handle many of the subtle intricacies of dealing with dates and times.

// 1
val months = arrayOf(
    "January", "February", "March",
    "April", "May", "June",
    "July", "August", "September",
    "October", "November", "December"
)

// 2
class SimpleDate1(var month: String)

// 3
fun monthsUntilWinterBreak(from: SimpleDate1): Int {
  return months.indexOf("December") - months.indexOf(from.month)
}
class SimpleDate2(var month: String) {
  fun monthsUntilWinterBreak(from: SimpleDate2): Int {
    return months.indexOf("December") - months.indexOf(from.month)
  }
}

val date2 = SimpleDate2("October")
println(date2.monthsUntilWinterBreak(date2)) // > 2
date.monthsUntilWinterBreak() // Error!

Introducing this

A class definition is like a blueprint, whereas an instance is a real object. To access the value of an instance, you use the keyword this inside the class.

// 1
fun monthsUntilWinterBreak(): Int {
  // 2
  return months.indexOf("December") - months.indexOf(this.month)
}
val date3 = SimpleDate3("September")
date3.monthsUntilWinterBreak() // 3
return months.indexOf("December") - months.indexOf(month)

Mini-exercise

Since monthsUntilWinterBreak() returns a single value and there’s not much calculation involved, transform the method into a property with a customer getter.

Object methods

Like classes, Kotlin objects defined with the object keyword can have member functions that refer to the object itself.

class MyMath {
  // 1
  companion object {
    fun factorial(number: Int): Int {
      // 2
      return (1..number).fold(1) { a, b -> a * b }
    }
  }
}

// 3
MyMath.factorial(6) // 720

Mini-exercise

Add a method to the MyMath class that calculates the n-th triangle number. It will be similar to the factorial formula, except instead of multiplying the numbers, you add them.

Extension methods

Sometimes you want to add functionality to a class but don’t want to muddy up the original definition. And sometimes you can’t add the functionality because you don’t have access to the source code. Just as for properties, it is possible to augment an existing class or object (even one you do not have the source code for) by adding methods to it.

fun SimpleDate.monthsUntilSummerBreak(): Int {
  val monthIndex = months.indexOf(month)
  return if (monthIndex in 0..months.indexOf("June")) {
    months.indexOf("June") - months.indexOf(month)
  } else if (monthIndex in
      months.indexOf("June")..months.indexOf("August")) {
    0
  } else {
    months.indexOf("June") + (12 - months.indexOf(month))
  }
}
val date = SimpleDate()
date.month = "December"
println(date.monthsUntilSummerBreak()) // > 6
fun Int.abs(): Int {
  return if (this < 0) -this else this
}

println(4.abs())    // > 4
println((-4).abs()) // > 4

Companion object extensions

If your class has a companion object, you can add extension methods to it by using the implicit companion object name Companion, or by using the custom name if the companion object has one.

fun MyMath.Companion.primeFactors(value: Int): List<Int> {
  // 1
  var remainingValue = value
  // 2
  var testFactor = 2
  val primes = mutableListOf<Int>()
  // 3
  while (testFactor * testFactor <= remainingValue) {
    if (remainingValue % testFactor == 0) {
      primes.add(testFactor)
      remainingValue /= testFactor
    } else {
      testFactor += 1
    }
  }

  if (remainingValue > 1) {
    primes.add(remainingValue)
  }

  return primes
}
MyMath.primeFactors(81) // [3, 3, 3, 3]

Challenges

As you work through these challenges, remember you can look at the solutions for this chapter at any time for a hint or to check your work.

import kotlin.math.PI

class Circle(var radius: Double = 0.0) {
 val area: Double
   get() {
     return PI * radius * radius
   }
}
val months = arrayOf(
   "January", "February", "March",
   "April", "May", "June",
   "July", "August", "September",
   "October", "November", "December"
)

class SimpleDate(var month: String, var day: Int = 0) {
 fun advance() {
   day += 1
 }
}

var date = SimpleDate(month = "December", day = 31)
date.advance()
date.month // December; should be January!
date.day // 32; should be 1!

Key points

  • Methods are behaviors that extend the functionality of a class.
  • A typical method is a function defined inside of a class or object.
  • A method can access the value of an instance by using the keyword this.
  • Companion object methods add behavior to a class instead of the instances of that class. To define a companion object method, you add a function in the class companion object block.
  • You can augment an existing class definition and add methods to it using extension methods.

Where to go from here?

Methods and properties are the things that make up your classes, instances, and objects. Learning about them as you have these last two chapters is important since you’ll use them all the time in Kotlin.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2024 Kodeco Inc.

You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now