Kotlin Basics

July 19, 2020

kotlin

Hello World!

The very begginig will always be the “Hello World!” example.

fun com.josias.kotlin.basics.main() {
    println("Hello World!")
}

Kotlin is a strongly typed language, but one of the advantages we can found is the ability to do ”type inference”, it is necessary to always declare types explicitly. The compiler will take care of this.

val & var

var is a mutable variable, can be changed to another value later by reassigning it.

val is a read-only variable (like final variable in Java)

val name = "Kotlin"
println(name)

//  var can be initialized later
var anotherName: String
anotherName = "Kotlin var initialized later"
println(anotherName)

// Val MUST be initialized when it is created, it cannot be changed later.
val nameFinal = "Hello Kotlin World!"
println(nameFinal)

Classes & Objects

package com.josias.kotlin.foo

/**
 * Foo class to show how to use classes and objects is Kotlin
 */
class Foo {
    // property (data member)
    private var isOn: Boolean = false

    // member function
    fun turnOn() {
        isOn = true
    }

    // member function
    fun turnOff() {
        isOn = false
    }

    fun displayLightStatus(lamp: String) {
        if (isOn == true)
            println("$lamp lamp is on.")
        else
            println("$lamp lamp is off.")
    }
}

fun com.josias.kotlin.basics.main(args: Array<String>) {
    val l1 = Foo() // create l1 object of Lamp class
    val l2 = Foo() // create l2 object of Lamp class
    l1.turnOn()
    l2.turnOff()
    l1.displayLightStatus("l1")
    l2.displayLightStatus("l2")
}

The output should be:

> l1 lamp is on.
> l2 lamp is off.

Visibility Modifiers

Not all functions or classes are part of a public API. Some parts of the code are being required to be marked as internal and not accessible from outside of the class or package. They keywords to specify this behavior is called visibility modifier.

There are four modifiers:

  • public
  • internal
  • protected
  • private

public is the default if modifier is not provided.

private

Accessed only from the same file. Any private function or property is only visible to other members of the same class, interface, or object:

class Person { 
  private fun age(): Int = 21 
}

internal

Internal deals with the concept of a module. A module is defined as a Maven or Gradle module or an IntelliJ module. Any code that is marked as internal is visible from other classes and functions inside the same module. Effectively, internal acts as public to a module, rather than public to the universe:

internal class Person { 
  fun age(): Int = 21 
}

protected

Top-level functions, classes, interfaces, and objects cannot be declared as protected. Any functions or properties declared as protected inside a class or interface are visible only to members of that class or interface, as well as subclasses.

NULLABILITY - Null syntax

Unfortunately, we have to live with null references as they are present in the JVM, but Kotlin introduces some functionality to make it easier to avoid some common mistakes.

Kotlin requires that a variable that can assigned to null be declared with a ?:

var str: String? = null

Object Oriented

Kotlin is a object-oriented programming language with support for higher-order functions and lambdas.

  • Everything is an object: An object is nothing but a block of memory allocated and configured according to a design/definition. From the problem space you have to solve, you take all the logical entities and translate them into objects in your program.
  • Objects communicate by sending and receiving messages (in terms of objects): Your program will be a set of objects performing different actions as a result of calling methods that each one expose.
  • Objects have their own memory (in terms of objects): This should be read as, You can create an object by composing other objects.
  • Every object is an instance of a class (which must be an object): Think of a class as a blueprint specifying what the type can do.
  • The class holds the shared behavior for its instances (in the form of objects in a program list): This means all the objects of a particular type can receive the same messages; in other words, they expose the same methods.

Classes

A class is a blueprint for creating objects (a particular data structure), providing initial values for state (member variables or attributes), and implementations of behavior (member functions or methods). Classes are declared by using the class keyword

class Foo {
 // class body where the behavior and data are defined: fields, properties, and methods.
// An empty constructor is generated by the compiler automatically
}

Kotlin allows to declare multiple classes within the same source file.

package com.josias.kotlin.foo

class Person
constructor(val firstName: String, val lastName: String, val age: Int?) {}

fun com.josias.kotlin.basics.main(args: Array<String>) {
    val person1 = Person("Axl", "Rose", 29)
    val person2 = Person("Foo", "Bar", null)
    println("${person1.firstName}, ${person1.lastName} is  ${person1.age} years old")
    println("${person2.firstName}, ${person2.lastName} is  ${person2.age?.toString() ?: "?"} years old")
}

In the example above, a constructor is provided and the ouput is similar to:

> Axl, Rose is  29 years old
> Foo, Bar is  ? years old

Data Classes

It happens quite often we need to define classes for the sole purpose of holding data.

data class Customer(val id:Int, val name:String, var  address:String)

Enum Classes

Enumeration is a specific type of class; a variable of a given enum type is limited to a set of predefined constants: the ones that have been defined by the type. To define an enumeration, you could use the enum class keywords, as in the following example where we create a type for all the days in a week:

enum class Day { MONDAY, TUESDAY, WEDNESDAY, THURSDAY,  FRIDAY, SATURDAY, SUNDAY }

enumeration types can inherit an interface and implement it anonymously for each enum value.

interface Printable { 
  fun print(): Unit 
}

public enum class Word : Printable { 
  HELLO { 
    override fun print() { 
      println("Word is HELLO") 
    } 
  }, 
  BYE { 
    override fun print() { 
      println("Word is BYE") 
    } 
  } 
} 

val w= Word.HELLO 
w.print()

Static methods and companion objects

fun showFirstCharacter(input: String): Char {
    if (input.isEmpty()) throw IllegalArgumentException()
    return input.first()
}

Interfaces

An interface is nothing more than a contract; it contains definitions for a set of related functionalities. Interfaces in Kotlin can contain declarations of abstract methods, as well as method implementations. What makes them different from abstract classes is that interfaces cannot store state. They can have properties but these need to be abstract or to provide accessor implementations.

interface Document { 
  val version: Long   
  val size: Long 

  val name: String     
  get() = "NoName" 

  fun save(input: InputStream) 
  fun load(stream: OutputStream) 
  fun getDescription(): String { 
     return "Document $name has $size byte(-s)"} 
} 

Inheritance

All classes in Kotlin have a common superclass Any, that is the default superclass for a class with no supertypes declared:

class Example // Implicitly inherits from Any

Any has three methods: equals(), hashCode() and toString(). Thus, they are defined for all Kotlin classes.

Visibility modifiers

When you define your class, the contained methods, properties, or fields can have various visibility levels. In Kotlin, there are four possible values:

  • Public: This can be accessed from anywhere
  • Internal: This can only be accessed from the module code
  • Protected: This can only be accessed from the class defining it and any derived classes
  • Private: This can only be accessed from the scope of the class defining it

If the parent class specifies that a given field is open for being redefined (overwritten), the derived class will be able to modify the visibility level. Here is an example:

open class Container { 
  protected open val fieldA: String = "Some value" 
} 
class DerivedContainer : Container() { 
  public override val fieldA: String = "Something else" 
} 

Abstract classes

Adding the abstract keyword in front of the class definition will mark the class as abstract. An abstract class is a partially defined class; properties and methods that have no implementation must be implemented in a derived class, unless the derived class is meant to be an abstract class as well. Here is how you would define an abstract class in Kotlin:

abstract class A { 
  abstract fun doSomething() 
}

Unlike interfaces, you have to mark the function abstract if you don’t provide a body definition.