---
title: 'Fonksiyonel Arayüzler'
source: 'https://academia.sh/tr/kurslar/java-standart-kutuphane/fonksiyonel-arayuzler'
course: 'Standart Kütüphane ve Akışlar'
language: tr
updated: '2026-08-17T18:09:42+00:00'
license: 'CC BY-SA 4.0'
---

# Fonksiyonel Arayüzler

Tek soyut yöntem bir derleme zamanı sözüdür: iki yöntemli bir arayüz asla lambda hedefi olamaz, işaret yalnız bu sözü erken bozan tanımı yakalar. Arayüzün ikinci sözü — davranış — hiçbir yerde denetlenmez: tip sözü ailenin dördünde de derlenir, saflık ve yan etkisizlik sözü ise Predicate ve Function'da sessizce kırılabilir.

Önceki konunun son dersi sıra kuralını dışarıdan verilen bir nesneye taşımıştı: karşılaştırıcı,
çağıranın koleksiyona taktığı, tek yöntemli bir tipti. Kütüphane onu çağırdı, kararı vermedi.
Bu ders o nesnenin kendisine bakar — tek soyut yöntemli bir tipin, fonksiyonel arayüzün,
derleyiciye ne söylediğini ve hangi sözünün hiç kimse tarafından denetlenmediğini ölçer.

Standart kütüphanenin her satırı bir sözdür ve üç kaynaktan biri o sözü verir: arayüzün
kendisi, seçilen gerçekleştirim ya da çağıranın uyduğu bir kural. Fonksiyonel arayüzler bu
üçlünün en dar örneğidir — yalnızca bir soyut yöntem taşırlar — ve tam da bu darlık
yüzünden lambda ifadelerinin hedefi olabilirler. Bu darlığı derleyici mi tutuyor, yoksa
yalnız belgede mi duruyor? Arayüzün taşıdığı ikinci bir söz daha var: yöntemin nasıl
davranması gerektiği. O söz nerede duruyor, kim denetliyor?

## Tek Soyut Yöntem Derleme Zamanı Bir Sözdür

- **FN1** — Dört kap biçimi denenir: tek yöntemli ve iki yöntemli arayüz, her ikisi de
  `@FunctionalInterface` işaretli ve işaretsiz olarak. Kaynak metinler dersin içinde yazılır.
- **FN2** — Bir arayüzün tanımı derlenip derlenmediği ayrı, o arayüzü lambda hedefi olarak
  kullanan bir sınıfın derlenip derlenmediği ayrı ölçülür; ikisi karıştırılmaz.
- **FN3** — Derleyicinin hata iletisinin metni basılmaz; yalnız derlenip derlenmediği
  bildirilir, çünkü ölçülen şey iletinin içeriği değil kapının açık olup olmadığıdır.

```java
// Derleme.java — ortak çekirdek: verilen kaynak metni derleniyor mu
import java.io.PrintWriter;
import java.io.Writer;
import java.nio.file.*;
import java.util.spi.ToolProvider;

class Derleme {
    static boolean derlenirMi(String kaynak, String sinif) throws Exception {
        Path d = Files.createTempDirectory("olcek");
        Path k = d.resolve(sinif + ".java");
        Files.writeString(k, kaynak);
        PrintWriter bos = new PrintWriter(Writer.nullWriter());
        return ToolProvider.findFirst("javac").orElseThrow()
                .run(bos, bos, "-d", d.toString(), k.toString()) == 0;
    }
}
```

```java
// Isaret.java — @FunctionalInterface isareti neyi yakaliyor
public class Isaret {
    static final String TEK = "interface Islem { int uygula(int x); }";
    static final String TEK_ISARETLI = "@FunctionalInterface\ninterface Islem { int uygula(int x); }";
    static final String IKI = "interface Islem { int uygula(int x); int geriAl(int x); }";
    static final String IKI_ISARETLI = "@FunctionalInterface\ninterface Islem { int uygula(int x); int geriAl(int x); }";

    static final String[][] DENEMELER = {
        {"tek yontem, isaretsiz", TEK},
        {"tek yontem, isaretli", TEK_ISARETLI},
        {"iki yontem, isaretsiz", IKI},
        {"iki yontem, isaretli", IKI_ISARETLI},
    };

    public static void main(String[] args) throws Exception {
        System.out.printf("%-24s %-20s %s%n", "bicim", "tanim derleniyor mu", "lambda hedefi olabiliyor mu");
        for (String[] d : DENEMELER) {
            String ad = d[0], govde = d[1];
            boolean tanim = Derleme.derlenirMi(govde, "Islem");
            boolean lambda = tanim && Derleme.derlenirMi(
                    govde + "\nclass Kullan { Islem i = x -> x; }", "Islem");
            System.out.printf("%-24s %-20s %s%n", ad,
                    tanim ? "derlendi" : "derlenmedi",
                    !tanim ? "-" : (lambda ? "derlendi" : "derlenmedi"));
        }
    }
}
```

```
bicim                    tanim derleniyor mu  lambda hedefi olabiliyor mu
tek yontem, isaretsiz    derlendi             derlendi
tek yontem, isaretli     derlendi             derlendi
iki yontem, isaretsiz    derlendi             derlenmedi
iki yontem, isaretli     derlenmedi           -
```

Dört satırın yalnız biri tanım aşamasında düşüyor: iki yöntemli ve işaretli arayüz hiç
derlenmiyor, çünkü işaret derleyiciye "bu arayüzün tam olarak bir soyut yöntemi olsun"
demektir ve derleyici bunu kontrol eder. Geri kalan üç satırın tanımı derleniyor — işaretsiz
iki yöntemli arayüz de sıradan bir arayüz olarak geçerlidir, Java'da bir arayüzün birden çok
soyut yöntemi olması yasak değildir.

Asıl ayrım ikinci sütunda. Tek yöntemli arayüzlerin ikisi de — işaretli olsun olmasın --
lambda hedefi olabiliyor. İki yöntemli, işaretsiz arayüz ise tanımı geçse bile lambda hedefi
**olamıyor**: `x -> x` ifadesi hangi yönteme karşılık geldiğini belirtmiyor, derleyici bunu
çözemiyor. İşaretin yaptığı ile yapmadığı burada ayrılıyor.

## İşaret Garantiyi Eklemez, Erken Yakalar

Tablo tek bir sonucu doğruluyor: bir arayüzün lambda hedefi olabilmesi **yapısal** bir
niteliktir — tam olarak bir soyut yöntem taşımak — ve bu nitelik işaretten bağımsız var
olur ya da olmaz. İki yöntemli, işaretsiz arayüz de tanım olarak derleniyor ama zaten
fonksiyonel değildi; yalnızca bunu kimse söylemedi, ta ki biri onu lambda ile kullanmaya
çalışana kadar. O andaki hata, arayüzün tanımlandığı satırdan uzakta, kullanıldığı her
noktada ayrı ayrı çıkar.

İşaret bu uzaklığı kapatıyor. İki yöntemli ve işaretli arayüz derleme **anında** düşüyor --
kullanımı beklemeden, tanımın kendisinde. İşaretin verdiği söz "bu arayüz fonkiyoneldir"
değil, "bu arayüz fonksiyonel olmaktan çıkarsa bana burada söyle" sözüdür. Garantiyi
**arayüz** zaten kendi yapısıyla veriyordu; işaret yalnız o garantinin bozulduğu anı, kullanım
yerine değil tanım yerine taşıyor. Standart kütüphanedeki `Runnable`, `Comparator`,
`Predicate` gibi tipler bu işareti taşır, ama işareti silseniz bile hâlâ birer soyut
yöntemli arayüzdürler ve hâlâ lambda hedefi olurlar — işaret onları fonksiyonel yapmaz,
yalnız bozulmalarını erkenden yakalar.

Nesneye Dayalı Java kursunda derleyicinin reddettiği dört şey sayılmıştı: erişim belirteci,
`final`, denetlenen istisna, tip parametresi. Tek soyut yöntem kuralı bu listeye eklenen
beşinci bir koruma değil, aynı korumanın standart kütüphaneye taşınmış hâlidir — burada da
derleyici bir yapıyı kabul etmiyor ve bunu tanım satırında bildiriyor. Ama bu korumanın
kapsamı dardır: yalnız arayüzün *şekline* bakar, kaç yöntem olduğuna. Şeklin arkasındaki
sözün ne olduğuna hiç bakmaz — ve bu ayrım aşağıdaki ölçümde ortaya çıkıyor.

Şeklin kendisi de sanıldığından daha az şey taşır. Nesneye Dayalı Java kursunda bir sınıfın
bir arayüzü uygulaması **adla** kurulur: `implements` satırında arayüzün adı geçer. Lambda
ifadesi bu adı hiç yazmaz; derleyici hedefin adına değil, yalnız biçimine bakar.

```java
// Yapisal.java — ayni lambda, birbirinden habersiz iki fonksiyonel arayuzun hedefi olabiliyor mu
public class Yapisal {
    static final String IKI_ARAYUZ = """
        interface Katlayici { int uygula(int x); }
        interface Donusturucu { int uygula(int x); }
        class Kullan {
            Katlayici k = x -> x * 3;
            Donusturucu d = x -> x * 3;
        }
        """;

    public static void main(String[] args) throws Exception {
        System.out.println("iki ayrı, birbirini bilmeyen arayuz, ayni govdeli lambda: "
                + (Derleme.derlenirMi(IKI_ARAYUZ, "Katlayici") ? "derlendi" : "derlenmedi"));
    }
}
```

```
iki ayrı, birbirini bilmeyen arayuz, ayni govdeli lambda: derlendi
```

`Katlayici` ile `Donusturucu` birbirini hiç bilmiyor, aralarında ne kalıtım var ne ortak bir
üst tip — ikisi de yalnızca aynı biçimde bir soyut yöntem taşıyor. Aynı lambda ifadesi ikisi
için de derleniyor. Bu, arayüzü uygulayan bir sınıfın davranışından ayrılır: orada ad
bağlayıcıdır, burada biçim yeterlidir. Derleyicinin denetlediği söz, tam olarak bu kadar
dardır — ne isim ne köken, yalnız parametre sayısı, parametre tipleri ve dönüş tipi.

## Varsayılan, Statik ve Object Yöntemleri Sayılmaz

Tek soyut yöntem kuralı "tek yöntem" değil, "tek **soyut** yöntem" der. Bir arayüz varsayılan
gövdeli (`default`) ya da statik yöntemler taşıyabilir, bunlar soyut sayılmaz ve saymaya
girmez — çünkü çağıran onları uygulamak zorunda değildir, kütüphane onları zaten yazmıştır.

- **FN4** — İki kap denenir: biri bir soyut yöntemin yanına bir `default` ve bir `static`
  yöntem ekler; öteki bir soyut yöntemin yanına `Object` sınıfının kendi yöntemlerinden
  ikisini (`equals`, `toString`) soyut olarak yeniden bildirir. İkisi de `@FunctionalInterface`
  işaretlidir.
- **FN5** — Her iki kap için de hem tanımın derlenip derlenmediği hem lambda hedefi
  olabilip olmadığı ayrı ayrı ölçülür.

```java
// Sayilmaz.java — varsayilan, statik ve Object yontemleri soyut sayaca girmiyor mu
public class Sayilmaz {
    static final String COK_UYELI = """
        @FunctionalInterface
        interface Islem {
            int uygula(int x);
            default int ikiKat(int x) { return uygula(x) * 2; }
            static Islem ozdeslik() { return x -> x; }
        }
        """;

    static final String OBJECT_IMZALI = """
        @FunctionalInterface
        interface Islem {
            int uygula(int x);
            boolean equals(Object o);
            String toString();
        }
        """;

    public static void main(String[] args) throws Exception {
        System.out.println("bir soyut + iki varsayilan/statik yontem : "
                + (Derleme.derlenirMi(COK_UYELI, "Islem") ? "derlendi" : "derlenmedi"));
        System.out.println("bir soyut + Object'in iki yontemi        : "
                + (Derleme.derlenirMi(OBJECT_IMZALI, "Islem") ? "derlendi" : "derlenmedi"));

        boolean lambdaCokUyeli = Derleme.derlenirMi(
                COK_UYELI + "\nclass K { Islem i = x -> x; }", "Islem");
        boolean lambdaObjectImzali = Derleme.derlenirMi(
                OBJECT_IMZALI + "\nclass K { Islem i = x -> x; }", "Islem");
        System.out.println("ilkinde lambda hedefi olabiliyor mu       : "
                + (lambdaCokUyeli ? "derlendi" : "derlenmedi"));
        System.out.println("ikincisinde lambda hedefi olabiliyor mu   : "
                + (lambdaObjectImzali ? "derlendi" : "derlenmedi"));
    }
}
```

```
bir soyut + iki varsayilan/statik yontem : derlendi
bir soyut + Object'in iki yontemi        : derlendi
ilkinde lambda hedefi olabiliyor mu       : derlendi
ikincisinde lambda hedefi olabiliyor mu   : derlendi
```

Dört satır da derleniyor. İlk kap beklenen bir sonuç veriyor: `ikiKat` ve `ozdeslik`
soyut değildir, birer gövdeleri vardır, sayaca girmezler — arayüz hâlâ tek soyut yöntemlidir
ve işaret buna itiraz etmez. İkinci kap daha az sezgiseldir: `equals` ve `toString` soyut
olarak yeniden bildirilmiş olsalar bile derleyici onları saymaz, çünkü ikisi de `Object`
sınıfının **herkese açık** bir yöntemiyle eşleşir ve her gerçekleştirim `Object`'ten miras
aldığı için bu yöntemleri zaten dolaylı olarak sağlar. Kural üç soyut bildirimi değil, üç
bildirimden **ikisinin zaten `Object`'te karşılığı olduğunu** görür ve yalnız `uygula`'yı
sayar.

Bu ölçüm, tek soyut yöntem kuralının söylediğinden biraz daha dar bir kural olduğunu
gösteriyor: sayılan şey "arayüzdeki soyut bildirim sayısı" değil, "arayüzün her
gerçekleştirimin **yeniden** yazmak zorunda kalacağı yöntem sayısı"dır. `Object`'in
yöntemleri zaten her sınıfta vardır, o yüzden yeniden yazma yükümlülüğüne girmezler. Önceki
konudan tanıdık bir örnek burada açıklığa kavuşuyor: `Comparator<T>` bir düzine civarında
`default` ve `static` yöntem taşır (`reversed`, `thenComparing`, `naturalOrder`) ve yine de
fonksiyoneldir, çünkü çağıranın yeniden yazması gereken tek yer `compare` kalır. Üye
sayısıyla soyut yöntem sayısı aynı şey değildir.

## Arayüzün Davranış Sözü Hiçbir Yerde Denetlenmez

Bir fonksiyonel arayüzün iki ayrı sözü vardır. Birincisi imzadır — kaç parametre, hangi
tipte, ne döndürüyor — ve bu söz yukarıdaki tablolarda ölçüldüğü gibi derleme zamanında
tutuluyor. İkincisi davranıştır: `Predicate` "aynı girdiye aynı sonucu ver", `Function`
"yan etki yaratma" bekler. Bu ikinci söz hangi katmanda duruyor?

- **FN6** — Standart ailenin dört üyesi örnek alınır: `Predicate`, `Function`, `Supplier`,
  `Consumer`. Ailenin geri kalanı aynı örüntüyü izler.
- **FN7** — Saflık ihlali bir çağrı sayacıyla, yan etki ihlali bir biriktiriciyle gözle
  görülür kılınır; ikisi de yalnızca bu ölçüm için yazılmış yardımcı durumdur.

```java
// Anlam.java — arayuzun tip sozu ile davranis sozu ayni yerde denetlenmiyor
import java.util.function.*;

public class Anlam {
    static int cagriSayaci = 0;

    public static void main(String[] args) {
        Predicate<Integer> p = x -> x > 0;
        Function<Integer, Integer> f = x -> x * 2;
        Supplier<Integer> s = () -> 42;
        Consumer<Integer> c = x -> { };
        System.out.println("dort tip sozu de eslesti, dordu de derlendi");
        System.out.println();

        Predicate<Integer> kararsiz = x -> { cagriSayaci++; return cagriSayaci == 1; };
        System.out.printf("ayni girdiyle ilk cagri   : %s%n", kararsiz.test(5));
        System.out.printf("ayni girdiyle ikinci cagri: %s%n", kararsiz.test(5));

        StringBuilder gunluk = new StringBuilder();
        Function<Integer, Integer> yanEtkili = x -> { gunluk.append(x).append(','); return x + 1; };
        yanEtkili.apply(1);
        yanEtkili.apply(2);
        System.out.printf("yan etki biriktirdi mi   : %s%n", !gunluk.isEmpty());
    }
}
```

```
dort tip sozu de eslesti, dordu de derlendi

ayni girdiyle ilk cagri   : true
ayni girdiyle ikinci cagri: false
yan etki biriktirdi mi   : true
```

İlk satır tip sözünün nerede durduğunu tekrar doğruluyor: dört değişken de kendi arayüzünün
imzasına uydu, derleyici bunu denetledi ve dördü de derlendi. Geri kalan üç satır ikinci
sözü sınıyor. `kararsiz` adlı `Predicate`, aynı girdiye (**5**) iki ayrı çağrıda iki ayrı
sonuç veriyor — önce `true`, sonra `false` — ve derleyici buna hiç karışmadı, çalışma
zamanı da bir istisna düşürmedi. `yanEtkili` adlı `Function` çağrıldıkça kendi kapsamının
dışındaki bir `StringBuilder`'a yazıyor; bu da ne derlenirken ne çalışırken engellendi.

Sonuç sessizdir: `Predicate.test` "aynı girdiye aynı sonucu ver" demez diye bir istisna
fırlatmaz, yalnızca yanlış davranan bir uygulamayı olduğu gibi çalıştırır. Ailenin tip sözü
yukarıdaki ilk satırda doğrulandı: dört üyenin dördü de kendi imzasına uydu, dördü de
derlendi. Davranış sözü ise ailede eşit dağılmaz. `Predicate` ve `Function` için saflık ve
yan etkisizlik gerçek birer belge sözüdür ve az önce ikisi de kırıldı, ikisi de sessiz
kaldı — derleyici karışmadı, çalışma zamanı bir istisna düşürmedi. `Supplier` için belge
daha da gevşektir: her çağrıda aynı ya da farklı bir değer üretmesi konusunda **hiçbir
zorunluluk yoktur**, yani orada kırılacak bir söz bile bulunmaz. `Consumer` ise tam tersi
yönde kuruludur — amacı zaten yan etkidir, belge onu bir kusur saymaz, bir söz gibi
davranmaz. Tabloya sığan tek genel kural şudur: derleyici tip sözünü ailenin **dördünde de**
eksiksiz tutar; davranış sözü ailede tektip değildir ve tutulduğu yerlerde bile hiçbir
katman onu denetlemez.

Bu, önceki dersle (Karşılaştırma ve Sıralama) kurulan bir gözlemin tekrarıdır ama farklı bir
yerde: orada geçişli olmayan bir karşılaştırıcının küçük girdide sessizce yanlış sıra
ürettiği ölçülmüştü. Burada aynı sessizlik, sıralamadan çok daha küçük ve çok daha sık
kullanılan bir yüzeyde — tek satırlık bir lambda ifadesinde — ortaya çıkıyor. Fonksiyonel
arayüz ne kadar dar olursa olsun, darlığın kendisi bir davranış garantisine dönüşmüyor.

## Özet

- Bir arayüzün lambda hedefi olabilmesi yapısal bir koşuldur: tam olarak bir soyut yöntem.
  Bu koşul derleme zamanında tutulur, işaretten bağımsızdır.
- `@FunctionalInterface` işareti garanti eklemez; yalnız bu yapısal koşulun ihlalini,
  kullanım yerine değil tanım yerine taşıyarak erken yakalar.
- İki yöntemli, işaretsiz bir arayüz de derlenir ama lambda hedefi olamaz — fonksiyonel
  olmama hâli işaret olmadan da geçerlidir, yalnız daha geç fark edilir.
- Fonksiyonel arayüzlerin ikinci bir sözü vardır: davranış (saflık, yan etkisizlik). Bu söz
  ne derleyicide ne çalışma zamanında denetlenir; ihlali sessizdir, istisna düşürmez.
- Standart ailenin tip sözü dört üyede de derleyicide durur; davranış sözü ailede tektip
  değildir — `Predicate` ve `Function`'da kırılabilir ve kırıldığında sessiz kalır,
  `Supplier`'da böyle bir söz belgede bile yoktur.

## Sonraki Adım

Bu ders fonksiyonel arayüzün kendisine baktı: tek soyut yöntemin nerede tutulduğunu, ikinci
sözün nerede tutulmadığını. Bir lambda ifadesi yazıldığında bu tip yerinde bir şey daha
yapar: çevresindeki adları **yakalar**. Sıradaki ders o tipin yerinde yazıldığında neyi
yakaladığını ölçer — yerel bir değişkenle bir alanın yakalanması aynı kısıta mı bağlıdır,
ve ikisi aynı sonucu mu üretir.
