Lambda — είναι μια ανώνυμη συνάρτηση που παρουσιάζεται ως συμπαγής έκφραση { ορίσματα -> σώμα }. Στο Kotlin, τα lambda είναι ο κύριος τρόπος μεταφοράς συμπεριφοράς σε συναρτήσεις ανώτερης τάξης (higher-order functions), παρέχοντας συνοπτική σύνταξη χωρίς την ανάγκη δήλωσης ξεχωριστής συνάρτησης. Σύμφωνα με την τεκμηρίωση του Kotlin (2026), πάνω από το 70% των συναρτήσεων ανώτερης τάξης σε τυπικά έργα καλούνται με lambda. Lambda επιτρέπει τη γραφή κώδικα σε λειτουργικό στυλ με ελάχιστο συντακτικό θόρυβο.
Κύρια σημεία
Lambda (έκφραση lambda) — είναι μια ανώνυμη συνάρτηση που ορίζεται ως έκφραση, όχι ως δήλωση. Ο όρος προέρχεται από τον λογισμό λάμδα του Alonzo Church (1936). Στον προγραμματισμό, το lambda αντιπροσωπεύει ένα μπλοκ κώδικα που μπορεί να μεταβιβαστεί ως τιμή, να αποθηκευτεί σε μια μεταβλητή και να κληθεί αργότερα. Στο Kotlin, το lambda περικλείεται πάντα σε άγκιστρα { }, τα ορίσματα διαχωρίζονται από το σώμα με το βέλος ->.
Το lambda διαφέρει από μια συνηθισμένη συνάρτηση ως προς την απουσία ονόματος και της λέξης-κλειδιού fun. Αυτό επιτρέπει τη δήλωση συμπεριφοράς απευθείας στο σημείο χρήσης, χωρίς να επιβαρύνεται ο κώδικας με πρόσθετες δηλώσεις. Ο μεταγλωττιστής Kotlin συνάγει τους τύπους ορισμάτων από το περιβάλλον, επομένως σε πολλές περιπτώσεις οι τύποι μπορούν να παραλειφθούν. Το lambda είναι συντακτική ζάχαρη πάνω από τον συναρτησιακό τύπο (T) -> R: κάθε lambda έχει έναν αντίστοιχο συναρτησιακό τύπο.
Η κύρια εφαρμογή των lambda στο Kotlin είναι η μεταβίβαση σε συναρτήσεις ανώτερης τάξης (higher-order functions). Η τυπική βιβλιοθήκη χρησιμοποιεί lambda παντού: filter { it > 0 }, map { it.uppercase() }, forEach { println(it) }. Τα lambda χρησιμοποιούνται επίσης για τη δημιουργία ακροατών συμβάντων, callback, διαμορφωτών αντικειμένων μέσω apply και run, καθιστώντας τον κώδικα πιο δηλωτικό σε σύγκριση με τις ανώνυμες κλάσεις.
Η πλήρης μορφή της έκφρασης lambda στο Kotlin: { ορίσματα -> σώμα_lambda }. Τα ορίσματα απαριθμούνται με κόμμα, ακολουθούμενα από βέλος και σώμα — μία ή περισσότερες εκφράσεις. Εάν το σώμα περιέχει πολλές γραμμές, η τελευταία έκφραση γίνεται η τιμή επιστροφής. Εάν η συνάρτηση δέχεται lambda ως τελευταίο όρισμα, μπορεί να μεταφερθεί εκτός των παρενθέσεων κλήσης.
val sum: (Int, Int) -> Int = { a, b -> a + b }
// Τύποι που συνάγονται από το περιβάλλον
val sumShort = { a: Int, b: Int -> a + b }
// Κλήση lambda
val result = sum(5, 3) // 8
println(result)
Η μεταβλητή sum δηλώνεται με ρητό συναρτησιακό τύπο (Int, Int) -> Int και αρχικοποιείται με lambda { a, b -> a + b }. Για το sumShort, οι τύποι καθορίζονται εντός του lambda και ο τύπος της μεταβλητής συνάγεται. Και οι δύο παραλλαγές είναι ισοδύναμες. Η κλήση ενός lambda δεν διαφέρει από την κλήση μιας συνηθισμένης συνάρτησης — χρησιμοποιείται η σύνταξη sum(5, 3). Το lambda χωρίς ορίσματα γράφεται ως { body }, με ένα όρισμα — { it -> it * 2 } ή απλά { it * 2 }.
Όταν το lambda δέχεται ακριβώς ένα όρισμα, το Kotlin παρέχει το σιωπηρό όνομα it. Αυτό εξαλείφει την ανάγκη δήλωσης του ορίσματος στην αριστερή πλευρά. Ο προγραμματιστής γράφει μόνο το σώμα του lambda, χρησιμοποιώντας το it για πρόσβαση στη μοναδική παράμετρο. Αυτή η σύνταξη είναι ιδιαίτερα βολική σε αλυσίδες επεξεργασίας συλλογών, όπου το it υποδηλώνει το τρέχον στοιχείο.
val numbers = listOf(1, 2, 3, 4, 5)
// Ρητό όνομα παραμέτρου
val squaredExplicit = numbers.map { n -> n * n }
// Σιωπηρό it
val squared = numbers.map { it * it }
// Φιλτράρισμα με it
val even = numbers.filter { it % 2 == 0 }
println(squared) // [1, 4, 9, 16, 25]
Στο παράδειγμα map { it * it } χρησιμοποιείται it αντί της δήλωσης n ->. Το Kotlin εκχωρεί αυτόματα το it για τη μοναδική παράμετρο του lambda. Εάν το lambda δέχεται δύο ή περισσότερα ορίσματα, το it δεν δημιουργείται — όλες οι παράμετροι πρέπει να δηλωθούν ρητά. Για καλύτερη αναγνωσιμότητα των ένθετων lambda, συνιστάται να δίνονται στις παραμέτρους ουσιαστικά ονόματα και να χρησιμοποιείται το it σε σύντομα μονόγραμμα κατηγορήματα.
Trailing lambda (τελικό lambda) — ένα συντακτικό χαρακτηριστικό του Kotlin που επιτρέπει τη μεταφορά του τελευταίου ορίσματος-lambda εκτός των στρογγυλών παρενθέσεων κλήσης της συνάρτησης. Αυτό κάνει τον κώδικα να μοιάζει με ενσωματωμένες γλωσσικές κατασκευές. Εάν το lambda είναι το μοναδικό όρισμα, οι παρενθέσεις μπορούν να παραλειφθούν εντελώς. Αυτή η προσέγγιση χρησιμοποιείται ενεργά στην τυπική βιβλιοθήκη και στο DSL.
// Τυπική κλήση
thread(block = {
println("Γεια από το νήμα")
})
// Έκδοση trailing lambda
thread {
println("Γεια από το νήμα")
}
// repeat με trailing lambda
repeat(3) { index ->
println("Επανάληψη $index")
}
// run με πολύγραμμο lambda
val config = run {
val host = "localhost"
val port = 8080
"$host:$port"
}
Η συνάρτηση thread δέχεται Runnable ως τελευταίο όρισμα. Χάρη στο trailing lambda, το lambda μπορεί να μεταβιβαστεί εκτός παρενθέσεων, που οπτικά μοιάζει με μπλοκ κώδικα. Η συνάρτηση repeat δέχεται τον αριθμό των επαναλήψεων και ένα lambda με δείκτη. run — ένα παράδειγμα συνάρτησης ανώτερης τάξης όπου ένα πολύγραμμο lambda υπολογίζει την τιμή που επιστρέφεται από την τελευταία έκφραση. Οι παρενθέσεις γύρω από το run() μπορούν να παραλειφθούν εάν το lambda είναι το μοναδικό όρισμα.
Σύλληψη μεταβλητών (closure) — η ικανότητα του lambda να έχει πρόσβαση σε μεταβλητές που δηλώνονται στο εξωτερικό πεδίο ορατότητας. Στο Kotlin, το lambda μπορεί να διαβάζει και να τροποποιεί μεταβλητές var, καθώς και να διαβάζει μεταβλητές val από το περιβάλλον πλαίσιο. Οι συλληφθείσες μεταβλητές αποθηκεύονται μαζί με το lambda καθ' όλη τη διάρκεια του κύκλου ζωής του, επιτρέποντας τη δημιουργία συναρτήσεων με κατάσταση.
fun makeCounter(): () -> Int {
var count = 0
return {
count++ // αριθμός συλλήψεων
}
}
fun main() {
val counter = makeCounter()
println(counter()) // 0
println(counter()) // 1
println(counter()) // 2
}
Η συνάρτηση makeCounter δηλώνει μια τοπική μεταβλητή count και επιστρέφει το lambda { count++ }. Παρόλο που η makeCounter ολοκλήρωσε την εργασία της, το επιστρεφόμενο lambda διατηρεί την αναφορά στο count μέσω κλεισίματος (closure). Κάθε κλήση counter() αυξάνει και επιστρέφει την τρέχουσα τιμή. Ο μηχανισμός closure αποτελεί τη βάση του currying, των εργοστασίων συναρτήσεων και της απομνημόνευσης. Είναι σημαντικό να θυμάστε ότι η σύλληψη μεταβλητών που μπορούν να αλλάξουν μπορεί να οδηγήσει σε απροσδόκητη συμπεριφορά κατά την παράλληλη εκτέλεση.
Συχνές ερωτήσεις
Lambda δεν υποστηρίζει άνευ όρων return — το return χωρίς ετικέτα επιστρέφει τον έλεγχο στην εξωτερική συνάρτηση. Για έξοδο από το lambda, χρησιμοποιήστε return@label, όπου label είναι το όνομα της συνάρτησης ανώτερης τάξης στην οποία μεταβιβάστηκε το lambda.
Ανώνυμη συνάρτηση γράφεται ως fun(a: Int): Int { return a * 2 } και υποστηρίζει return χωρίς ετικέτα. Lambda { a -> a * 2 } είναι συντακτικά συντομότερη, αλλά απαιτεί return@label για πρόωρη έξοδο.
Εάν το lambda δεν δέχεται ορίσματα, το βέλος παραλείπεται: { body() }. Εάν δέχεται ένα όρισμα και δεν το χρησιμοποιεί, αντί για βέλος γράφεται { _ -> body() } με κάτω παύλα για αγνόηση της παραμέτρου.
Ναι, κάθε lambda που μεταβιβάζεται σε μη inline συνάρτηση δημιουργεί ένα στιγμιότυπο ανώνυμης κλάσης. Για inline συναρτήσεις, το lambda εισάγεται στο σημείο κλήσης χωρίς δημιουργία αντικειμένου. Τα μη συλλαμβάνοντα (non-capturing) lambda αποθηκεύονται σε singleton αντικείμενα.
Return στο Kotlin είναι ένας τελεστής άλματος που ανήκει στην πλησιέστερη συνάρτηση με fun. Το lambda δεν είναι συνάρτηση (fun), αλλά έκφραση. Επομένως, το return εντός lambda χωρίς ετικέτα θεωρείται επιστροφή από την εξωτερική περιβάλλουσα συνάρτηση.
Σύνοψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης