Wednesday, February 17, 2021

Kotlin

General

In Kotlin, Everything is Object.

Any is root of all classes like java Object. 

Unit is same as void of JAVA.

Nothing this is usually used to represent the return type of function which will always throw an exception.

0] Data Type:- Same like java, all are objects not primitive.

Byte, Short, Int, Long, Float, Double, String, Date, Char, Boolean

Default number variables are Int unless it crosses Int max limit.

Type check is done using "is" keyword

e.g. if (obj is String) {

        return obj.length

    }

'New' keyword not needed.

privateprotectedinternal(default in java) and public

In kotlin default scope is "public".

1] Variables :-

val for immutable variable declaration.

var for mutable variable declaration

e.g. val name : String = "abc"

Variables are mandatory to be initialized.

If want to assign null value then put "?" after type declaration

e.g. var dept : String? = null

Kotlin infers variable types, so variable type declaration is not mandatory

e.g. var fname = "ABC"

String comparison "=="

String formatting :-  

val name = "hello"

println("$name world")

println("{$name.count()} world")

buildString() isnin built function for string builder.

const for constant.

== for equals comparison.

=== for reference comparison.

Explicitly getter, setter method can be defined for custom behaviour.

var interestRate : Int = 0
set(value) {
if (value > 3)
field = value
}

val isEmpty: Boolean get() = this.size == 0

field is internal variable available.

2] Control Flow :- 

  If Else If Else are same like java

  Instead of "switch", Kotlin has "when".

In "when" instead of "default" it uses "else".

"if",  "when", "try/catch" can be used to assign values to a variable.

e.g. val dept = if (name != null) "hi" else "hello"

vale dept = when(name) {null -> "hello" else -> "hi"} 

Ternary operator are not supported as same can be achieved with if <expr> else <expr> in one line


3] Function :-

Syntax is     fun <function_name> : <return_type> {

}

for VOID function it is ": Unit".

Return types are mandatory except VOID. Function return types are not inferred.

"if",  "when", "try/catch" can be used to assign values to a function.

Function parameter can have default values.

Overloading of function is same as java.

Extension functions :- To declare an extension function, prefix its name with a receiver type, which refers to the type being extended. Extensions are resolved statically.

fun String.mask(value : String) : String {
return "abcde"
}

Extension properties :- 

val <T> List<T>.lastIndex: Int get() = size - 1

Initializers are not allowed for extension properties.

Companion objects can also have extension functions.

Scope of extension function:- In most cases, define extensions on the top level, directly under packages. To use an extension outside its declaring package, import it at the call site.

Recursive function - tailrec makes computation of result in each step so there is no stack overflow, it acts as loop. But if it is not used tailrec then result is calculated in the end but if may cause stack overflow.

A higher-order function is a function that takes functions as parameters, or returns a function.

val ss : (Int, Int) -> Int = { a: Int, b : Int -> a + b }

Function can be called as f.invoke or f()

e.g. ss.invoke(12, 34)    or     ss(12,34)   // can be denoted as ::

Passing trailing lambdas :- if the last parameter of a function is a function, then a lambda expression passed as the corresponding argument can be placed outside the parentheses.
val product = items.fold(1) { acc, e -> acc * e }
If the lambda is the only argument in that call, the parentheses can be omitted entirely

Function parameter can have default value assigned.

Named arguments. -- function with many parameter can be called by passing parameter name.

e.g.  reformat( "String!", false, upperCaseFirstLetter = false,
divideByCamelHumps = true, '_')

Member functions and extensions with a single parameter can be turned into infix functions.

infix fun Int.times(str: String) = str.repeat(this)       
println(2 times "Bye ")                     // method called without brackets        

A higher-order function is a function that takes functions as parameters, or returns a function.        

it: implicit name of a single parameter

4] Loop :-

For loop syntax is similar to python.

for (i in 1..100) { ... }  // closed range: includes 100

for (i in 1 until 100) { ... } // half-open range: does not include 100

for (x in 2..10 step 2) { ... }

for (x in 10 downTo 1) { ... }

if (x in 1..10) { ... }


while, do - while is similar to java

break, return supports label

loop@ for (i in 1..100) {

    for (j in 1..100) {

        if (...) break@loop

    }

}

4] classes :- 

All classes are default final, it can't be inherited.

e.g.   class myClass

To make a class inheritable, mark it with the open keyword.

open class Base(p: Int)

class Derived(p: Int) : Base(p)

A class in Kotlin can have a primary constructor and one or more secondary constructors.The primary constructor is part of the class header:

class Person constructor(firstName: String) { /*...*/ }

class C private constructor(a: Int) { ... }

By default constructor is public. Constructor parameters are by default val.

The primary constructor cannot contain any code. Initialization code can be placed in initializer blocks, which are prefixed with the init keyword.

During an instance initialization, the initializer blocks are executed in the same order as they appear in the class body, interleaved with the property initializers:

If the class has a primary constructor, each secondary constructor needs to delegate to the primary constructor, either directly or indirectly through another secondary constructor(s). 

If a non-abstract class does not declare any constructors (primary or secondary), it will have a generated primary constructor with no arguments. The visibility of the constructor will be public. 

To override method & properties use 'open' prefix for method & property in parent class & use 'override' keyword in child class.

'lateinit' allows initializing a not-null property outside of a constructor

@JvmOverloads is used when overloading method to be used in Java. As in Kotlin function has default parameter but java doesn't support.

Sealed classes and interfaces represent restricted class hierarchies. No other subclasses may appear outside a module within which the sealed class is defined.

enum classes can't extend a sealed class (as well as any other class), but they can implement sealed interfaces.

Generics : Classes in Kotlin can have type parameters, just like in Java.

Kotlin doesn't have wildcard. Kotlin supports declaration site variance.

Type parameter T is not INPUT in any method.

interface Source<out T> { fun nextT():

}

Type parameter T is not OUTPUT of any method.

interface Comparable<in T> {

operator fun compareTo(other: T): Int }

Object Expression, Object declaration, Companion object

Nested and inner classes - interface can be used with inner classes. Inner classes carry a reference to an object of outer class.  Anonymous inner class instances are created using an object expression.

Sealed classes let you restrict the use of inheritance. Once you declare a class sealed, it can only be subclassed from inside the same package.

Inline classes - To declare an inline class, use the value modifier before the name of the class. To declare an inline class for the JVM backend, use the value modifier along with the @JvmInline annotation before the class declaration.


Object classes - Like Singleton of Java.

Delegation - Delegation pattern          class Derived(b: Base) : Base by b
The by-clause in the supertype list for Derived indicates that b will be stored internally in objects of Derived and the compiler will generate all the methods of Base that forward to b.

Delegated properties :- 

      Lazy properties: the value is computed only on first access

  • Observable properties: listeners are notified about changes to this property.

    Storing properties in a map instead of a separate field for each property.

Type Aliases :- 

Operator overloading:- To implement an operator, provide a member function or an extension functionwith a specific name for the corresponding type.

operator fun Point.unaryMinus() = Point(-x, -y)

Null Handling :-

var b: String? = "abc"

Safe calls ( ?. )

 val b: String? = null

println(b?.length)

Safe call operator ?. doesn't execute function if it is null. it returns null instead of throwing exception.

e.g. bob?.department?.head?.name

if in above bob or department or head is null it returns null

Elvis operator ( ?: ) (If-not-null-else shorthand):

val l : Int ?= null
println(l?.toString() ?: "error")

The !! operator 

This is the not-null assertion operator. Use it only when you are sure that value is not null otherwise it will throw NPE.

Safe Casts

Regular casts may result in a ClassCastException
val aInt: Int? = a as? Int

Collections of a nullable type

If you have a collection of elements of a nullable type and want to filter non-null elements, you can do so by using filterNotNull:


val nullableList: List<Int?> = listOf(1, 2, null, 4) val intList: List<Int> = nullableList.filterNotNull()


This expressions

class A { // implicit label @A inner class B { // implicit label @B fun Int.foo() { // implicit label @foo val a = this@A // A's this val b = this@B // B's this val c = this // foo()'s receiver, an Int val c1 = this@foo // foo()'s receiver, an Int val funLit = lambda@ fun String.() { val d = this // funLit's receiver, a String }}}}


5] Collections

Collection Types

Collection interfaces hierarchy

Utility functions listOf, setOf, mapOf creates immutable list, set, map. MutableList is ArrayList.
The default implementation of MutableSet – LinkedHashSet – preserves the order of elements insertion.HashSet order is not guaranteed.


Collection useful methods map, filter, filterNot, partition (returns pair first collection satisfying condition & other not), take(2) (returns first 2 elements), drop(3) removes 3 elements
any() - returns true if predicate condition match for any element, all(), none(), chunked() -- cuts list into
list of list. windowed() -- cuts list into list of list. 
zip() -- one list can be zipped with other list & will return List<Pair>. Pair will have element from both the list. reduce(), fold() both has accumulator passed as first argument. In fold function initial value can be passed. reduceRight(), runningReduce(), foldRight(), slice(), subList(), shuffled()
Sequence - > is similar to iterator but it is evaluated lazily. Iterator is eager. sequenceOf()
sortBy() -> original Collection is sorted 
sortedBy() -> original Collection is not modified, it returns output with modified collection.
sortedWith() -> original Collection is sorted with Multiple conditions applied.

6] Scope Functions -

Function

Object reference

Return value

Is extension function

let

it

Lambda result

Yes

run

this

Lambda result

Yes

run

-

Lambda result

No: called without the context object

with

this

Lambda result

No: takes the context object as an argument.

apply

this

Context object

Yes

also

it

Context object

Yes


7] try with resource

val stream = Files.newInputStream(Paths.get("/some/file.txt")) stream.buffered().reader().use { reader -> println(reader.readText()) }

use keyword is for autoclosable of resource.

8] Equality checks
Kotlin uses == for structural comparison and === for referential comparison.
More precisely, a == b compiles down to if (a == null) b == null else a.equals(b).

9] Ternary operator 
There is no ternary operator condition ? then : else in Kotlin. Instead, if may be used as an expression: e.g. fun max(a: Int, b: Int) = if (a > b) a else b

No comments:

Post a Comment