← Kursa Dön
📄 Text · 15 min

Metot Kavramı ve Tanımlama

Giriş — Neden Metot?

Şimdiye kadar tüm kodunu main metodunun içine yazdın. Küçük programlar için bu sorun değil. Ama program büyüdükçe main metodu binlerce satır olur ve bir şeyi değiştirmek, bulmak, test etmek imkansız hale gelir.

Düşün: her sabah kahvaltı yapıyorsun. Ama her seferinde "ocağı aç, tavayı koy, yağı ekle, yumurtayı kır, pişir, tabağa al" diye tüm adımları tekrar yazmak yerine, buna "yumurta yap" deyip geçsen güzel olmaz mı?

Metotlar tam da bunu yapar. Tekrarlayan veya mantıksal olarak bir bütün olan kodu bir isim altında paketler. İhtiyacın olduğunda o ismi çağırırsın.

Analoji: Metotları bir restoran mutfağı gibi düşün. "Sipariş ver" diyorsun (metodu çağır), mutfak çalışıyor (metot gövdesi), tabak gelir (dönüş değeri). Mutfakta ne olduğunu bilmene gerek yok — sadece ne istediğini söylüyorsun.


Metot Tanımlama

Java'da metot tanımlamak şöyle:

erişimBelirteci static dönüşTipi metotAdi(parametreler) {
    // metot gövdesi
    return değer;  // void ise gerek yok
}

Her parçanın anlamı:

  • Erişim belirteci: public, private, vb. (şimdilik public kullanacağız, OOP dersinde detaylandıracağız)

  • `static`: main'den doğrudan çağırabilmek için (OOP öncesinde hep static kullanacağız)

  • Dönüş tipi: Metot ne tür bir değer döndürür (int, String, double, vb.)

  • Metot adı: Metodu çağırmak için kullanacağın isim

  • Parametreler: Metoda dışarıdan gönderilen veriler

  • `return`: Değeri döndürüp metottan çıkar

İlk Metot: Selamlama

public class MerhabaMetot {

    public static void selamla() {
        System.out.println("Merhaba, Java dünyasına hoş geldin!");
    }

    public static void main(String[] args) {
        selamla();  // Metodu çağır
        selamla();  // İstediğin kadar çağır
        selamla();
    }
}

selamla() metodu 3 kez çağrıldı, her seferinde aynı mesajı yazdırdı. Kodu bir kez yazdık, üç kez kullandık.

Örnek: İki Sayıyı Toplayan Metot

public static int topla(int a, int b) {
    int sonuc = a + b;
    return sonuc;
}

public static void main(String[] args) {
    int toplam = topla(5, 3);
    System.out.println("5 + 3 = " + toplam);  // 8
    
    System.out.println("10 + 20 = " + topla(10, 20));  // 30
}

topla metodu:

  • İki int parametre alıyor (a ve b)

  • int tipinde bir değer döndürüyor

  • return sonuc ile değeri geri gönderiyor


void — Değer Döndürmeyen Metotlar

Her metot bir değer döndürmek zorunda değil. Sadece bir iş yapıp biten metotlar void dönüş tipini kullanır.

public static void bilgiYazdir(String isim, int yas) {
    System.out.println("İsim: " + isim);
    System.out.println("Yaş: " + yas);
    System.out.println("---");
}

public static void main(String[] args) {
    bilgiYazdir("Ali", 25);
    bilgiYazdir("Ayşe", 30);
}

void metotlarda:

  • return yazman gerekmez (metot sonunda otomatik döner)

  • return; (değersiz) yazarak erken çıkabilirsin

public static void mesajGonder(String alici, String mesaj) {
    if (alici == null || alici.isEmpty()) {
        System.out.println("Hata: Alıcı belirtilmedi!");
        return;  // Erken çıkış — guard clause
    }
    
    System.out.println(alici + " kişisine gönderildi: " + mesaj);
}

💡 İpucu: void metotlar genellikle bir yan etki (side effect) yapar: ekrana yazdırır, dosyaya yazar, değişken günceller. Değer döndüren metotlar ise genellikle bir hesaplama yapar. İkisini karıştırma — bir metot ya hesaplasın ya da iş yapsın.


Parametreler ve Argümanlar

Bu iki terim sık karıştırılır:

  • Parametre: Metot tanımındaki değişken (formal parameter)

  • Argüman: Metodu çağırırken gönderdiğin gerçek değer (actual argument)

//            parametre  parametre
public static int topla(int a, int b) {
    return a + b;
}

//              argüman  argüman
int sonuc = topla(5, 3);

a ve b parametre, 5 ve 3 argüman.

Birden Fazla Parametre

public static double ucgenAlani(double taban, double yukseklik) {
    return taban * yukseklik / 2;
}

public static String tekrarla(String metin, int kez) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < kez; i++) {
        sb.append(metin);
    }
    return sb.toString();
}

public static void main(String[] args) {
    System.out.println("Alan: " + ucgenAlani(5.0, 3.0));  // 7.5
    System.out.println(tekrarla("Ha", 3));  // HaHaHa
}

Parametre Sırası Önemli!

public static void bilgi(String isim, int yas) { ... }

bilgi("Ali", 25);    // Doğru
bilgi(25, "Ali");    // DERLEME HATASI — tipler uyuşmuyor

Parametrelerin sırası, tanımdaki sırayla eşleşmeli.


Dönüş Tipi ve return

Metot bir değer döndürüyorsa:

  1. Dönüş tipi belirtilmeli (int, String, double, vb.)

  2. Metot gövdesinde return değer; olmalı

  3. Döndürülen değer, belirtilen tiple uyumlu olmalı

Her Yolda return Olmalı

// DERLEME HATASI — else'te return yok!
public static String notHesapla(int puan) {
    if (puan >= 50) {
        return "Geçti";
    }
    // Peki puan < 50 ise? return yok!
}

// DOĞRU
public static String notHesapla(int puan) {
    if (puan >= 50) {
        return "Geçti";
    }
    return "Kaldı";  // Her koşulda bir return var
}

Java derleyicisi tüm olası yolların bir return ifadesine ulaştığını kontrol eder. Eğer bir yol return'süz kalırsa derleme hatası verir.

return Birden Fazla Olabilir (Early Return)

public static char notHarfi(int puan) {
    if (puan >= 90) return 'A';
    if (puan >= 80) return 'B';
    if (puan >= 70) return 'C';
    if (puan >= 60) return 'D';
    return 'F';
}

İlk eşleşen return çalışır ve metottan çıkılır.

Dönüş Değerini Kullanmak Zorunda Değilsin

public static int topla(int a, int b) {
    return a + b;
}

topla(3, 5);                    // Geçerli ama dönen değer kaybolur
int sonuc = topla(3, 5);       // Değeri yakala
System.out.println(topla(3, 5)); // Değeri doğrudan kullan

Call by Value — Java'nın Parametre Geçiş Mekanizması

Java'da parametreler her zaman değer kopyalanarak (call by value) geçirilir. Bu çok önemli bir kural.

Primitive Tipler — Kopya Geçer

public static void ikiyeKatla(int sayi) {
    sayi = sayi * 2;
    System.out.println("Metot içinde: " + sayi);  // 20
}

public static void main(String[] args) {
    int x = 10;
    ikiyeKatla(x);
    System.out.println("Metot sonrası: " + x);    // 10 — değişmedi!
}

x'in kopyası metoda gönderildi. Metot kopyayı değiştirdi ama orijinal x etkilenmedi.

Bu, bir arkadaşına bir belgenin fotokopisini vermek gibi. Fotokopi üzerinde ne yaparsa yapsın, senin orijinal belgen aynı kalır.

Referans Tipler — Referansın Kopyası Geçer

public static void elemanEkle(int[] dizi) {
    dizi[0] = 999;  // Orijinal diziyi değiştirir!
}

public static void main(String[] args) {
    int[] sayilar = {1, 2, 3};
    elemanEkle(sayilar);
    System.out.println(sayilar[0]);  // 999 — değişti!
}

Durum! Dizi değişti mi? Ama "call by value" demiştik?

Açıklama: Referans tiplerinde referansın kopyası geçirilir. Yani hem sayilar hem metottaki dizi aynı diziye işaret eder. Referansı kopyalıyoruz, ama ikisi de aynı nesneye bakıyor.

public static void diziDegistir(int[] dizi) {
    dizi = new int[]{100, 200, 300};  // Yeni dizi oluşturdu
    System.out.println("Metot içinde: " + dizi[0]);  // 100
}

public static void main(String[] args) {
    int[] sayilar = {1, 2, 3};
    diziDegistir(sayilar);
    System.out.println("Metot sonrası: " + sayilar[0]);  // 1 — değişmedi!
}

Bu sefer değişmedi! Çünkü metot içinde dizi referansı yeni bir diziye yönlendirildi, ama orijinal referans (sayilar) hâlâ eski diziyi gösteriyor.

⚠️ Dikkat: Java'da call by reference yoktur. Referans tiplerinde bile referansın kopyası geçirilir. Bu, referans üzerinden nesnenin içeriğini değiştirebilirsin ama referansın kendisini (hangi nesneye baktığını) değiştiremezsin demektir.

Özet Tablo

TipMetotta DeğişiklikOrijinale Etkisi
int, double, vb.Kopyayı değiştirirYok
int[], String[]İçeriği değiştirirVar
int[], String[]Referansı yeniler (= new ...)Yok
StringImmutable, yeni nesne oluşurYok

static Metotlar

Şimdiye kadar yazdığımız tüm metotlar static idi. Peki neden?

static metotlar, sınıfa aittir, herhangi bir nesneye değil. Nesne oluşturmadan doğrudan çağırabilirsin. main metodu static olduğu için, ondan çağırdığımız metotlar da static olmalı (ya da bir nesne üzerinden çağırmalıyız).

public class Hesaplama {
    
    // static metot — sınıf üzerinden çağrılır
    public static int topla(int a, int b) {
        return a + b;
    }
    
    public static void main(String[] args) {
        // Aynı sınıf içinden — direkt çağır
        int sonuc = topla(3, 5);
        
        // Başka sınıftan — sınıf adıyla çağır
        // int sonuc = Hesaplama.topla(3, 5);
    }
}

Java'nın Kendi static Metotları

Zaten birçok static metot kullandın:

Math.sqrt(25);          // Math sınıfının static metodu
Math.max(10, 20);       // Math sınıfının static metodu
Integer.parseInt("42"); // Integer sınıfının static metodu
Arrays.sort(dizi);      // Arrays sınıfının static metodu

Hepsi sınıf adıyla çağrılıyor, nesne oluşturmana gerek yok.

static vs Instance Metotlar (Kısa Bakış)

public class Kisi {
    String isim;
    
    // instance metot — nesneye ait
    public String selamla() {
        return "Merhaba, ben " + this.isim;
    }
    
    // static metot — sınıfa ait
    public static String genelBilgi() {
        return "Bu bir Kisi sınıfıdır.";
    }
}

// Kullanım
Kisi ali = new Kisi();
ali.isim = "Ali";
ali.selamla();           // nesne üzerinden
Kisi.genelBilgi();       // sınıf üzerinden

Instance metotları OOP dersinde detaylı göreceğiz. Şimdilik static metotlarla devam ediyoruz.

💡 İpucu: OOP öncesinde tüm metotları public static olarak yaz. Bu, main'den doğrudan çağırmanı sağlar. OOP konusuna geçtiğimizde static'i ne zaman kullanıp kullanmamayı öğreneceksin.


Metot Çağırma Akışı

Bir metot çağrıldığında neler olur?

  1. Argümanlar hesaplanır ve parametrelere kopyalanır

  2. Program akışı metot gövdesine atlar

  3. Metot gövdesi çalışır

  4. `return` ifadesine ulaşılır (veya metot sonu)

  5. Dönüş değeri çağıran yere gönderilir

  6. Program akışı çağrılan yerden devam eder

public static int kareAl(int n) {
    System.out.println("kareAl çağrıldı, n=" + n);
    return n * n;
}

public static void main(String[] args) {
    System.out.println("1. satır");
    int sonuc = kareAl(5);           // → kareAl'a atla
    System.out.println("Sonuç: " + sonuc);  // kareAl'dan dön
    System.out.println("Son satır");
}

Çıktı:

1. satır
kareAl çağrıldı, n=5
Sonuç: 25
Son satır

Metotlar Birbirini Çağırabilir

public static double dikdortgenAlani(double en, double boy) {
    return en * boy;
}

public static double dikdortgenCevresi(double en, double boy) {
    return 2 * (en + boy);
}

public static void dikdortgenBilgi(double en, double boy) {
    System.out.println("En: " + en + ", Boy: " + boy);
    System.out.println("Alan: " + dikdortgenAlani(en, boy));
    System.out.println("Çevre: " + dikdortgenCevresi(en, boy));
}

public static void main(String[] args) {
    dikdortgenBilgi(5, 3);
}

dikdortgenBilgi metodu, dikdortgenAlani ve dikdortgenCevresi metotlarını çağırıyor. Metotlar birbirini çağırarak karmaşık işleri adım adım çözer.


Metot İmzası (Method Signature)

Java'da bir metot, imzası (signature) ile tanımlanır. İmza şunlardan oluşur:

  1. Metot adı

  2. Parametre tipleri ve sırası

Dönüş tipi imzanın parçası değildir!

// Bu üçü farklı imzaya sahip:
int topla(int a, int b)         // topla(int, int)
double topla(double a, double b) // topla(double, double)
int topla(int a, int b, int c)  // topla(int, int, int)

// Bu ikisi aynı imzaya sahip — DERLEME HATASI!
int topla(int a, int b)
double topla(int x, int y)  // İmza aynı: topla(int, int)

Parametre isimleri imzayı değiştirmez, sadece tipler ve sıralama önemlidir.


Pratik Örnekler

Örnek: Basit Hesap Makinesi

public static double hesapla(double a, double b, char islem) {
    return switch (islem) {
        case '+' -> a + b;
        case '-' -> a - b;
        case '*' -> a * b;
        case '/' -> {
            if (b == 0) {
                System.out.println("Hata: Sıfıra bölme!");
                yield 0;
            }
            yield a / b;
        }
        default -> {
            System.out.println("Geçersiz işlem: " + islem);
            yield 0;
        }
    };
}

public static void main(String[] args) {
    System.out.println("10 + 3 = " + hesapla(10, 3, '+'));
    System.out.println("10 / 3 = " + hesapla(10, 3, '/'));
    System.out.println("10 / 0 = " + hesapla(10, 0, '/'));
}

Örnek: Dizi İşlemleri

public static int diziBul(int[] dizi, int aranan) {
    for (int i = 0; i < dizi.length; i++) {
        if (dizi[i] == aranan) {
            return i;  // Bulunduğu index
        }
    }
    return -1;  // Bulunamadı
}

public static double diziOrtalama(int[] dizi) {
    if (dizi == null || dizi.length == 0) {
        return 0;
    }
    
    int toplam = 0;
    for (int eleman : dizi) {
        toplam += eleman;
    }
    return (double) toplam / dizi.length;
}

public static int[] diziFiltrele(int[] dizi, int esik) {
    int sayac = 0;
    for (int eleman : dizi) {
        if (eleman >= esik) sayac++;
    }
    
    int[] sonuc = new int[sayac];
    int idx = 0;
    for (int eleman : dizi) {
        if (eleman >= esik) {
            sonuc[idx++] = eleman;
        }
    }
    return sonuc;
}

public static void main(String[] args) {
    int[] notlar = {45, 78, 92, 35, 67, 88, 54};
    
    System.out.println("78'in indexi: " + diziBul(notlar, 78));
    System.out.printf("Ortalama: %.1f%n", diziOrtalama(notlar));
    
    int[] gecenler = diziFiltrele(notlar, 50);
    System.out.print("50+ notlar: ");
    for (int n : gecenler) System.out.print(n + " ");
}

Örnek: String Yardımcı Metotları

public static boolean palindromMu(String metin) {
    String temiz = metin.toLowerCase().replaceAll("[^a-z0-9ğüşıöç]", "");
    int sol = 0, sag = temiz.length() - 1;
    
    while (sol < sag) {
        if (temiz.charAt(sol) != temiz.charAt(sag)) {
            return false;
        }
        sol++;
        sag--;
    }
    return true;
}

public static String basliklaCevir(String metin) {
    if (metin == null || metin.isEmpty()) return metin;
    
    String[] kelimeler = metin.split(" ");
    StringBuilder sb = new StringBuilder();
    
    for (String kelime : kelimeler) {
        if (!kelime.isEmpty()) {
            sb.append(Character.toUpperCase(kelime.charAt(0)));
            sb.append(kelime.substring(1).toLowerCase());
            sb.append(" ");
        }
    }
    return sb.toString().trim();
}

public static void main(String[] args) {
    System.out.println(palindromMu("kayak"));      // true
    System.out.println(palindromMu("java"));        // false
    System.out.println(basliklaCevir("merhaba DÜNYA")); // Merhaba Dünya
}

Metotların Avantajları

  1. Kod tekrarını azaltır — Aynı işi yapan kodu bir kez yaz, istediğin kadar çağır

  2. OkunabilirliksiparisOnayla() yazmak 30 satır kodu okumaktan daha açıklayıcı

  3. Test edilebilirlik — Her metot bağımsız test edilebilir

  4. Bakım kolaylığı — Bir şeyi değiştirmek için tek yere bakarsın

  5. Soyutlama — Detayları gizler, büyük resmi gösterir


Call Stack — Metot Çağrı Yığını

Metotlar birbirini çağırdığında Java bir call stack (çağrı yığını) tutar. Her metot çağrısı yığına bir çerçeve (frame) ekler, metot bitince o çerçeve kaldırılır.

public static void a() {
    System.out.println("a başladı");
    b();
    System.out.println("a bitti");
}

public static void b() {
    System.out.println("b başladı");
    c();
    System.out.println("b bitti");
}

public static void c() {
    System.out.println("c başladı");
    System.out.println("c bitti");
}

public static void main(String[] args) {
    a();
}

Çıktı:

a başladı
b başladı
c başladı
c bitti
b bitti
a bitti

Call stack'in durumu:

[main] → [main, a] → [main, a, b] → [main, a, b, c]
                                   → [main, a, b]
                                   → [main, a]
                                   → [main]

⚠️ Dikkat: Call stack'in bir boyut sınırı var. Metotlar sonsuza kadar birbirini çağırırsa StackOverflowError alırsın. Bu konuyu Recursion dersinde detaylı göreceğiz.


Metot Tasarımında İlk Adımlar

İyi bir metot yazmak için şu soruları sor:

  1. Bu metot ne yapıyor? — Tek cümleyle açıklayabiliyorsan iyi tasarlanmış.

  2. Kaç parametre alıyor? — 3'ten fazla genellikle çok fazla.

  3. Ne döndürüyor? — Hesaplama metotları değer, aksiyon metotları void döndürmeli.

  4. Adı ne? — Fiille başlamalı: hesapla, bul, kontrol, yazdir.

// İYİ — adı açıklayıcı, tek iş yapıyor
public static boolean asalMi(int sayi) { ... }
public static double daireAlani(double yaricap) { ... }
public static int enBuyukBul(int[] dizi) { ... }

// KÖTÜ — ne yaptığı belirsiz, çok iş yapıyor
public static void islemYap(int[] d, String m, boolean f) { ... }

Bu konuyu Metot Tasarım İlkeleri dersinde derinlemesine işleyeceğiz.


Yaygın Hatalar

1. static Olmayan Metodu main'den Çağırmak

public class Hata {
    public int topla(int a, int b) {  // static DEĞİL!
        return a + b;
    }
    
    public static void main(String[] args) {
        topla(3, 5);  // HATA! Non-static method cannot be
                       // referenced from a static context
    }
}

Çözüm: Ya metodu static yap, ya da nesne oluştur: new Hata().topla(3, 5).

2. return Sonrası Kod Yazmak

public static int topla(int a, int b) {
    return a + b;
    System.out.println("Bitti");  // DERLEME HATASI — unreachable code
}

return'den sonra kod yazamazsın, çünkü orası ulaşılamaz (unreachable).

3. void Metotta Değer Döndürmek (veya Tam Tersi)

// HATA — void metot değer döndüremez
public static void selamla() {
    return "Merhaba";  // Derleme hatası!
}

// HATA — int metot değer döndürmeli
public static int topla(int a, int b) {
    System.out.println(a + b);
    // return yok → derleme hatası!
}

Özet

  • Metot, tekrarlayan kodu bir isim altında paketler — kodu yeniden kullanılabilir, okunabilir ve test edilebilir yapar.

  • Parametreler metoda veri gönderir, return metottan değer döndürür. void metotlar değer döndürmez.

  • Java'da call by value geçerlidir — primitive tipler kopyalanır, referans tiplerinde referansın kopyası geçer.

  • static metotlar sınıfa aittir, nesne oluşturmadan çağrılabilir. OOP öncesi her metodu static yap.

  • Metot imzası = metot adı + parametre tipleri. Dönüş tipi imzanın parçası değildir.

  • Her yolda return olmalı — Java derleyicisi bunu kontrol eder, eksik return derleme hatası verir.