27 octombrie 2022

Kotlin - colecții - ziua 7

Colecții

var people: List<Pers?> = listOf(Pers(23), null)
for (person: Pers? in people) {
println(person?.age)
}

val items = IntArray(2)
items[0] = 1
items[1] = 2

val numbers = intArrayOf(1,2,3,4,5)
numbers.forEachIndexed {index, element ->
println("$index is $element")
}


High order functions

= o funcție care ia ca parametru o altă funcție

val action = { println("Hello World") }
// val calc = {x:Int, y:Int -> x*y}
val calc: (Int, Int) -> Int = {x, y -> x*y}
doSomething(action)

fun doSomething(func: () -> Unit) {
func()
}


Inlining 

- ajută la performanță

val ints = listOf(1,2,3,4)
val i = first(ints, { i -> i == 3})
println(i)


inline fun <T> first(items: List<T>, predicate: (T) -> Boolean): T {
for (item in items) {
if (predicate(item)) return item
}
throw Exception()
}

19 octombrie 2022

Kotlin - NULL handling - ziua 6

Java functional interfaces

Ex. Runnable, Callable 


variabila lambda este refolosita la al doilea apel;

variabila lambda nu mai poate fi refolosita la al doilea apel din cauza lui count;


Constructor SAM - pentru dezambiguizare (când compilatorul nu știe să transforme lambda în interfață funcțională)



Constrângeri de nulabilitate

Evitare NPE prin „cod defensiv” --> mult cod în plus

Kotlin:

- tipuri non-nullable

fun closeMeeting(m: Meeting): Boolean { // m: Meeting, deci nu poate fi null
return if (m.canClose()) m.close()
else false
}

fun main(args: Array<String>) {
closeMeeting(
null) // EROARE de COMPILARE
}


- tipuri nullable:  fun closeMeeting(m: Meeting?): Boolean

- safe calls: obj?.method()  === if (obj != null) obj.method()

- operatorul Elvis: newMeeting = m ?: Meeting()   === newMeeting = (m != null) ? m : new Meeting();

- safe cast:  val saveable = obj as? ISaveable    === saveable = obj instanceof ISaveable ? obj : null;

- not-null assertion:  m!!.close()  === assert (m != null) si arunca NPE daca s-a gasit null

- LET: cheama ce e in paranteze doar daca m != null

  m?.let { closeMeeting(m) }

- lateinit: Kotlin nu te lasă să declari o variabilă fără să fie inițializată. Soluții: inițializare cu o valoare default, cu null (și atunci devine nullable), sau cu lateinit (când știu că nu vreau să fie nullable).

  lateinit var address: Address // promisiune compilatorului că voi inițializa variabila


Interacțiune cu Java (adnotări)

public @Nullable String getTitle() {
  return meetingTitle;
}

public void setTitle(@NotNull String title) {
  this.meetingTitle = title;
}

// Kotlin
var title: String? = meeting.getTitle()


Platform type

Când nu există adnotări, compilatorul Kotlin știe că este doar un tip din Java, nu se știe dacă poate fi null sau nu, apare cu semnul exclamării, ex. String! = String sau String?
- dacă Kotlin implementează o interfață din Java unde există return type de tip platform, atunci return type al metodelor implementate poate fi atât nullable cât și non-nullable

15 octombrie 2022

Kotlin - Objects, High level functions & Filtre (ziua 5)

 object

- introduce un singleton (nu există constructor, instanțe)

- poate extinde un Comparator

- adnotare metodă din interiorul obiectului cu @JvmStatic pentru a putea fi chemată din Java

class Course(val id: Int, val title: String) {
}

object Courses {
var allCourses = arrayListOf<Course>()

init {
allCourses.add(Course(1, "Kotlin"))
allCourses.add(Course(2, "Maven"))
}
}

fun enroll(courseName: String){
val course = Courses.allCourses
.filter{it.title == courseName}
.firstOrNull()
}


Companion objects

- keyword: companion objects => Metodele din interiorul obiectului devin statice (factory methods)

open class Student : Person {
  // ....
  companion object : Internship<Student> {
    override fun applyToInternship(title: Student) {
TODO("Not yet implemented")
}

// adding static methods to the class
fun createUndergrad(name: String) = Undergrad(name)
fun createPostgrad(name: String) = Postgrad(name)
}
}

class Undergrad(name: String) : Student(name)

class Postgrad(name: String) : Student(name)

interface Internship<T> {
fun applyToInternship(title: T)
}


fun main(args: Array<String>) {
  Student.createPostgrad("Naim")
  Student.createUndergrad("Amir")
}


High level functions

program.fibonacci(8) { n -> println(n) }

program.fibonacci(8) { println(it) }

program.fibonacci(8, ::println)


Lambda

- pot schimba valori (in Java trebuie să fie final)

var total = 0

program.fibonacci(8) { it -> total += it }


with (student) {

  // asignari pe campurile obiectului student

  name = "Geo"

  city = "Bucharest"

}


student.apply {

  name = "Geo"

  city = "Bucharest"

}


Filter, map, predicate

val ints = listOf(1,2,3,4,5)
val smallInts = ints.filter { it < 4 }
for(i: Int in smallInts) println(i)

val sqInts = ints.map { it*it }
for(i: Int in sqInts) println(i)

val smallSqInts = ints.filter { it < 3 }.map { it*it }
for(i: Int in smallSqInts) println(i)

val largeInts = ints.all { it > 3 }
println(largeInts) // false: not all are grt than 3

val largeIntsAny = ints.any { it > 3 }
println(largeIntsAny) // true: there is one elem grt than 3

val grtThnThree = { v: Int -> v > 3 }
val largeCount = ints.count(grtThnThree)
println(largeCount) // 2

var found :Int? = ints.find(grtThnThree)
println(found) // 4 is the first elem found grt than 3

found = ints.find { it > 5 }
println(found) // null


Secvențe

- folosite atunci când listele create de filter/map ar fi imense

- folosesc evaluare leneșă

- se preferă secvențele în locul listelor

- în Java8, echivalentul este streams

Exemplu:

val titles = meetings.asSequence().filter { ... }.map { ... }

// for (i: String in titles) println(i)

Diferențe

- cu asSequence si fara println (comentat), nu se evalueaza deloc expresia (lazy)

- cu asSequence si println, ordinea este filtru + map + printare element din meetings, deoarece rezultatul este evaluat la cerere, cand este nevoie de el in println

- fara asSequence se evalueaza expresia indiferent daca rezultatul este sau nu folositor; ordinea este: toate filtrele, apoi toate maparile, apoi toate printarile

- cu asSequence operatiile pot fi mai eficiente, in special daca se cere doar primul rezultat (ca exemplu cu find = terminal operator)

06 octombrie 2022

KOTLIN - Clase (ziua 4)

 Interfețe

- public by default

- nu există implements / extends

interface Time {
fun setTime(hrs: Int, mins: Int = 0, secs: Int = 0)
fun setTime(time: String) = setTime(0) // default implementation
}

interface NoTime {
fun setTime(time: String) {}
}

class MyTime : Time, NoTime {
override fun setTime(hrs: Int, mins: Int, secs: Int) {}

override fun setTime(time: String) {
super<Time>.setTime(time)
super<NoTime>.setTime(time)

}
}


Clase

- public, final by default (și metodele sunt final by default)

- dacă vrei să nu fie final - se specifică open

In Java era o practică bună să adaugi final claselor care nu trebuiesc extinse

- suport pt abstract

- clase sigilate (sealed)

- internal: clase vizibile doar în modulul respectiv 

- protected, private; dar nu există package private

open abstract class Person () {
var firstName: String = ""
var lastName: String = ""

open fun getName(): String = "$firstName $lastName" // can be overriden

abstract fun getWork() // can be implemented

fun getVacations() {} // cannot be overriden
}

class Student : Person() {
override fun getName(): String{return ""}
override fun getWork() {
TODO("Not yet implemented")
}
}


Clase sigilate

- ierarhizare, asemănare cu enum

sealed class PersonEvent {
// nested subclasses
class Awake: PersonEvent()
class Asleep: PersonEvent()
class Eating(val food: String): PersonEvent()
}

fun handlePersonEvent(event: PersonEvent) =
when(event) {
is PersonEvent.Awake -> println("Awake")
is PersonEvent.Asleep -> println("Asleep")
is PersonEvent.Eating -> println("Eating ${event.food}")
}


Constructori

open class Person (_fname: String, _lname: String) {
var firstName: String = ""
var lastName: String = ""

init {
this.firstName = _fname
this.lastName = _lname
}

constructor(name: String) : this(name, "")
}


class Student : Person {
var age: Int;
init {
age = 0;
}

constructor(name: String) : super(name)

constructor(first: String, last: String) : super(first, last)

constructor(first: String, last: String, age: Int) : super(first, last) {
this.age = age;
}
}


Data classes

- furnizează metodele toString, equals, hashCode + metoda copy pentru clonare

- sunt clase imutabile

- introdusă prin keywork data class

fun main(args: Array<String>) {
var st1 = Steward(1, "Lina")
var st2 = Steward(1, "Lina")
var st3 = st2.copy(name = "Roberta")
// toate câmpurile la fel mai puțin name

println("Equal? ".plus(st1 == st2)) // true numai dacă există keyword data peste Steward
println(st3) // apelează toString, rezultat citibil față de un Steward@5e2de80c, dacă nu era data
}

data class Steward(val id: Int, val name: String)