From Java to Kotlin - Data Types, String Templates & Casting

Number Types

The built-in number types are as follows

Type Bytes
Long 64 bytes
Double 64 bytes
Int 32 bytes
Float 32 bytes
Short 16 bytes
Byte 8 bytes

The conversion methods are toByte() toShort() toInt() toLong() toFloat() toDouble() toChar()

// how to convert between types
fun main(args: Array<String>) {
    val minutesInYear: Double = (60*24*365).toDouble()

    val input = Scanner(System.`in`)
    print("Input the number of minutes: ")
    val min = input.nextDouble().toInt()

    val years = (min / minutesInYear.toLong())
    val days = (min / 60.0 / 24.0).toInt() % 365

    println("$min mins is approx $years years and $days days")
}

Strings and String Templates

Strings are immutable in Kotlin. There’re two types of String literals

Escaped String

Created using double "" quotes. Special chars such as new line must be escaped.

val string = "string with \n new line"
Raw String

Created by a triple quote """. Contains no escaping and can contain newlines and any other characters.

val test = """
	for (c in "foo")
	  print(c) """

String templates

They’re for embedding values, variables or expressions inside a string, without string concatenation.

val name = "Sam"
val str = "hello $name"

Methods can be embedded by prefixing with a dollar $ and wrapping in braces {}

val name = "Sam"
val str = "hello $name. Your name has ${name.length} characters"

You can also use string templates in multiline Strings.

Any

Any is the supertype of all non-nullable types. It cannot contain a null value. It’s similar to java.lang.Object.

// this performs automatic boxing
val answer: Any = 42

If you need a variable that can hold any possible value, including null, you must use Any?

Unit Type (Java’s void)

It can be used as a return type of a function that has nothing to return. It does not have to be explicitly declared.

Unlike in Java, where void just indicates that the method doesn’t return anything at all, in Kotlin Unit actually returns something, and this something is nothing. You’re literally returning nothing. Also, unlike void, it can be used as a type argument.

Unit is also useful when you override a function that returns a generic parameter and you want to make it return nothing.

// this requires to return a generic 'T'
interface Processor {
  fun process(): T
}

// as Unit is a type and it returns something
//    we may use it to implement the previous
//    method and don't return anything.
class NoResultProcessor : Processor {
  override fun process() {
    // do stuff
  }
}

The Nothing Type (never returns)

Nothing has no type. You can use it to mark a function that never returns successfully. It helps optimize the compiler.

For example, if you have a function like an eternal for loop or a function that always throws an Exception. It’s never going to return data. There’s no reason to have that function identified as returning something. Even the Unit type.

There’re no instances of nothing. It’s defined as a type but can never be instantiated.

fun fail(message: String): Nothing {
  throw IllegalArgumentException(message)
}

Functions returning Nothing can be used on the right side of the Elvis operator to perform precondition checking (you don’t have to check for null).

val s = person.name ?: fail("Name required")
println(s) // 's' is known to be initialized at this point.

Explicit Casts and Smart Casts

You can check whether a variable is of a certain type by using an is check. This is the same as an instanceof in Java.

// casting in java
if(a instanceof ObjectB) {
  ObjectB myObject = (ObjectB) a;
}

In Kotlin you don’t need to do this. The compiler does it for you.

Smart Cast

If you check the variable for a certain type, you don’t need to cast it afterwards. You can use it as having the type you checked for previously

fun printStringLength(any: Any) {
  if (any is String) {
    // we can access methods from String class
    //    without a manual cast.
    println(any.length)
  }
}

Smart casts can only be used on objects or variables that the compiler can guarantee has not changed between the time when the variable is checked and the time when it’s used.

var fields and local vars that have been closed over and mutated cannot be used in smart casts.

Explicit Casting

To cast a reference explicitly we use the as operator. This operation will throw a ClassCastException if the cast cannot be performed legally.

fun length(any: Any): Int {
  val string = any as String
  return string.length
}

The null value cannot be cast to a type that’s not defined as nullable.

To cast to a value that can be null, declare the required type as nullable

val string: String? = any as String