Kotlin Console Password

The Console object has a readPassword() method that disables echoing and allows a user to enter a password blindly. The password is returned as a character array. Here is an example of how to use the Console class to request a password from the user.

import java.io.Console

fun main(args : Array<String>){
    //Best to declare Console as a nullable type since System.console() may return null
    val console : Console? = System.console()

    when (console){
        //In this case, the JVM is not connected to the console so we need to exit
        null -> {
            println("Not connected to console. Exiting")
            System.exit(-1)
        }
        //Otherwise we can proceed normally
        else -> {
            val userName = console.readLine("Enter your user name => ")
            val pw = console.readPassword("Enter your password => ")

            println("Access Granted for $userName")

            //This is important! We don't know when the character array
            //will get garbage collected and we don't want it to sit around
            //in memory holding the password. We can't control when the array
            //gets garbage collected, but we can overwrite the password with
            //blank spaces so that it doesn't hold the password.
            for (i in 0 until pw.size){
                pw[i] = ' '
            }
        }
    }
}

We begin by getting a reference to the console. Since there is a possibility that System.console() can return null, it’s a best practice to declare console as a nullable type so that we have Kotlin compiler safety. After getting a reference to the console, we can use the when() function to react to the null case or continue with the program.

The call to readPassword (line 16) isn’t very dramatic. The program uses the overloaded version to prompt the user for a password and return the password as a character array. In terms of security, it’s important to never hold a password as a String. That’s why the readPassword() method returns a character array.

Strings are immutable. That means we can never change the value of the String. Furthermore, we never know when the JVM will garbage collect an object. Those two facts make for dangerous circumstances because a String holding a password can sit in memory for an unknown amount of time. Should someone break past the security constraints of the JVM and gain access to the program’s memory, there is the potential they could steal a password.

Character arrays also get garbage collected at unknown times. The difference between the character array and a String is that we can overwrite each element in the array. The example program demonstrates this on lines 25-27 by overwriting each element of the pw array with a blank space. Should someone break into the program’s memory, all they will see is a character array of empty spaces. The operation of converting a password character array to empty spaces should be completed as soon as password validation is finished.

Kotlin Console Object

The System.console() method provides an access point for the Console object, which is used to read input from a character input device like the keyboard and prints to character display device like the screen’s display. If the JVM is started indirectly or as a background process, the method will return null. The Console object is useful when creating CLI applications.

The class provides a way to both read character input and write character output. Keep in mind that character output may be less important than input. Kotlin already provides its own print() and println() functions for writing to the standard out. The console class does make it easy to read input from the keyboad since we do not need to work about working with System.in directly.

Let’s take a look at an example where we simply echo what’s inputted to the keyboard.

import java.io.Console

fun main(args : Array<String>){
    val console : Console? = System.console()
    when (console){
        null -> {
            println("Running from an IDE...")
        }
        else -> {
            while (true){
                //Read a line from the keyboard
                val line = console.readLine("What does Bob say? ")
                if (line == "q"){
                    return
                }
                console.printf("Bob says: %s\n", line)
            }
        }
    }
}

The program is really simple. We make a console variable, that is nullable. This step is critical because System.console() can return null. Our next operation is to check if the console object is null. When console is null, we exit the program. Otherwise, we enter a loop that continues until the user enters “q” to quit.

The console.readLine() method returns a line inputted from the keyboard. In other words, it will return everything typed until the user pressed the enter or return key. To print the output, we use printf() to print a formatted output.
We could have used Kotlin’s print() function also.

Common Console Methods

reader() : Reader

This method returns a Reader object reference that can be used for low-level read operations.

writer() : PrintWriter

Returns a PrintWriter object reference that can be used for low-level output operations.

readLine() : String

Returns a line of text inputed from the console. The overloaded version accepts a String that serves as a command prompt.

readPassword() : CharArray!

This method disablese echoing so that a user can type a password in private. The overloaded version takes a String that is used as a command prompt.

format(fmt : String, varArgs args : Any) : Console

This method writes the format string an it’s argments to the output.

printf(fmt : String, varArgs args : Any) : Console

Does same thing as format.

flush() : void

This method flushes the buffer and forces all output to be written immediately.

References

See https://docs.oracle.com/javase/8/docs/api/java/io/Console.html

Kotlin Command Line Compile

Once in a great while, it’s necessary to compile and run a Kotlin program from the terminal. Here is how to do it.

Mac

Install homebrew first. Then open the Mac terminal and type the following commands.

brew update
brew install kotlin

This will install the necessary command-line applications to compile a Kotlin program.

Next, open your terminal and navigate to the folder that holds your Kotlin file. Kotlin source files have the extension .kt. Assuming your file is belcher.kt, you would type

kotlinc belcher.kt -include-runtime -d belcher.jar

to compile the source file. You will get a jar file in the same folder. The program can be run with

java -jar belcher.jar

Windows (Cygwin) or WSL

Open your Cygwin or WSL terminal and type

curl -s https://get.skdman.io | bash
sdk install kotlin

This will install the necessary command-line applications to compile a Kotlin program.

Next, open your terminal and navigate to the folder that holds your Kotlin file. Kotlin source files have the extension .kt. Assuming your file is belcher.kt, you would type

kotlinc belcher.kt -include-runtime -d belcher.jar

to compile the source file. You will get a jar file in the same folder. The program can be run with

java -jar belcher.jar

More Information

More information can be found at http://kotlinlang.org/docs/tutorials/command-line.html

Kotlin String Formatting

String formatting allows developers to define a common string template and then interchange values as needed.

String Templates

Kotlin has a feature known as String Templates that allow you specify a string and then reference variables as required.

var good = "good"
var great = "great"

var templateGood = "Bob is a $good chef"
var templateGreat = "Bob is a $great chef"

In the above example, the value of the variable good is inserted at $good in the templateGood string. Likewise, the value of the variable great is inserted at $great in the templateGreat string.

We are also free to do evaluations.

var plus = "Eagerly awaiting ${1 + 2}"

The 1 + 2 will add to 3 and the result will be “Eagerly awaiting 3”

String.format()

The String class has a format method that takes in a format string and then any number of arguments. The number of arguments must match the same number of format specifiers in the string or an exception will get raised.

To begin, the format string takes the form of “[flags][width][.precision]type” so for example.

val simple = "%d" //very basic
val medium = "Have a nice %s" //More complex
val advanced = "%-2s\t%s"

The first example, simple, only has the type, %d. The same is true with the second String, which only has %s. The final example, has a left-justified flag “-“, followed by the width of two characters (2), and its type, String.

Type Specifiers

Here is a list of the type specifiers and their meanings.

%b Boolean
%c Character
%d Signed Integer
%e Float in Scientific Notation
%f Float in Decimal Format
%g Float in Decimal or Scientific Notation, depending on value
%h Hashcode of the supplied argument
%n Line separator
%o Octal Integer
%s String
%t Date or Time
%x Hexadecimal Integer

Here is an example of how to use the String.format() method.

var formatTemplate = "%-2s\t%s"
println(formatTemplate.format("%b", "Boolean") //prints %b	Boolean

Putting it Together

Here is an example program that shows off String templates.

fun main(args : Array<String>){
    var good = "good"
    var great = "great"

    println("Using Kotlin String templates")
    var templateGood = "Bob is a $good chef"
    var templateGreat = "Bob is a $great chef"

    println(templateGood)
    println(templateGreat)

    var formatTemplate = "%-2s\t%s"
    var func = {pair : Pair<String, String> -> println(formatTemplate.format(pair.first, pair.second))}

    var table = arrayOf(
            "%b" to "Boolean",
            "%c" to "Character",
            "%d" to "Signed Integer",
            "%e" to "Float in scientific format",
            "%f" to "Float in decimal format",
            "%g" to "Float in either decimal or scientific notation based on value",
            "%h" to "Hashcode of argument",
            "%n" to "Line separator",
            "%o" to "Octal Integer",
            "%s" to "String",
            "%t" to "Date or Time",
            "%x" to "Hexadecimal Integer")

    println("\n%[flags][width][.precision]type")

    println("\nFormatting Symbols")
    table.forEach(func)
}

Output

Using Kotlin String templates
Bob is a good chef
Bob is a great chef

%[flags][width][.precision]type

Formatting Symbols
%b	Boolean
%c	Character
%d	Signed Integer
%e	Float in scientific format
%f	Float in decimal format
%g	Float in either decimal or scientific notation based on value
%h	Hashcode of argument
%n	Line separator
%o	Octal Integer
%s	String
%t	Date or Time
%x	Hexadecimal Integer

Kotlin Regex Pattern Matching

Matching Strings using regular expressions (REGEX) is a difficult topic. Regex strings are often difficult to understand and debug. They often require extensive testing to make sure that the regex is matching what it is supposed to match.

Kotlin goes out of its way to avoid making developers use regex. For example, the split() method of String does not require a regex (unlike its Java counterpart). Doing so reduces bugs and helps keep the code more readable in general. When we need to use a regex, Kotlin has an explicit Regex type.

One advantage of having a regex type is that code is immediately more readable.

val regex = """\d{5}""".toRegex()

Notice a few things about this String. First, we use the triple quoted, or raw, string to define the regular expression. This helps us avoid bugs caused by improper escaping of the regex string. Also, the string has a toRegex() method that converts the String to a Regex object.

The Regex object comes packed with its own methods that are used for pattern matching.

regex.containsMatchIn("My string 00000")
regex.findAll("00000, 000121, 23213")

Of course there are many other methods found on the Regex object, but see the Kotlin documentation for more details: http://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/-regex/index.html

Regex Tables

Below are some common regex symbols, meta symbols, and quantifiers as presented in Oracle Certified Professional Java SE 7 Programmer Exams 1Z0-804 and 1Z0-805 A Comprehensive OCPJP 7 Certification Guide by Ganesh and Sharma.

Common Symbols

Matches either x or y
Symbol Meaning
^expr Matches expr at beginning of the line
expr$ Matches expr at end of line
. Matches any single character (exception the newline character)
[xyz] Matches either x, y, or z
[p-z] Matches either any character from p to z or any digit from 1 to 9
[^p-z] ‘^’ as the first character negates the pattern. This will match anything outside of the range p-z
xy Matches x followed by y
x|y

Common Meta Symbols

\d Matches digits ([0-9])
\D Matches non-digits
\w Matches word characters
\W Matches non-word characters
\s Matches whitespaces [\t\r\f\n]
\S Matches non-whitespaces
\b Matches word boundary when outside of a bracket. Matches backslash when placed in a bracket
\B Matches non-word boundary
\A Matches beginning of string
\Z Matches end of String

Common Quantifiers

expr? Matches 0 or 1 occurrence of expr (expr{0,1})
expr* Matches 0 or more occurrences of expr (expr{0,})
expr+ Matches 1 or more occurrences of expr (expr{1,})
expr{x, y} Matches between x and y occurrences of expr
expr{x, } Matches x or more occurrences of expr

Putting it Together

Here is an example program that uses Regex in Kotlin.

fun main(args : Array<String>){
    val symbols = mapOf(
            "^expr" to "Matches expr at beginning of the line",
            "expr$" to "Matches expr at end of line",
            "." to "Matches any single character (exception the newline character)",
            "[xyz]" to "Matches either x, y, or z",
            "[p-z]" to "Specifies a range. Matches any character from p to z",
            "[p-z1-9]" to "Matches either any character from p to z or any digit from 1 to 9",
            "[^p-z]" to "'^' as the first character negates the pattern. This will match anything outside of the range p-z",
            "xy" to "Matches x followed by y",
            "x|y" to "Matches either x or y")

    val metaSymbols = mapOf(
            "\\d" to "Matches digits ([0-9])",
            "\\D" to "Matches non-digits",
            "\\w" to "Matches word characters",
            "\\W" to "Matches non-word characters",
            "\\s" to "Matches whitespaces [\\t\\r\\f\\n]",
            "\\S" to "Matches non-whitespaces",
            "\\b" to "Matches word boundary when outside of a bracket. Matches backslash when placed in a bracket",
            "\\B" to "Matches non-word boundary",
            "\\A" to "Matches beginning of string",
            "\\Z" to "Matches end of String")


    val quantifiers = mapOf(
            "expr?" to "Matches 0 or 1 occurrence of expr (expr{0,1})",
            "expr*" to "Matches 0 or more occurrences of expr (expr{0,})",
            "expr+" to "Matches 1 or more occurrences of expr (expr{1,})",
            "expr{x, y}" to "Matches between x and y occurrences of expr",
            "expr{x, }" to "Matches x or more occurrences of expr")

    val format = "%-10s\t%s"
    val func = {entry : Map.Entry<String, String> -> println(format.format(entry.key, entry.value)) }

    println("Symbols")
    symbols.entries.forEach(func)

    println("\nMeta Symbols")
    metaSymbols.entries.forEach(func)

    println("\nQuantifiers")
    quantifiers.entries.forEach(func)

    //Create a regex object
    println("\nTesting regex: ^Matches")
    val regex = "^Matches".toRegex()
    symbols.entries.forEach({it ->
        //The Regex Type has a Number of Pattern Matching Methods
        val matchResult = regex.containsMatchIn(it.value)
        println("$matchResult => ${it.value}")
    })
}

Output

Symbols
^expr     	Matches expr at beginning of the line
expr$     	Matches expr at end of line
.         	Matches any single character (exception the newline character)
[xyz]     	Matches either x, y, or z
[p-z]     	Specifies a range. Matches any character from p to z
[p-z1-9]  	Matches either any character from p to z or any digit from 1 to 9
[^p-z]    	'^' as the first character negates the pattern. This will match anything outside of the range p-z
xy        	Matches x followed by y
x|y       	Matches either x or y

Meta Symbols
\d        	Matches digits ([0-9])
\D        	Matches non-digits
\w        	Matches word characters
\W        	Matches non-word characters
\s        	Matches whitespaces [\t\r\f\n]
\S        	Matches non-whitespaces
\b        	Matches word boundary when outside of a bracket. Matches backslash when placed in a bracket
\B        	Matches non-word boundary
\A        	Matches beginning of string
\Z        	Matches end of String

Quantifiers
expr?     	Matches 0 or 1 occurrence of expr (expr{0,1})
expr*     	Matches 0 or more occurrences of expr (expr{0,})
expr+     	Matches 1 or more occurrences of expr (expr{1,})
expr{x, y}	Matches between x and y occurrences of expr
expr{x, } 	Matches x or more occurrences of expr

Testing regex: ^Matches
Disconnected from the target VM, address: '127.0.0.1:61983', transport: 'socket'
true => Matches expr at beginning of the line
true => Matches expr at end of line
true => Matches any single character (exception the newline character)
true => Matches either x, y, or z
false => Specifies a range. Matches any character from p to z
true => Matches either any character from p to z or any digit from 1 to 9
false => '^' as the first character negates the pattern. This will match anything outside of the range p-z
true => Matches x followed by y
true => Matches either x or y

Rerences

Ganesh, S G., and Tushar Sharma. Oracle Certified Professional Java SE 7 Programmer Exams 1Z0-804 and 1Z0-805 A Comprehensive OCPJP 7 Certification Guide. Apress, 2013.

Kotlin String Splitting

Most programming tasks require string splitting. For example, CSV files often separate data based on the comma character, which requires developers to split each line based on the comma in order to extract data. Extracting domain names from a web address is another common use case for String splitting. For example, we might have the address https://stonesoupprogramming.com and we wish to separate the https:// portion of the string. We can split the string into a list where the first part contains http:// and the second index contains stonesoupprogramming.com.

In Kotlin, we use the split() method defined in the String class. It comes in two flavors. One flavor takes the character to split the string on, and the other flavor takes a Regex. Both versions of the split method return a list that contains all potions of the String.

Non-Regex Splitting

The first version of split() takes a varargs parameter of delimiters, an optional boolean argument to ignoreCase and an optional limit argument that restricts how many times the split happens.

val str = "I smell fear on you"
val parts = str.split(" ")
val partsTwo = str.split("I", "fear", "you")
val partsThree = str.split("I", true)
val partsFour = str.split(delimiters = " ", limit = 2)

All versions of split return a list. It’s worth keeping in mind that the returned list will not contain any of the delimiters passed to the delimiters argument in split(). Normally, that isn’t a problem. For example, would you really want the ‘,’ character for all fields in a CSV file?

Regex Version

Most programming languages treat regular expressions, REGEX, as a String. Doing so often leads to unexpected bugs. Consider Java’s String.split() method.

String myString = "Green. Eggs. Ham.";
String [] parts = myString.split(".");

You may think that parts holds {“Green”, “Eggs”, “Ham”}. It doesn’t. The period character is treated as a regex expression that matches to any character. It’s a very common mistake.

Thankfully, Kotlin treats regular expressions as its own type. When we want to use a Regex in Kotlin, we need to create a Regex object. The Kotlin String class has a toRegex() function that performs the conversion from String to Regex.

val str = "Green. Eggs. Ham"
val partsNonRegex = str.split(".") //No Regex. This will split on the period character
val partsRegex = str.split(".".toRegex()) //Now using REGEX matching

Putting it together

As always, we will conclude with an example program that demonstrates the topic. Many of my students are given assignments where they need to track the number of unique words in a String. We will use String splitting and maps to accomplish the goal.

fun main(args : Array<String>){
    val paragraph = """
        |I am Sam.
        |Sam I am.

        |That Sam-I-am!
        |That Sam-I-am!
        |I do not like
        |That Sam-I-am!

        |Do you like
        |Green eggs and ham?

        |I do not like them,
        |Sam-I-Am
        |I do not like
        |Green eggs and ham.
        """.trimMargin()

    //Remove all end line characters and then split the string on the space character
    val parts = paragraph.replace('\n', ' ').split(" ")
    
    //Create an empty mutable map
    val uniqueWords = mutableMapOf<String, Int>()
    
    //Populate the map
    parts.forEach( { it -> uniqueWords[it] = uniqueWords.getOrDefault(it, 0) + 1 })
    
    //Print each word with it's count value
    println(uniqueWords)
}

Here is the output when run.

{I=5, am=1, Sam.=1, Sam=1, am.=1, =3, That=3, Sam-I-am!=3, do=3, not=3, like=4, Do=1, you=1, Green=2, eggs=2, and=2, ham?=1, them,=1, Sam-I-Am=1, ham.=1}

Kotlin String Parsing

Kotlin is a strongly typed language, which means that variables of one type may not be used for another type. In many cases, strong typing is a benefit. For example, since the language only allows Int variables to hold int values, we have some protection (not complete) against injection attacks that attempt to insert a string of code into an int variable.

On a more practical manner, strong typing helps us prevent bugs. The compiler can check ahead of time if a variable has certain attributes or methods prior to runtime. We are also protected against unsafe implicit conversions of data, which is a common problem in weakly typed languages. However, strong typing has a drawback. We are forced to convert between data types.

In languages such as Java, this can be really troubling. Consider the following Java code snippet.

String three = "3";
int t = Integer.parseInt(three);

String four = String.valueOf(4);

Java’s approach to converting between Strings and Ints is clunky, to say the least. Since Java primitives are not objects, wrapper classes have to be used to facilitate conversion between types when casting won’t work. Using wrapper classes add verbosity to the code and mixes a procedural approach in with what could be an OOP approach.

Oddly, this is true of Java’s String class also. Strings are objects in Java, yet you will not find methods such as toInt() or toDouble() on the String class. Once again, you are forced to turn to a primitive type wrapper class methods such as Integer.parseInt(). Using such an approach feels unnatural, to say the least.

Kotlin Conversions

Kotlin treats all variables as objects. Furthermore, variables have conversion methods. So if when we want to convert a String to an Int in Kotlin, we call toInt() on the String. When we want to convert an Int to a String, we call toString(). The approach is much more OOP in design since we are calling the behavior on the object that we are using.

Here are a few code examples to demonstrate type conversions in Kotlin.

//convert "3" to 3
val three = "3".toInt()

//convert 3 to "3"
val threeStr = three.toString()

//convert "3.14159" to a double
val pi = "3.14159".toDouble()

It should be noted that while type conversions in Kotlin may be more simple than Java, they aren’t safer. If we attempt to call toInt() on a string that isn’t a number, we will get an exception.

val three = "Mr. Pickles".toInt() //Bad!!!

The runtime isn’t able to figure out what number is represented by the string “Mr. Pickles” as such, we will get a runtime exception. If we aren’t sure if a conversion is safe, we will need to wrap the cast in a try-catch block or turn to a third party library such as StringUtils in Apache Commons.

Putting it Together

Below is an example program that demonstrates String parsing and type conversions.

fun main(args : Array<String>){
    val three = 3
    val pi = 3.14159
    val t = true

    //Note: We are using toString() explicitly here for demonstration
    //purposes.
    println("Converting 3 to String => " + three.toString())
    println("Converting pi to String => " + pi.toString())
    println("Converting t to String => " + t.toString())

    val threeNum = "3".toInt()
    val piNum = "3.14159".toDouble()
    val tBool = "true".toBoolean()

    println("threeNum => " + threeNum)
    println("piNum => " + piNum)
    println("tBool => " + tBool)
}

Output

Converting 3 to String => 3
Converting pi to String => 3.14159
Converting t to String => true
threeNum => 3
piNum => 3.14159
tBool => true

Kotlin String Methods

The Kotlin String class has an indexOf() method that allows developers to the position of a character or set of characters within a string. Such an operation is especially useful in situations where you may need to break a string into a substring or divide a string into different parts. Let’s go over the indexOf() method with a few examples.

indexOf

indexOf(Char)

The indexOf(Char) method is used to search for a single character within a string. It will return the index where the character was first found or -1 if the string doesn’t contain such a character.

val paragraph = 
    "I am Sam.\n" +
    "Sam I am.\n" +

    "That Sam-I-am!\n" +
    "That Sam-I-am!\n" +
    "I do not like\n" +
    "That Sam-I-am!\n" +

    "Do you like\n" +
    "Green eggs and ham?\n" +

    "I do not like them,\n" +
    "Sam-I-Am\n" +
    "I do not like\n" +
    "Green eggs and ham.\n"

//Index of letter a => 2
println("Index of letter a => " + paragraph.indexOf('a'))

The letter ‘a’ is the 3rd character in the example string. Since computers count starting at 0, the result is 2. This method also has an optional argument that allows it to ignore case.

indexOf(String)

If we want to find where a certain substring begins, we use the indexOf(String) method. It works just like its Char counterpart.

//Index of 'Green eggs and ham' => 91
println("Index of 'Green eggs and ham' => " + paragraph.indexOf("Green eggs and ham"))

The substring “Green eggs and ham” is found at position 91. Once again, this method returns -1 if the search string isn’t found. We can also use the ignoreCase optional argument when we do not care about case sensitivity.

indexOf(Char, Int), indexOf(String, Int)

The indexOf method has an optional startIndex parameter that takes an int value. By default, startIndex is 0, which is why indexOf starts at the beginning of the string. If we want to start looking in the middle of the string, we need to pass a value to startIndex. Let’s look at an example of where we can find all occurrences of the letter ‘I’.

var fromIndex = 0
while(paragraph.indexOf('I', fromIndex) > -1){
    fromIndex = paragraph.indexOf("I", fromIndex)
    println("Found at => " + fromIndex)
    fromIndex++
}

Output

Found at => 0
Found at => 14
Found at => 29
Found at => 44
Found at => 50
Found at => 73
Found at => 111
Found at => 135
Found at => 140

The code tracks each index with a fromIndex variable. We enter into a while loop that continues until indexOf returns -1. With each iteration of the loop, we update fromIndex using indexOf() and pass in the old value of fromIndex. That causes the search to keep moving forward. After we print the index, we need to increment fromIndex by 1 because indexOf is inclusive. Should we fail to increment fromIndex, we will enter into an infinite loop because indexOf will continue to return the same value.

lastIndexOf

Strings also have a lastIndexOf() method that is a cousin to the indexOf() method. It takes the same arguments as indexOf(), but rather than returning the first occurence of the search character or string, it returns the last occurence instead.

//Last index of 'eggs' => 160
println("Last index of 'eggs' => " + paragraph.lastIndexOf("eggs"))

startsWith(), endsWith()

The startsWith() and endsWith() methods are convience methods that are used to check if a string starts or ends with a supplied prefixString. It also has an optional offset parameter that allows for searching in the middle of the string.

//paragraph starts with 'I am Sam' => true
println("paragraph starts with 'I am Sam' => " + paragraph.startsWith("I am Sam"))
//paragraph ends with 'Green eggs and ham. => true
println("paragraph ends with 'Green eggs and ham. => " + paragraph.endsWith("Green eggs and ham.\n"))

Putting it Together

Here is an example program followed by the output.

fun main(args : Array<String>){
    val paragraph =
        "I am Sam.\n" +
        "Sam I am.\n" +

        "That Sam-I-am!\n" +
        "That Sam-I-am!\n" +
        "I do not like\n" +
        "That Sam-I-am!\n" +

        "Do you like\n" +
        "Green eggs and ham?\n" +

        "I do not like them,\n" +
        "Sam-I-Am\n" +
        "I do not like\n" +
        "Green eggs and ham.\n"


    println("Index of letter a => " + paragraph.indexOf('a'))
    println("Index of 'Green eggs and ham' => " + paragraph.indexOf("Green eggs and ham"))
    println("Finding all occurrences of 'I'...")
    var fromIndex = 0
    while(paragraph.indexOf('I', fromIndex) > -1){
        fromIndex = paragraph.indexOf("I", fromIndex)
        println("Found at => " + fromIndex)
        fromIndex++
    }
    println("Last index of 'eggs' => " + paragraph.lastIndexOf("eggs"))
    println("paragraph starts with 'I am Sam' => " + paragraph.startsWith("I am Sam"))
    println("paragraph ends with 'Green eggs and ham. => " + paragraph.endsWith("Green eggs and ham.\n"))
}

Output

Index of letter a => 2
Index of 'Green eggs and ham' => 91
Finding all occurrences of 'I'...
Found at => 0
Found at => 14
Found at => 29
Found at => 44
Found at => 50
Found at => 73
Found at => 111
Found at => 135
Found at => 140
Last index of 'eggs' => 160
paragraph starts with 'I am Sam' => true
paragraph ends with 'Green eggs and ham. => true

Kotlin Arrays

Although they are used less frequently than the collection class, Kotlin does have arrays. Kotlin arrays are declared as Array where T corresponds to the type of object the array holds. The array type is packed with factory methods and extension functions, all of which make working with arrays easy.

Creating Arrays

We normally use the arrayOf() method to create an array.

//Create an initialized array
val belchers = arrayOf("Bob", "Linda", "Tina", "Gene", "Louise")

//Create an empty array with five elements
val teddies = arrayOfNulls<String>(5)

//Create an array with a generator function
val morts = Array(5){ "mort" }

In the first example, we use arrayOf() and then pass any number of arguments to the function. The Kotlin compiler will determine the type of object based on the arguments and create an array initialized with arguments. The second example creates an object array of the specified size and initialized with nulls. There are overloaded versions for primitives. The final function creates an array with a specified number of elements and initializes it with a generator function.

Extension Functions

toList() and other conversion functions

True to Kotlin style, Arrays have methods that convert the array to a collection class. Here is an example of converting an array to an immutable list.

val belcherList = belchers.toList()

sort()

Arrays have a sort() method that makes it easy to sort an array. There is an overloaded version that takes a comparator object also.

belchers.sort()

binarySearch

Kotlin arrays have a binarySearch method that lets developers apply the binarySearch algorithm to the array. Note that the function will fail if the array isn’t sorted first.

belchers.sort()
belchers.binarySearch("Linda") //returns 2

Arrays Class

The Arrays class is part of JDK and provides additional methods that are useful for working with arrays.

toString()

Calling toString() on an array doesn’t yield the result that one might expect. That’s because an array does not override toString() and instead uses the implementation found in java.lang.Object. To pretty print an array, we need to use Arrays.toString().

Arrays.toString(belchers)

equals

Arrays also use the equals() implementation found in java.lang.Object. If we want to compare two arrays by their elements, we use Arrays.equals().

val pestos = arrayOf("Jimmy", "Jimmy JR", "Andy", "Ollie")
val isEqual = Arrays.equals(belchers, pestos) //returns false

Putting it Together

Below is a Kotlin program that demonstrates arrays.

import java.util.*

fun main(args : Array<String>){
    val belchers = arrayOf(
                    "Bob",
                    "Linda",
                    "Tina",
                    "Gene",
                    "Louise")

    //Pretty print arrays using Arrays.toString()
    println("Printing the array")
    println(Arrays.toString(belchers) + "\n")

    println("Converting to a list")
    val belcherList = belchers.toList()
    println("belcherList => " + belcherList + "\n")

    println("Sorting")
    Arrays.sort(belchers)
    println("Sorted belchers => " + Arrays.toString(belchers) + "\n")

    println("Binary Search")
    println("Linda found at index => " + belchers.binarySearch("Linda") + "\n")

    println("Equals")
    val pestos = arrayOf("Jimmy", "Jimmy JR", "Andy", "Ollie")
    println(Arrays.toString(belchers) + " is equal to " + Arrays.toString(pestos) + " => " + Arrays.equals(belchers, pestos) + "\n")

    println("Filling an empty array")
    val teddies = Array(5){ "teddy" }
    println("After filling teddies => " + Arrays.toString(teddies) + "\n")
}

Output

Printing the array
[Bob, Linda, Tina, Gene, Louise]

Converting to a list
belcherList => [Bob, Linda, Tina, Gene, Louise]

Sorting
Sorted belchers => [Bob, Gene, Linda, Louise, Tina]

Binary Search
Linda found at index => 2

Equals
[Bob, Gene, Linda, Louise, Tina] is equal to [Jimmy, Jimmy JR, Andy, Ollie] => false

Filling an empty array
After filling teddies => [teddy, teddy, teddy, teddy, teddy]

Kotlin Collections Class

Kotlin and JDK have a number of extension methods that make working with collection classes easier.

Extension Methods

sort()

The sort() method sorts elements by their natual order. It also has an overloaded version that takes a comparator that allows for custom sorting.

val belchers = mutableListOf(
            "Bob",
            "Linda",
            "Tina",
            "Gene",
            "Louise")
belchers.sort()

binarySearch(T) : Int

The binarySearch function applies the binary search algorithm to the collection and returns the index of the element or -1 if not found. The list has to be sorted first.

belchers.sort()
belchers.binarySearch("Gene") //returns 1

Conversion Methods

Kotlin provides methods that allow for each switching between collection types.

val setBelchers = belchers.toSet()
val listBelchers = belchers.toList()

Populating a List

Collections can be populated with a generator function. Here is an example for a list.

val teddies = List(10){ "Teddy" }
println(teddies) //prints: [Teddy, Teddy, Teddy, Teddy, Teddy, Teddy, Teddy, Teddy, Teddy, Teddy]

max()

The max() function returns the maximum element in the collection. There is an overloaded version that takes a comparator.

val max = belchers.max()

min()

The min() function returns teh minimum element in the collection. There is an overloaded version that takes a comparator.

val min = belchers.min()

replaceAll

The replaceAll takes a lambda expression and replaces all elements according to the lambda function. Here is an example that replaces all occurences of “Tina” with “Mort”.

belchers.replaceAll { it -> if(it == "Tina") "Mort" else it }

addAll

The addAll function takes a list and adds all elements in the list to the collection.

belchers.addAll(teddies)

removeAll

The removeAll takes a collection and removes all matches from the current collection.

belchers.removeAll(teddies)

reverse()

The revesere() method reverses the order of the elements in the collection.

belchers.reverse()

Note

The functions demonstrated above are on MutableList. They may or may not be present on other collection types such as List, Set, or MutableSet. See the Kotlin documentation for more details.

Collections

Oddly, not all of the methods found in the Collections class have been implemented as extension functions. Here are two common functions found in the Collections class.

shuffle

Randomizes the elements in the list.

Collections.shuffle(belchers)

swap

Swaps the elements at the specified indexes.

Collections.swap(belchers, 0, 3)

Putting it Together

Below is an example program that demonstrates the mentioned functions.

import java.util.*

fun main(args : Array<String>){
    val belchers = mutableListOf(
            "Bob",
            "Linda",
            "Tina",
            "Gene",
            "Louise")

    println("Soring the belchers")
    belchers.sort()
    println("After sorting => " + belchers + "\n")

    println("Using Binary Search")
    println("Gene Found at Index => " + belchers.binarySearch("Gene"))

    //Make a read-only copy of belchers
    val belchersCopy = belchers.toList()
    println("Read only copy => " + belchersCopy + "\n")

    //Filling a list
    val teddies = List(10) { "Teddy"}
    println("Printing teddies => " + teddies + "\n")

    println("Finding the max belcher => " + belchers.max() + "\n")

    println("Find the min belcher => " + belchers.min() + "\n")

    println("Replacing Tina")
    belchers.replaceAll { it -> if(it == "Tina") "Mort" else it }
    println("After replacing Tina => " + belchers + "\n")

    println("Adding teddies...")
    belchers.addAll(teddies)
    println("After adding teddies => " + belchers + "\n")

    println("Removing all teddies...")
    belchers.removeAll(teddies)
    println("After removing teddies => " + belchers + "\n")

    println("Reversing belchers")
    belchers.reverse()
    println("After reversing => " + belchers + "\n")

    //Methods in the Collections class that haven't been made
    //into extension functions
    println("Shuffling belchers...")
    Collections.shuffle(belchers)
    println("After shuffling => " + belchers + "\n")


    println("Swapping 0 and 3")
    Collections.swap(belchers, 0, 3)
    println("After swap => " + belchers)
}

Output

Soring the belchers
After sorting => [Bob, Gene, Linda, Louise, Tina]

Using Binary Search
Gene Found at Index => 1
Read only copy => [Bob, Gene, Linda, Louise, Tina]

Printing teddies => [Teddy, Teddy, Teddy, Teddy, Teddy, Teddy, Teddy, Teddy, Teddy, Teddy]

Finding the max belcher => Tina

Find the min belcher => Bob

Replacing Tina
After replacing Tina => [Bob, Gene, Linda, Louise, Mort]

Adding teddies...
After adding teddies => [Bob, Gene, Linda, Louise, Mort, Teddy, Teddy, Teddy, Teddy, Teddy, Teddy, Teddy, Teddy, Teddy, Teddy]

Removing all teddies...
After removing teddies => [Bob, Gene, Linda, Louise, Mort]

Reversing belchers
After reversing => [Mort, Louise, Linda, Gene, Bob]

Shuffling belchers...
After shuffling => [Linda, Gene, Louise, Mort, Bob]

Swapping 0 and 3
After swap => [Mort, Gene, Louise, Linda, Bob]