Skip to content

Instantly share code, notes, and snippets.

@rahularity
Created July 5, 2020 20:46
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rahularity/7af1c2de9d3e1340fa6dd01b0144e24a to your computer and use it in GitHub Desktop.
Save rahularity/7af1c2de9d3e1340fa6dd01b0144e24a to your computer and use it in GitHub Desktop.
Getting Started With Kotlin

Kotlin Programming (Basics and Important)

Index

Kotlin Function

     //Syntax
     fun function_name (argument : argument_type) : return_type {}

     //Example
     fun main(args: Array<String>) : Unit {
          println("Hello World!")  
     }

Note: the unit return type is optional

     fun main(args: Array<String>){
          println("Hello World!")
     }

Variable Declaration

A variable in Kotlin can be declared using var or val.

     var string_variable = "Kotlin"
     val int_variable = 12345

Here the variable string_variable is type string and int_variable is type integer, but we do not require to explicitly specify the type. Kotlin complier knows this by initilizer expression.

We can also specify the type if we want

     var string_variable : String = "Kotlin"
     val int_variable : Int = 12345

When we are just declaring a variable without initializing then we need to specify a type.

     var a    // [ERROR : No type, no body]
     val b    // [ERROR : No type, no body]

     var a : String      // :white_check_mark: OK
     val b : Int         // :white_check_mark: OK

Difference between var and val

  • var (Mutable Variables): Can be changed inside the program at a later point in time.
  • val (Immutable Variables): Once assigned cannot be changed at any point in time.
     var name1 = "Rahul"
     name1 = "Pandey"    // :white_check_mark: OK

     val name2 = "Rahul"
     name2 = "Pandey"    // [ERROR : Val cannot be reassigned]

Array

Arrays in Kotlin can be created using library funcitons arrayOf() and Array()

     // arrayOf() to create an array
     val id = arrayOf(1,2,3,4,5,6,7,8,9)  
     val firstElement = id[0]  // 1
     val lastElement = id[id.size-1]  // 9


     // Array() to create an array
     val arr = Array(5, { i -> i*2 }) // arr[0,2,4,6,8]
     // first arg -> size of the array
     // second arg -> used to initialize and return the value of array element given its index.

Type Conversion

In Kotlin implicit type conversion is not allowed (as it is supported in Java)

     // in Java
     int value1 = 10;
     long value2 = value1;    // :white_check_mark: Valid in java
     // in Kotlin
     val value1 : Int = 10
     val value2 : Long = value1    // [ERROR: Type mismatch.]

In Kotlin Type Conversion can be done explicitly where, small data type can be converted to large data type and vice versa. The list of helper functions used for numeric conversion in Kotlin is given below:

     - toByte()
     - toShort()
     - toInt()
     - toLong()
     - toFloat()
     - toDouble()
     - toChar()

Kotlin Standard Input / Output

Output

Kotlin output operation is performed using the standard methods print() and println().

     println("Hello World!")  // print the value inside () and move to the next line.
     print("Welcome to  this world")  // print the value inside () and stay on the same line 

Input

We can use readLine() to read line of string input from standard input stream. It returns the line read or null.

Reading string input

     println("Enter your name : ")
     val name = readLine();

Reading other inputs

While using the readLine() function, we need to explicitly convert input lines other than String into their corresponding types.

     println("Enter your age : ")
     val age : Int = Integer.valueOf(readLine())

To input other data type rather than String, we need to use Scanner object of java.util.Scanner class from Java standard library.

     import java.util.Scanner  
     fun main(args: Array<String>) {  
          val read = Scanner(System.`in`)  
          println("Enter your age")  
          var age = read.nextInt()  
          println("Your input age is "+age)  
     }  

Here nextInt() is a method which takes integer input and stores in integer variable. The other data types Boolean, Float, Long and Double uses nextBoolean(), nextFloat(), nextLong() and nextDouble() to get input from user.

Kotlin Control Flow

WHEN

when expression is a conditional expression which returns a value corresponding to the satisfied expression. Kotlin, when expression is replacement of switch statement.

Comparison of switch and when

     public static void main(){
          int num = 1;
          switch(num){
               case 1:
                    System.out.println("Number One");
                    System.out.println("Multiple statements under one case");
                    break;
               case 2:
                    System.out.println("Number Two");
                    break;
               case 3:
               case 4:
                    System.out.println("Number Three or Number 4");
                    break;
               default:
                    System.out.println("None of the case satisfied.")
          }
     }
     fun main(args : Array<String>){
          val num : Int = 1
          when(num) {
               1 -> {
                    println("Number One")
                    println("Multiple statements under one case")
               }
               2 -> println("Number Two")
               3,4 -> println("Number Three or Number 4")
               else -> println("None of the case satisfied.")
          }
     }

in Kotlin:

  • break statement not required
  • instead of default we use else
  • multiple cases can be separated by comma in kotlin
 we can also use ranges in when
     fun main(args : Array<String>){
          val num : Int = 3
          when(num) {
               in 1..5 -> println("Input is provided in the range 1 to 5")  
               in 6..10 -> println("Input is provided in the range 6 to 10")  
               else -> println("none of the above")  
          }
     }

Null Safety

A variable that doesn't refers to anything, refers to null. Null is a keyword to allow a variable refer to nothing or to check if it exists (comparison can be done with == or !=)

In Kotlin - A variable cannot actually be null unless it is declared to allow for null.

Null can be allowed by suffixing the type name with ?

Example:

     fun nullSafety( val a : String, val b : String? ){     // here b is allowed for null

     }

Let's see what calling to above function are allowed and what callings are not allowed

     nullSafety("a", "b")     // :white_check_mark: Allowed
     nullSafety("a", null)    // :white_check_mark: Allowed
     nullSafety(null, "b")    // :x: Not Allowed
     nullSafety(null, null)   // :x: Not Allowed
     nullSafety(a, b)         // :interrobang: is only allowed if the compiler can prove that a cannot possibly be null.

Inside of nullSafety, the compiler will not allow you to do anything with b that would result in an exception if b should happen to be null - so you can do a.length, but not b.length. However, once you're inside a conditional where you have checked that b is not null, you can do it:

    fun nullSafety( val a : String, val b : String? ){     
         
         println(b.length)        // :x: NOT ALLOWED

         if (b != null) {         
             println(b.length)    // :white_check_mark: ALLOWED AFTER CHECKING FOR NULL CONDITION
         }
    }

Safe Call Operator ( ?. )

x?.y evaluates x, and if it is not null, then it evaluates x.y (without reevaluating x).

Basically safe call operator evaluates a chain by checking for null values.

     x && x.y && x.y.z &&& x.y.z.p 

     :point_down: // this can be written by safe call operator as // :point_down:

     x?.y?.z?.p

Elvis operator ( ?: )

x ?: y evaluates x, which becomes the result of the expression unless it's null, in which case you'll get y instead (which ought to be of a non-nullable type). This is also known as the "Elvis operator". You can even use it to perform an early return in case of null:

     val z = x ?: return y

This will assign x to z if x is non-null, but if it is null, the entire function that contains this expression will stop and return y (this works because return is also an expression, and if it is evaluated, it evaluates its argument and then makes the containing function return the result).

Not-null assertion operator ( !! )

Sometimes we know that we have a value x that is not null, but compiler is not able to identify the logic, in that case we need to explicitly tell the compiler that it should not care about about the variable to have a null value.

!! operator is used for this purpose.

Example:

     val x: String? = javaFunctionThatYouKnowReturnsNonNull()
     val y: String = x!!      // here the compiler will object as it is not sure if x is not null as x is declared to have null values.

!! will raise a NullPointerException if the value actually is null.

Functional Programming

In Kotlin, functions are first-class values - they can be assigned to variables and passed around as parameters.

     fun safeDivide(numerator: Int, denominator: Int) =
          if (denominator == 0) 0.0 else numerator.toDouble() / denominator     
 we can assign a function to a variable by prefixing function's name with ::
     // the type of the variable would normally be inferred in case of a function    
     val f: (Int, Int) -> Double = ::safeDivide
     OR
     val f = ::safeDivide

Lambda Expressions

lambda expressions: unnamed function declarations with a very compact syntax, which evaluate to callable function objects.

  • A lambda expression is enclosed in curly braces
  • Begins by listing its parameter names and possibly their types (unless the types can be inferred from context):
  • Parameters are not enclosed in paranthesis
  • The last statement must be an expression, whose result will become the return value of the lambda (unless Unit is the return type of the variable/parameter that the lambda expression is assigned to, in which case the lambda has no return value).
     val safeDivide = { numerator: Int, denominator: Int ->
          if (denominator == 0) 0.0 else numerator.toDouble() / denominator     
     }
 The type of safeDivide is (Int, Int) -> Double.

If the type is declared of the variable to which the lambda expression is attached then kotlin can infer the parameter types.

    val drivingResult : (factor1 : String, factor2 : String ) -> Unit =  { factor1 : String, factor2 : String ->
       if( factor1 == "Good" && factor2 == "Good" ){
           print("Passed")
       }else if( (factor1 == "Good" && factor2 == "Bad") || (factor1 == "Bad" && factor2 == "Good") ){
           print("Passed in half")
       }else{
           print("Failed")
       }
   }

   // as we have declared the type of drivingResult we need not to mention the type of lambda function arguments

   val drivingResult : (factor1 : String, factor2 : String ) -> Unit =  { factor1, factor2 ->
       if( factor1 == "Good" && factor2 == "Good" ){
           print("Passed")
       }else if( (factor1 == "Good" && factor2 == "Bad") || (factor1 == "Bad" && factor2 == "Good") ){
           print("Passed in half")
       }else{
           print("Failed")
       }
   }

If we are passing the lambda function directly as parameter to a function then kotlin can infer the type of lambda arguments.

    fun callAndPrint(function: (Int, Int) -> Double) { 
         println(function(2, 0))
    }

    callAndPrint({ numerator, denominator ->     // here lambda function argument type is not required
         if (denominator == 0) 0.0 else numerator.toDouble() / denominator
    })

A parameterless lambda does not need the arrow

    val hero: () -> Unit = { println("Lambda without parameter does not require -> ") }
    OR
    val hero = { println("Lambda without parameter does not require -> ") }

In Lambda with only one parameter, we can choose to omit the parameter and arrow (->)

   // with arrow 
   val oneParameterLambda : (arg: Double) -> Double = { arg : Double -> 
        arg * arg
   }

   //without arrow and argument
   val oneParameterLambda : (arg: Double) -> Double = { it*it }

   // calling the function
   oneParameterLambda(8.2);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment