---
title: 'Lambdalar ve Yüksek Mertebeden Fonksiyonlar'
source: 'https://academia.sh/tr/kurslar/kotlin/lambda-ve-yuksek-mertebeden-fonksiyonlar'
course: 'Kotlin Dili'
language: tr
updated: '2026-10-21T05:02:40+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Lambda ifadesini, `it` adını ve sondaki lambda yazımını kullanmak'
    - 'Fonksiyon tipini ve fonksiyon alan ya da döndüren yüksek mertebeden fonksiyonu yazmak'
    - 'İki lambdanın kimlik ölçütüne düştüğünü, yakalama yapmayan lambdanın ise tek nesne olduğunu ölçmek'
---

# Lambdalar ve Yüksek Mertebeden Fonksiyonlar

Lambda yazımını, fonksiyon tiplerini ve fonksiyon alan fonksiyonları tanıtır; iki lambda ifadesinin eşit olmadığını, yakalama yapmayan bir lambdanın ise tek nesne olduğunu ölçer.

Önceki derste `::plain` gibi bir fonksiyon referansının her alınışta ayrı ama eşit bir nesne verdiğini gördük. Şimdi fonksiyonu yerinde yazıyoruz. Lambda, adı olmayan bir fonksiyon değeridir; bir değişkene atanabilir, bir fonksiyona argüman olarak verilebilir ya da bir fonksiyondan döndürülebilir. Dersin sorusu önceki dersin sorusunun devamıdır: aynı gövdeye sahip iki lambda eşit midir?

## Lambda ve Fonksiyon Tipi

Lambda süslü parantez içinde yazılır: önce parametreler, ardından `->`, sonra gövde. Parametresi tek olan ve tipi bağlamdan bilinen bir lambdada parametre bildirilmez, onun yerine örtük `it` adı kullanılır. Fonksiyon tipi (function type) `(Int) -> Int` biçimindedir: parantez içinde parametre tipleri, okun ardından dönüş tipi bulunur.

Fonksiyon alan ya da fonksiyon döndüren bir fonksiyona yüksek mertebeden fonksiyon (higher-order function) denir. Son parametresi bir fonksiyon tipi olan fonksiyon çağrılırken lambda parantezin dışına yazılabilir: buna sondaki lambda (trailing lambda) denir. `inline` anahtar sözcüğü bu derste yalnız tanım olarak geçer: satır içi olarak işaretlenen bir yüksek mertebeden fonksiyonun gövdesi ve ona verilen lambda çağrı yerine derleme zamanında yerleştirilir. Bu derste `inline` ölçülmedi.

Bu derste de ölçümler ilk derste tanıtılan yardımcı dosyayla yapılır. `Criterion` sınıfı, bir değer ile ikizini ve farklı bir değeri alıp üç soruyu sorar; dosya aşağıda aynen verilmiştir.

```kotlin
// Criterion.kt — iki degeri esit yapan olcutu siniflandirir
class Criterion(val label: String, first: Any?, twin: Any?, other: Any?) {
    val sameObject = first === twin
    val equalTwin = first == twin
    val equalOther = first == other

    val name: String = when {
        sameObject -> "tekil"
        !equalTwin -> "kimlik"
        !equalOther -> "icerik"
        else -> "kismi-icerik"
    }

    fun report() {
        println("$label: ayni-nesne=$sameObject, ikiz=$equalTwin, farkli=$equalOther -> $name")
    }
}

fun summarize(checks: List<Criterion>) {
    for (name in listOf("tekil", "kimlik", "icerik", "kismi-icerik")) {
        println("$name: ${checks.count { it.name == name }}")
    }
}
```

Fonksiyon tipi sıradan bir tiptir: bir değişkenin, bir parametrenin ya da bir dönüş değerinin tipi olarak yazılabilir. `val increment: (Int) -> Int = { it + 1 }` satırında tipi açıkça yazdığımız için lambdada parametre bildirmeye gerek kalmaz ve `it` kullanılabilir. Tip yazılmadığında ise parametre lambdanın içinde `n: Int ->` biçiminde bildirilir; derleyici iki yoldan birinden parametre tipini öğrenmek zorundadır.

Aşağıdaki program bunları birlikte gösterir. `applyTwice` bir işlemi iki kez uygular, `makeAdder` ise bir fonksiyon döndürür.

```kotlin
// Main.kt — lambda, it, sondaki lambda ve fonksiyon tipi
fun applyTwice(value: Int, operation: (Int) -> Int): Int = operation(operation(value))

fun makeAdder(amount: Int): (Int) -> Int = { it + amount }

fun main() {
    val twice = { n: Int -> n * 2 }
    val increment: (Int) -> Int = { it + 1 }
    println(twice(4))
    println(applyTwice(3, increment))
    println(applyTwice(3) { it * 10 })
    val addFive = makeAdder(5)
    println(addFive(10))
    println(listOf(1, 2, 3).map { it * it })
}
```

```
8
5
300
15
[1, 4, 9]
```

`twice(4)` doğrudan bir lambdayı çağırdı ve `8` verdi. `applyTwice(3, increment)` üçe iki kez bir ekledi ve `5` çıktı. `applyTwice(3) { it * 10 }` sondaki lambda yazımıdır: üç, otuz, üç yüz; sonuç `300`. `makeAdder(5)` beş ekleyen bir fonksiyon döndürdü ve bu fonksiyon `10` üzerinde `15` verdi. Son satırda `map` her öğeye lambdayı uyguladı ve `[1, 4, 9]` çıktı.

**DT45.** `it` yalnız tek parametreli lambdalarda gösterildi; birden çok parametreli bir lambdada parametrelerin adlandırılması yalnız `twice` örneğindeki tek parametreyle sınırlı kaldı.

**DT46.** Yüksek mertebeden fonksiyonlar yalnız `Int` üzerinde ve `map` ile gösterildi; `filter`, `fold` gibi öteki koleksiyon fonksiyonları sonraki konunun işidir.

## İki Lambda Eşit Midir

Ölçüm dört gözlemden kurulur. `iki-lambda`: iki ayrı yerde yazılmış `{ 1 }` ifadesi. `ayni-cagri-noktasi`: aynı yerde yazılmış `{ 1 }` lambdasını döndüren `makeConstant` fonksiyonu, iki kez çağrılır. `yakalayan-lambda`: dış bir değişkeni, yani `amount` parametresini kullanan lambda, `makeAdderFor(1)` iki kez çağrılır. `fonksiyon-referansi`: `::inc` iki kez, önceki dersteki gözlemin bir daha tekrarı.

Yakalama (capture), bir lambdanın kendi gövdesinin dışındaki bir değişkeni kullanmasıdır. `makeAdderFor` içindeki lambda `amount` değerini yakalar; `{ 1 }` ise dışarıdan hiçbir şey yakalamaz.

```kotlin
// Main.kt — lambdalar ve kimlik
fun makeConstant(): () -> Int = { 1 }

fun makeAdderFor(amount: Int): (Int) -> Int = { it + amount }

fun inc(n: Int): Int = n + 1

fun dec(n: Int): Int = n - 1

fun main() {
    val checks = listOf(
        Criterion("iki-lambda", { 1 }, { 1 }, { 2 }),
        Criterion("ayni-cagri-noktasi", makeConstant(), makeConstant(), { 2 }),
        Criterion("yakalayan-lambda", makeAdderFor(1), makeAdderFor(1), makeAdderFor(2)),
        Criterion("fonksiyon-referansi", ::inc, ::inc, ::dec),
    )
    for (check in checks) {
        check.report()
    }
    summarize(checks)
}
```

```
iki-lambda: ayni-nesne=false, ikiz=false, farkli=false -> kimlik
ayni-cagri-noktasi: ayni-nesne=true, ikiz=true, farkli=false -> tekil
yakalayan-lambda: ayni-nesne=false, ikiz=false, farkli=false -> kimlik
fonksiyon-referansi: ayni-nesne=false, ikiz=true, farkli=false -> icerik
tekil: 1
kimlik: 2
icerik: 1
kismi-icerik: 0
```

`iki-lambda` kimliktir: ayrı yerde yazılan iki aynı gövdeli lambda eşit değildir, `ikiz=false`. `yakalayan-lambda` da kimliktir: `makeAdderFor(1)` iki kez çağrıldığında iki ayrı lambda nesnesi doğdu, aynı değeri yakalamış olsalar bile eşit değiller.

`ayni-cagri-noktasi` ise tekildir: `makeConstant()` iki çağrıda aynı nesneyi döndürdü, `ayni-nesne=true`. Bu lambda dışarıdan bir şey yakalamıyor; sandbox'ta her çağrıda aynı örnek olarak gözlendi. `fonksiyon-referansi` içeriktir, önceki dersin sonucu burada yeniden doğrulandı. Özet satırları bir tekil, iki kimlik, bir içerik ve sıfır kısmi içerik verir.

**DT47.** Yakalama yapmayan lambdanın tek nesne olması Kotlin 2.4.21'in JVM hedefinde ölçüldü; bu bir dil sözleşmesi değil, o sürümde gözlenen sonuçtur.

**DT48.** `yakalayan-lambda` gözlemi tek bir `Int` yakalamasıyla yapıldı; yakalanan değişkenin tipi ya da sayısı değiştiğinde sonucun değişmediği iddia edilmiyor.

## Yakalanan Değişken Her Yaratılışta Ayrıdır

Bir lambda kendi dışındaki bir `var` değişkenini okuyabilir ve değiştirebilir. Soru, bu değişkenin kaç kopyasının bulunduğudur. Aşağıdaki blok bir sayaç üreten fonksiyon yazar, iki ayrı sayaç kurar ve aynı sayaca iki ayrı ad verir.

```kotlin
// Main.kt — yakalanan var her yaratilista ayri
fun makeCounter(): () -> Int {
    var count = 0
    return { ++count }
}

fun main() {
    val first = makeCounter()
    val second = makeCounter()
    println(first())
    println(first())
    println(second())
    println(first())
    val shared = makeCounter()
    val alias = shared
    println(shared())
    println(alias())
}
```

```
1
2
1
3
1
2
```

`first` iki kez çağrıldı ve `1`, `2` verdi; `second` ilk çağrıda `1` verdi. İki sayaç ayrı `count` değişkenlerini yakaladı, çünkü `makeCounter` her çağrıldığında yeni bir `count` yaratılır. `first` yeniden çağrıldığında `3` bastı ve `second`'ın çağrısı bunu etkilemedi. Son iki satır `1` ve `2` verdi: `alias`, `shared` ile aynı lambda nesnesine işaret ettiği için ikisi aynı sayacı artırdı.

Kural şudur: yakalanan değişken lambda nesnesi ile birlikte yaşar ve nesne başına bir kopya vardır. Sık yapılan hata, sayacın fonksiyon her çağrıldığında sıfırlandığını sanmak ya da tüm lambdaların aynı değişkeni paylaştığını varsaymaktır. Java'da lambda yalnız fiilen yeniden atanmayan (effectively final) değişkenleri yakalayabilir, Kotlin ise `var` yakalamaya izin verir; bunun arkasında değişkenin bir referans kutusuna sarıldığı bilinir, ama bu derste ölçülmedi.

**DT49.** Sayaç ölçümü tek iş parçacığında yapıldı; birden çok iş parçacığı aynı yakalanan değişkeni artırırsa ne olduğu bu derste ölçülmedi.

## Lambdadan Dönmek

Bir lambdanın içinde `return` yazmak bazen fonksiyonu bitirir, bazen de hata verir. Aşağıdaki blok üç durumu dener: `forEach` içinde etiketsiz `return`, `forEach` içinde `return@forEach` ve `map` içinde kendi etiketi ile `return@label`.

```kotlin
// Main.kt — lambdadan donmek
fun findFirstEven(values: List<Int>): Int {
    values.forEach {
        if (it % 2 == 0) return it
    }
    return -1
}

fun main() {
    println(findFirstEven(listOf(1, 3, 4, 6)))
    println(findFirstEven(listOf(1, 3)))
    val visited = mutableListOf<Int>()
    listOf(1, 2, 3, 4).forEach {
        if (it == 2) return@forEach
        visited.add(it)
    }
    println(visited)
    val labeled = listOf(1, 2, 3).map label@{
        if (it == 2) return@label 20
        it
    }
    println(labeled)
}
```

```
4
-1
[1, 3, 4]
[1, 20, 3]
```

`findFirstEven(listOf(1, 3, 4, 6))` `4` verdi: `forEach` bir satır içi (inline) fonksiyondur, bu yüzden lambdanın içindeki `return` dış fonksiyonu bitirir ve ilk çift sayı olan 4 döner. İkinci çağrıda çift sayı olmadığı için döngü bitti ve `-1` döndü.

Üçüncü satır `[1, 3, 4]` verdi. `return@forEach` yalnız o lambda çalışmasını bitirir, yani `continue` gibi davranır: 2 atlandı, geri kalanlar eklendi. Dördüncü satır `[1, 20, 3]` verdi; `return@label` lambdanın değerini belirler, yani `map` içinde 2 değeri 20 ile değiştirildi.

Sık yapılan hata, etiketsiz `return` ile `forEach` içinde yalnız bir öğeyi atlamayı beklemektir: bu bütün fonksiyonu bitirir. Bu davranış `forEach` satır içi olduğu için mümkündür; satır içi olmayan bir lambdada etiketsiz `return` derleme hatası verir, ama bu dal ölçülmedi. Java'da lambda içindeki `return` yalnız lambdadan çıkar ve dış metodu bitirmez.

**DT50.** Dönüş davranışı `forEach` ve `map` ile ölçüldü; satır içi olmayan bir yüksek mertebeden fonksiyonda etiketsiz `return` yazılırsa verilen hata iletisi bu derste ölçülmedi.

## Alıcılı Lambda ve SAM Dönüşümü

Bazı lambdalar bir alıcı nesnenin üyelerine doğrudan erişir. Aşağıdaki blok `StringBuilder.() -> Unit` tipinde bir lambda kurar, Java arayüzü `Runnable` ve `Comparator` için lambda yazar ve iki fonksiyonu birleştiren bir lambda üretir.

```kotlin
// Main.kt — alicili lambda ve SAM donusumu
fun main() {
    val build: StringBuilder.() -> Unit = {
        append("kot")
        append("lin")
    }
    println(StringBuilder().apply(build).toString())
    val task = Runnable { println("calisti") }
    task.run()
    val byLength = Comparator<String> { a, b -> a.length - b.length }
    println(listOf("ccc", "a", "bb").sortedWith(byLength))
    val compose: ((Int) -> Int, (Int) -> Int) -> (Int) -> Int = { f, g -> { x -> g(f(x)) } }
    val doubleThenInc = compose({ it * 2 }, { it + 1 })
    println(doubleThenInc(5))
}
```

```
kotlin
calisti
[a, bb, ccc]
11
```

İlk satır `kotlin` verdi. `build` değişkeni alıcılı bir lambdadır: gövdesinde `append` doğrudan çağrılır, çünkü `this` olarak bir `StringBuilder` verilir. `apply(build)` onu yeni bir `StringBuilder` üzerinde çalıştırdı. İkinci satır `calisti`: `Runnable { ... }` yazımı, tek soyut metodu olan bir Java arayüzünü lambda ile oluşturur. Bu dönüşüme SAM dönüşümü (single abstract method) denir. Üçüncü satır `[a, bb, ccc]` verdi: `Comparator` de aynı biçimde lambda ile yazıldı ve uzunluğa göre sıralama yaptı.

Dördüncü satır `11` verdi. `compose` iki fonksiyon alıp üçüncüsünü döndürür; `doubleThenInc(5)` önce 5'i ikiyle çarpar (10), sonra bir ekler (11). Sıra önemlidir: `g(f(x))` yazıldığı için önce `f` çalışır. Sık yapılan hata, birleşimde sıranın tersini varsaymaktır.

**DT51.** SAM dönüşümü Java arayüzleriyle ölçüldü; Kotlin'de yazılmış bir arayüz için ayrı `fun interface` bildirimi gerektiği bu derste ölçülmedi.

## Ölçümlerden Çıkan Alışkanlıklar

Lambdalarla çalışırken üç soru sorulmalıdır: ne yakalanıyor, nereden dönülüyor ve hangi tip bekleniyor. Yakalama konusunda ölçüm net bir kural verdi: yakalanan değişken lambda nesnesiyle birlikte yaşar ve her yaratılışta ayrı bir kopya oluşur. Bu, sayaç ya da önbellek gibi durum taşıyan küçük nesneleri sınıf yazmadan kurmayı mümkün kılar; ama durumun nerede saklandığı kodda görünmediği için, okuyan kişi için gizli bir bağımlılıktır. Durumun uzun ömürlü ya da paylaşılan olması gerekiyorsa açık bir sınıf daha okunur olur.

Dönüş konusunda en önemli ayrım, lambdanın satır içi olup olmadığıdır. `forEach` içinde etiketsiz `return` dış fonksiyonu bitirir; ölçümde `findFirstEven` ilk çift sayıyı bulup döndü. Bu davranış kullanışlıdır, çünkü erken çıkışı döngü yazmadan ifade eder. Ama `continue` beklenen yerde yanlış kullanılırsa tüm fonksiyonu sessizce bitirir. Atlamak için `return@forEach`, değeri belirlemek için `return@label` yazılır. Okunurluk açısından, birden fazla dönüş noktası olan lambdalar küçük adlandırılmış fonksiyonlara bölünmelidir.

Tip konusunda, alıcılı lambda (`StringBuilder.() -> Unit`) gövdede `this` ile çalışır ve nesnenin üyelerine doğrudan erişir. Bu, yapı kurucu kod yazmak için (builder) temeldir ve sonraki derste kapsam fonksiyonlarının mekanizmasıdır. SAM dönüşümü ise Java arayüzlerini lambda ile kurmayı sağlar; Kotlin'de yazılmış arayüzler için `fun interface` gerekir, bu ölçülmedi.

Fonksiyonları birleştiren `compose` örneği, fonksiyonların değer olduğunu gösterir. Sıra `g(f(x))` olduğu için `f` önce çalışır ve 5 girdisi için sonuç 11 oldu. Ters sıra farklı bir sonuç verirdi, ama o hesap ölçülmedi; yalnız 11 çıktısı sandbox'tan geldi. Bu yüzden birleştirme sırasını bir örnekle sınamak yeterlidir. Fonksiyon birleştirme kütüphanelerinde bu sıra sık karıştırılır, bu yüzden küçük bir örnekle doğrulanması gerekir.

Java ile karşılaştırma: Java lambdası yalnız fiilen yeniden atanmayan değişkenleri yakalar ve `return` yalnız lambdadan çıkar. Kotlin ikisinde de daha geniş bir davranış sunar; esnekliğin bedeli, okurun hangi `return`'ün neyi bitirdiğini bilmesi gerektiğidir. Kodu gözden geçirirken her `return` için önce çevreleyen fonksiyonun satır içi olup olmadığına, sonra etiket bulunup bulunmadığına bakmak, bu belirsizliği çabuk giderir.

## Sınırlayıcı Ölçüm

Lambdalar için kimlik ölçütü iki sınırla kırılır. Birincisi yakalamadır: yakalamayan lambda çağrı yerinde tek nesne olur ve tekil çıkar, yakalayan lambda her çağrıda yeni nesne olur ve kimlik çıkar. Yani iki lambdanın eşit olup olmadığını gövdeleri değil, hangi yerde yazıldıkları ve bir şey yakalayıp yakalamadıkları belirler. İkincisi fonksiyon referansıdır: `::inc` iki kez alındığında nesneler ayrı ama eşittir.

## Özet

- Lambda `{ parametreler -> gövde }` biçiminde yazılır; tek parametre `it` adını alabilir ve son parametre bir fonksiyon tipiyse lambda parantezin dışına yazılabilir.
- Fonksiyon tipi `(Int) -> Int` biçimindedir; fonksiyon alan ya da döndüren fonksiyona yüksek mertebeden fonksiyon denir.
- Aynı gövdeli iki lambda ayrı yazıldıysa eşit değildir: kimlik. Yakalayan lambda her çağrıda yeni nesnedir.
- Yakalama yapmayan lambda aynı çağrı noktasından her seferinde aynı nesneyi verdi: tekil. `::inc` iki kez içeriktir.
- Bu dersin ölçütü: **kimlik**; sınırlayıcı ölçüm: yakalamayan lambda tekildir, `::inc` referansı içeriktir.

## Sonraki Adım

Lambdaları değer olarak taşımayı gördük. Son derste lambdayı bir nesnenin bağlamında çalıştıran beş hazır yüksek mertebeden fonksiyonu inceliyoruz: kapsam fonksiyonları. `let`, `run`, `with`, `apply` ve `also` aynı nesne üzerinde çalışır ama biri nesneyi `this`, biri `it` olarak verir; hangisinin neyi döndürdüğünü de ölçüyoruz.
