Bölüm 3.2: Fonksiyonlar

Java ile Nesne Yönelimli Programlama
Tanım ve çağrıParametre ve dönüş değeriÇağrı yığınıAşırı yükleme Hazır Java metotlarıKapsamSoyutlama ve tasarım
Sercan KÜLCÜ · Giresun Üniversitesi · Elektrik-Elektronik Mühendisliği

Giriş

Öğrenme Çıktıları

Tanımlamak ve çağırmak

Erişim belirleyici, dönüş tipi, ad ve parametre listesiyle bir metot yazmak; argümanlarla çağırıp dönüş değerini kullanmak.

Çalışmayı izlemek

Çağrı yığınında (call stack) çerçevelerin nasıl açılıp kapandığını, argümanların değer olarak kopyalandığını adım adım göstermek.

Aşırı yükleme

Aynı adlı metotları parametre listesiyle ayırmak; derleyicinin hangi sürümü seçtiğini argüman tiplerinden öngörmek.

Hazır metotlar

System.out ve Math metotlarını doğru kullanmak; Java kütüphanesinin sık kullanılan sınıflarını ve paketlerini tanımak.

Kapsam

Yerel değişkenlerin, sınıf alanlarının ve iç içe blokların kapsamını ve yaşam süresini açıklamak.

Tasarım

Soyutlama, genelleme, DRY ve tek sorumluluk ilkeleriyle iyi metot tasarlamak; problemi metotlara bölmek.

Fonksiyon Kavramı

Fonksiyon Nedir?

Fonksiyon (function), bir işi yapan, adı olan ve tekrar tekrar kullanılabilen kod parçasıdır. Java'da fonksiyonlar her zaman bir sınıfın içinde yazılır ve metot (method) adını alır.

  • Aldığı parametreler ve dönüş değeri tipi ile tanımlanır.
  • Kodun okunabilirliğini artırır, kod tekrarını azaltır.
  • Modüler ve düzenli kod yazmayı teşvik eder.
  • Programı küçük, yönetilebilir parçalara ayırır.
Benzetme: yemek tarifi

"Çay demle" bir tariftir: bir kez yazılır, istendiği kadar uygulanır. Malzemeler parametre, ortaya çıkan çay dönüş değeridir. Tarifi kullanan, her adımı yeniden düşünmek zorunda kalmaz.

Şimdiye kadar yazdığımız main da bir metottur; System.out.println(...) ise hazır bir metot çağrısıdır.

Fonksiyon Kavramı

Girdi – İşlem – Çıktı

Her fonksiyon üç aşamada düşünülebilir:

Girdi (Input) sayi1 = 5sayi2 = 3 İşlem (Process) toplama(...) sonuc = sayi1 + sayi2 Çıktı (Output) return 8 ne üzerinde çalışılacak? belirli bir görevi yerine getirir sonuç geri döndürülür
Girdi

Fonksiyona veri sağlanır: parametreler. Fonksiyonun ne üzerinde çalışacağını belirler.

İşlem

Fonksiyon, gövdesindeki deyimlerle girdiyi işler ve belirli bir görevi yerine getirir.

Çıktı

İşlem sonunda bir sonuç üretilir ve return ile çağırana geri döndürülür.

Matematikteki f(x) = x² gibi: x girdi, kare alma işlem, x² çıktıdır. Bazı fonksiyonların girdisi ya da çıktısı olmayabilir (void).

Tanım ve Çağrı

Fonksiyon Tanımı

public int toplama (int sayi1, int sayi2) { erişimbelirleyici dönüştipi metot adı parametre listesi (tip + ad) imza (signature) = ad + parametre tipleri int sonuc = sayi1 + sayi2; return sonuc; } gövde(kod bloğu) ← sonucu geri döndür
publicErişim belirleyici (access modifier): metodu kimlerin çağırabileceğini söyler.
intDönüş değeri tipi: metodun geri vereceği değerin tipi; değer döndürmüyorsa void.
toplamaMetot adı: fiil ya da fiil öbeği, küçük harfle başlar (camelCase).
(int sayi1, int sayi2)Parametreler: metodun girdileri; her birinin tipi ve adı yazılır.
{ ... }Kod bloğu (gövde): metot çağrıldığında çalışacak deyimler.

toplama metodu, sayi1 ve sayi2 adlı iki girdi parametresi alır, bunları toplar ve sonucu geri döndürür.

Tanım ve Çağrı

Fonksiyon Çağırma

public class ToplamaOrnegi {
    public static int toplama(int sayi1, int sayi2) {
        int sonuc = sayi1 + sayi2;
        return sonuc;
    }

    public static void main(String[] args) {
        int sonuc = toplama(5, 3);
        System.out.println("Toplam: " + sonuc);
    }
}
Çıktı
Toplam: 8
  • toplama(5, 3) bir çağrıdır (call): program akışı metoda gider, metot bitince çağrının yapıldığı yere geri döner.
  • Çağrıdaki 5 ve 3 argümandır (argument); tanımdaki sayi1, sayi2 ise parametredir (parameter).
  • Çağrı 8 değerini döndürür; bu değer sonuc değişkenine atanır.
  • Argüman sayısı, sırası ve tipleri parametrelerle uyuşmalıdır.
  • static: metot nesne oluşturmadan, doğrudan main'den çağrılabilir.

Tanım ve Çağrı · Adım adım kod izleme

Çağrı ve Dönüş: Adım Adım

Yığın (stack)main()

Program her zaman main metodundan başlar. Yığında yalnızca main çerçevesi vardır.

Yığın (stack)toplama(5, 3)sayi15sayi23main()sonuc?

toplama(5, 3) çağrılır: yeni bir çerçeve (frame) açılır, argümanlar parametrelere kopyalanır.

Yığın (stack)toplama(5, 3)sayi15sayi23sonuc8main()sonuc?

Gövde çalışır: sonuc = 5 + 3 = 8. Bu sonuc, toplama'nın yerel değişkenidir.

Yığın (stack)toplama(5, 3)sayi15sayi23sonuc8main()sonuc?

return sonuc; 8 değerini çağırana gönderir ve metodu bitirir; çerçeve yığından silinir.

Yığın (stack)main()sonuc8

Akış çağrının yapıldığı satıra döner: dönen 8, main'in sonuc değişkenine atanır. İki sonuc farklı değişkenlerdir.

Yığın (stack)main()sonuc8

println de bir metot çağrısıdır: ekrana Toplam: 8 yazılır.

static int toplama(int sayi1, int sayi2) {
  int sonuc = sayi1 + sayi2;
  return sonuc;
}

public static void main(String[] args) {
  int sonuc = toplama(5, 3);
  System.out.println("Toplam: " + sonuc);
}

Tanım ve Çağrı

Örnek Fonksiyonlar

public class OrnekFonksiyonlar {
    // Toplama fonksiyonu
    public static int toplama(int sayi1, int sayi2) {
        return sayi1 + sayi2;
    }
    // Kare hesaplama fonksiyonu
    public static double kareHesapla(double sayi) {
        return sayi * sayi;
    }
    // Merhaba dünya fonksiyonu
    public static void merhabaDunya() {
        System.out.println("Merhaba, Dünya!");
    }

    public static void main(String[] args) {
        System.out.println(toplama(2, 7));
        System.out.println(kareHesapla(1.5));
        merhabaDunya();
    }
}
Çıktı
9
2.25
Merhaba, Dünya!
MetotGirdiÇıktı
toplama2 × intint
kareHesapla1 × doubledouble
merhabaDunyayokyok (void)

Değer döndüren metodun sonucu bir ifadede kullanılır; void metot ise tek başına bir deyim olarak çağrılır.

Tanım ve Çağrı

return ve void

  • return ifade; değeri çağırana verir ve metodu hemen bitirir; sonraki satırlar çalışmaz.
  • Dönen değerin tipi, bildirilen dönüş tipiyle uyumlu olmalıdır (int → double genişlemesi serbesttir).
  • Değer döndüren metotta her yol bir return ile bitmelidir; yoksa derleyici missing return statement der.
  • void metot değer döndürmez; erken çıkmak için tek başına return; yazılabilir.
public class Erken {
    static void bolumYazdir(int bolunen, int bolen) {
        if (bolen == 0) {
            System.out.println("Sıfıra bölünemez!");
            return;                      // metottan hemen çık
        }
        System.out.println(bolunen / bolen);
    }
    public static void main(String[] args) {
        bolumYazdir(10, 2);
        bolumYazdir(7, 0);
    }
}
Çıktı
5
Sıfıra bölünemez!

Tanım ve Çağrı

static ve Nesne Üzerinden Çağrı

static metot
static int toplama(int sayi1, int sayi2) {
    return sayi1 + sayi2;
}
// main içinde, doğrudan:
int sonuc = toplama(5, 3);

static metot sınıfa aittir; nesne gerekmez. Başka sınıftan SinifAdi.metot() biçiminde çağrılır: Math.sqrt(16) gibi.

nesne (örnek) metodu
public class Hesap {
    int toplama(int sayi1, int sayi2) {
        return sayi1 + sayi2;
    }
    public static void main(String[] args) {
        Hesap hesap = new Hesap();
        int sonuc = hesap.toplama(5, 3);
        System.out.println(sonuc);  // 8
    }
}

static olmayan metot bir nesne üzerinden çağrılır: önce new ile nesne oluşturulur, sonra hesap.toplama(5, 3).

Tanımda static yokken main'den doğrudan toplama(5, 3) yazmak derleme hatasıdır:
non-static method toplama(int,int) cannot be referenced from a static context

Tanım ve Çağrı · Adım adım kod izleme

Değer ile Aktarım (Pass by Value)

Metot, kendisine verilen değişkeni değiştirebilir mi?

Yığın (stack)main()sayi5

main'de sayi = 5.

Yığın (stack)arttir(5)sayi5main()sayi5

Çağrıda değerin kopyası (5) gönderilir. arttir'in sayi'si ayrı bir kutudur; adlarının aynı olması önemsizdir.

Yığın (stack)arttir(5)sayi15main()sayi5

Yalnızca kopya değişir: arttir'deki sayi 15 olur, main'deki hâlâ 5.

Yığın (stack)arttir(5)sayi15main()sayi5

arttir içinde 15 yazılır.

Yığın (stack)main()sayi5

arttir bitti, çerçevesi ve kopyası silindi. main'deki sayi 5 kaldı: Java argümanları değer ile aktarır (pass by value).

static void arttir(int sayi) {
  sayi = sayi + 10;
  System.out.println("arttir: " + sayi);
}

public static void main(String[] args) {
  int sayi = 5;
  arttir(sayi);
  System.out.println("main: " + sayi);
}

Tanım ve Çağrı · Adım adım kod izleme

Referansın Kopyası: Kodu Adım Adım İzle

çağrı yığınıheapmaina12

a bir referans: dizi nesnesi heap'te durur, a onun adresini tutar.

çağrı yığınıheapmainax112

x = 1: ilkel değer doğrudan çerçevede saklanır.

çağrı yığınıheapmainax112degistirdx1

Çağrı: d'ye a'daki referansın kopyası, x'e 1'in kopyası verilir. d ve a aynı diziyi gösterir.

çağrı yığınıheapmainax1502degistirdx1

d[0] = 50: ortak dizi değişir; main da bu değişikliği görecek.

çağrı yığınıheapmainax1502degistirdx50

x = 50: yalnızca degistir'in kopyası değişir.

çağrı yığınıheapmainax1502degistirdx5000

d = new int[2]: d artık yeni bir diziyi gösterir. a etkilenmez; bağ koptu.

çağrı yığınıheapmainax1502degistirdx50050

d[1] = 50 yeni diziye yazılır; main'in dizisi değişmez.

çağrı yığınıheapmainax1502

Metot bitti; çerçevesi silindi. Yeni dizi artık hiçbir referansla gösterilmiyor (çöp toplayıcı temizleyecek).

çağrı yığınıheapmainax1502

50 2 1: dizinin içeriği değişti, x değişmedi. Java her şeyi değerle aktarır; referans da kopyalanan bir değerdir.

static void degistir(int[] d, int x) {
    d[0] = 50;
    x = 50;
    d = new int[2];
    d[1] = 50;
}

public static void main(String[] args) {
    int[] a = {1, 2};
    int x = 1;
    degistir(a, x);
    System.out.println(a[0] + " " + a[1] + " " + x);
}

Tanım ve Çağrı

Metot Aşırı Yükleme

public class AsiriYukleme {
    static int topla(int a, int b) {
        return a + b;
    }
    static double topla(double a, double b) {
        return a + b;
    }
    static int topla(int a, int b, int c) {
        return a + b + c;
    }

    public static void main(String[] args) {
        System.out.println(topla(2, 3));
        System.out.println(topla(2.5, 1.2));
        System.out.println(topla(1, 2, 3));
    }
}
Çıktı
5
3.7
6

Aşırı yükleme (overloading): aynı adlı birden fazla metot, parametre listeleri farklı olduğu sürece aynı sınıfta bulunabilir.

  • Farklılık: parametre sayısı, tipi ya da sırası.
  • Derleyici, çağrıdaki argümanlara bakarak hangi metodun çalışacağına derleme zamanında karar verir.
  • Yalnızca dönüş tipi farklı olan iki metot aşırı yükleme değildir: method topla(int,int) is already defined hatası verir.
  • println da aşırı yüklenmiştir: println(int), println(String), println(double)…

Tanım ve Çağrı · Adım adım kod izleme

Hangi topla Çalışır? Adım Adım

topla(4, 6)argümanlar: int, inttopla(int, int)✓ tam eşleşmetopla(double, double)✓ genişletmeyle uyartopla(int, int, int)✗ sayı tutmuyor

Aynı adlı üç topla var. İlk çağrının argümanları (int, int): üç parametreli sürüm elenir; (int, int) tam eşleşme olduğu için o seçilir.

topla(4, 6)argümanlar: int, inttopla(int, int)✓ tam eşleşmea = 4, b = 6topla(double, double)✓ genişletmeyle uyartopla(int, int, int)✗ sayı tutmuyor

topla(int, int) çalışır: a = 4, b = 6.

topla(4, 6)argümanlar: int, inttopla(int, int)✓ tam eşleşmedönüş: 10topla(double, double)✓ genişletmeyle uyartopla(int, int, int)✗ sayı tutmuyor

10 döner ve yazdırılır.

topla(4, 2.5)argümanlar: int, doubletopla(int, int)✗ 2.5 int olamaztopla(double, double)✓ 4 → 4.0topla(int, int, int)✗ sayı tutmuyor

(int, double): 2.5 int'e örtük dönüşemez, (int, int) elenir. 4, 4.0'a genişletilir → topla(double, double).

topla(4, 2.5)argümanlar: int, doubletopla(int, int)✗ 2.5 int olamaztopla(double, double)✓ 4 → 4.0a = 4.0, b = 2.5topla(int, int, int)✗ sayı tutmuyor

a = 4.0, b = 2.5: parametreler double.

topla(4, 2.5)argümanlar: int, doubletopla(int, int)✗ 2.5 int olamaztopla(double, double)✓ 4 → 4.0dönüş: 6.5topla(int, int, int)✗ sayı tutmuyor

6.5 döner ve yazdırılır.

topla(7, 1, 2)argümanlar: int, int, inttopla(int, int)✗ sayı tutmuyortopla(double, double)✗ sayı tutmuyortopla(int, int, int)✓ tam eşleşme

Üç argüman: yalnızca üç parametreli sürüm uyar.

topla(7, 1, 2)argümanlar: int, int, inttopla(int, int)✗ sayı tutmuyortopla(double, double)✗ sayı tutmuyortopla(int, int, int)✓ tam eşleşmea = 7, b = 1, c = 2

a = 7, b = 1, c = 2.

topla(7, 1, 2)argümanlar: int, int, inttopla(int, int)✗ sayı tutmuyortopla(double, double)✗ sayı tutmuyortopla(int, int, int)✓ tam eşleşmedönüş: 10

10 döner ve yazdırılır.

topla('A', 1)argümanlar: char, inttopla(int, int)✓ 'A' → 65topla(double, double)✓ genişletmeyle uyartopla(int, int, int)✗ sayı tutmuyor

(char, int): char hem int'e hem double'a genişleyebilir; derleyici en özel olanı, (int, int)'i seçer.

topla('A', 1)argümanlar: char, inttopla(int, int)✓ 'A' → 65a = 65, b = 1topla(double, double)✓ genişletmeyle uyartopla(int, int, int)✗ sayı tutmuyor

'A' → 65: a = 65, b = 1.

topla('A', 1)argümanlar: char, inttopla(int, int)✓ 'A' → 65dönüş: 66topla(double, double)✓ genişletmeyle uyartopla(int, int, int)✗ sayı tutmuyor

66 döner ve yazdırılır. Seçim derleme zamanında, yalnızca argüman tiplerine bakılarak yapılır.

static int topla(int a, int b) {
    return a + b;
}
static double topla(double a, double b) {
    return a + b;
}
static int topla(int a, int b, int c) {
    return a + b + c;
}
public static void main(String[] args) {
    System.out.println(topla(4, 6));
    System.out.println(topla(4, 2.5));
    System.out.println(topla(7, 1, 2));
    System.out.println(topla('A', 1));
}

Fonksiyon İçinde Fonksiyon

Fonksiyon İçinde Fonksiyon

public class IcIce {
    public static int kareAl(int sayi) {
        return sayi * sayi;
    }
    public static int topla(int sayi1, int sayi2) {
        return sayi1 + sayi2;
    }
    public static int ikiKareToplami(int sayi1, int sayi2) {
        return topla(kareAl(sayi1), kareAl(sayi2));
    }
    public static void main(String[] args) {
        int sonuc = ikiKareToplami(3, 4);
        System.out.println(sonuc);
    }
}
Çıktı
25
  • Bir fonksiyon, başka bir fonksiyonu çağırabilir.
  • Karmaşık görev küçük parçalara bölünür: ikiKareToplami, işi kareAl ve topla'ya yaptırır.
  • Kod okunabilir ve yönetilebilir olur; her parça ayrı ayrı test edilebilir.
  • topla(kareAl(sayi1), kareAl(sayi2)) ifadesinde önce argümanlar hesaplanır (soldan sağa), sonra dış çağrı yapılır.
3² + 4² = 9 + 16 = 25.

Fonksiyon İçinde Fonksiyon · Adım adım kod izleme

ikiKareToplami(3, 4): Çağrı Yığını

Yığın (stack)main()sonuc?

main, ikiKareToplami(3, 4) çağrısını yapar.

Yığın (stack)ikiKareToplami(3, 4)sayi13sayi24main()sonuc?

topla çağrılmadan önce argümanları hesaplanmalı: önce kareAl(sayi1).

Yığın (stack)kareAl(3)sayi3ikiKareToplami(3, 4)sayi13sayi24main()sonuc?

Üçüncü çerçeve açılır: kareAl(3) → 3 × 3 = 9 döner.

Yığın (stack)ikiKareToplami(3, 4)sayi13sayi24main()sonuc?

kareAl çerçevesi kapandı; ilk argüman (arg1) = 9. Sıradaki: kareAl(sayi2).

Yığın (stack)kareAl(4)sayi4ikiKareToplami(3, 4)sayi13sayi24main()sonuc?

kareAl(4) → 4 × 4 = 16 döner.

Yığın (stack)topla(9, 16)sayi19sayi216ikiKareToplami(3, 4)sayi13sayi24main()sonuc?

Argümanlar hazır: topla(9, 16) çağrılır → 25. Buradaki sayi1 = 9; ikiKareToplami'nınki hâlâ 3.

Yığın (stack)ikiKareToplami(3, 4)sayi13sayi24main()sonuc?

topla'nın sonucu, ikiKareToplami'nın dönüş değeri olur: 25 döner.

Yığın (stack)main()sonuc25

main'e dönüldü: sonuc = 25.

Yığın (stack)main()sonuc25

Ekrana 25 yazılır. En fazla 3 çerçeve aynı anda yığındaydı.

static int kareAl(int sayi) {
  return sayi * sayi;
}
static int topla(int sayi1, int sayi2) {
  return sayi1 + sayi2;
}
static int ikiKareToplami(int sayi1,
                          int sayi2) {
  return topla(kareAl(sayi1), kareAl(sayi2));
}
public static void main(String[] args) {
  int sonuc = ikiKareToplami(3, 4);
  System.out.println(sonuc);
}

Hazır Metotlar

En Sık Kullanılan Metotlar (Java API)

AlanSınıflarÖrnek metotlarPaket
Ekrana yazmaSystem.outprint, println, printfjava.lang
MatematikMathsqrt, abs, max, powjava.lang
MetinStringlength, charAt, substring, equalsjava.lang
DiziArrayssort, copyOf, binarySearch, equalsjava.util
Kullanıcı girişiScannernextInt, nextLine, closejava.util
DosyaFile, FileWritercreateNewFile, write, closejava.io
Veri tabanıDriverManager, StatementgetConnection, executeQuery, executeUpdatejava.sql
Veri yapılarıArrayListadd, remove, get, sizejava.util
ZamanLocalDateTime, DateTimeFormatternow, ofPattern, formatjava.time
Web / grafikURI, URL, JFrameURI.create, openConnection, setVisiblejava.net, javax.swing

java.lang otomatik içe aktarılır; diğerleri için import gerekir, ör. import java.util.Scanner;

Hazır Metotlar

Ekrana Yazdırma

public class Yazdirma {
    public static void main(String[] args) {
        System.out.println("Merhaba, Dünya!");
        System.out.print("Bir ");
        System.out.print("satır");
        System.out.println();
        int yas = 20;
        System.out.println("Yaş: " + yas);
        System.out.printf("Pi yaklaşık %.2f%n", Math.PI);
    }
}
Çıktı
Merhaba, Dünya!
Bir satır
Yaş: 20
Pi yaklaşık 3,14
  • System.out.println(x): x'i yazar, alt satıra geçer.
  • System.out.print(x): x'i yazar, aynı satırda kalır.
  • + ile metin ve değer birleştirilir: "Yaş: " + yas.
  • printf: biçimli yazma; %.2f 2 ondalık basamak, %d tam sayı, %s metin, %n satır sonu.
  • printf yerel ayarı kullanır: Türkçe sistemde ondalık ayırıcı virgüldür (3,14).

Hazır Metotlar

Math Sınıfı

double kareKok = Math.sqrt(16);
double mutlakDeger = Math.abs(-17.2);
double maksimum = Math.max(3, 5);
System.out.println(kareKok);
System.out.println(mutlakDeger);
System.out.println(maksimum);
System.out.println(Math.pow(2, 10));
System.out.println(Math.round(2.6));
System.out.println(Math.min(-4, 7));
System.out.println(Math.max(3, 5));
  • Math sınıfı matematiksel işlemler içindir; metotları static olduğundan Math.sqrt(16) biçiminde çağrılır.
  • Math.max(3, 5) int döndürür (5); double değişkene atanınca 5.0 olur.
  • sqrt ve pow her zaman double döndürür.
Çıktı
4.0
17.2
5.0
1024.0
3
-4
5

Kapsam

Yerel Değişken

public int carpma(int sayi1, int sayi2) {
    int sonuc = sayi1 * sayi2; // 'sonuc' bir yerel değişkendir
    return sonuc;
}
public void baskaMetot() {
    carpma(2, 3);
    System.out.println(sonuc);  // HATA
}
error: cannot find symbol
        System.out.println(sonuc);
                           ^
  symbol:   variable sonuc
carpma(2, 3) çalışırkencarpmasayi1=2 sayi2=3sonuc=6baskaMetotdönüşten sonrasilindibaskaMetot
  • Yerel değişken (local variable): metodun ya da bloğun içinde tanımlanır; parametreler de yereldir.
  • Yalnızca fonksiyon çalışırken var olur; fonksiyon dışından erişilemez.
  • sonuc, sadece carpma yürütülürken vardır; metot dönünce silinir.
  • Değeri dışarı taşımanın yolu return: int s = carpma(2, 3);

Kapsam

Kapsam

Kapsam (scope), bir değişkenin tanımlandığı ve kullanılabildiği kod bölgesidir.

  • Her değişkenin bir kapsamı vardır: Java'da kapsam, değişkenin tanımlandığı süslü parantez bloğudur.
  • Kapsam, değişkenin erişilebilirliğini ve yaşam süresini belirler.
  • Yerel ve genel (global) kapsamlar farklı erişim kurallarına sahiptir.
  • İç içe kapsamda iç kapsam, üst kapsamdaki değişkenlere erişebilir; dış kapsam içtekini göremez.
  • Aynı adın farklı kapsamlarda kullanılması isim çakışmasına yol açabilir; doğru kullanılmayan kapsam hatalara neden olur.
class Ornek (sınıf kapsamı) alan: globalDegisken void fonksiyon() (metot kapsamı) disDegisken { ... } (blok kapsamı) icDegisken görür: icDegisken, disDegisken, globalDegisken

Kapsam

Yerel ve Global Kapsam

public class IcKapsam {
    static int globalDegisken = 10; // global (sınıf alanı)
    static void fonksiyon() {
        int disDegisken = 10;       // yerel kapsam
        {
            int icDegisken = 5;
            // disDegisken ve icDegisken burada erişilebilir
            System.out.println(disDegisken + icDegisken
                    + globalDegisken);
        }
        // icDegisken burada YOK
    }
    public static void main(String[] args) {
        fonksiyon();
    }
}
Çıktı
25

10 + 5 + 10 = 25: iç blok, hem metodun hem sınıfın değişkenlerini görür.

sınıf: globalDegiskenfonksiyon(): disDegiskenblok: icDegiskenüçünü de görür
Yerel kapsam

Metot ya da blok içinde; yaşam süresi o bloğun çalışma süresi kadar.

Global kapsam

Her yerden erişilir, program boyunca yaşar. Java'da bu rolü sınıf alanları üstlenir.

İç içe kapsam

Kapsam içinde kapsam; iç kapsam dıştakinin değişkenlerine erişir.

Kapsam

İsim Çakışması

Bloğun içinde aynı ad: hata

public void fonksiyon() {
    int disDegisken = 10;
    {
        int disDegisken = 5;  // HATA
    }
}
error: variable disDegisken is already
       defined in method fonksiyon()

Java, iç bloğun dıştaki yerel değişkenle aynı adı kullanmasına izin vermez.

Yerel değişken alanı gölgeler

public class Golge {
    static int deger = 10;  // sınıf alanı
    static void goster() {
        int deger = 5;      // alanı gölgeler
        System.out.println(deger);
        System.out.println(Golge.deger);
    }
    public static void main(String[] args) {
        goster();
        System.out.println(deger);
    }
}
Çıktı
5
10
10

Yerel deger, aynı adlı alanı gölgeler (shadowing); alana Golge.deger ile ulaşılır.

Kapsam · Adım adım kod izleme

Gölgeleme: Kodu Adım Adım İzle

sınıf alanıGolge.deger = 10main

Sınıf alanı deger = 10 program başlarken oluşur ve program boyunca yaşar. main, goster()'i çağırır.

sınıf alanıGolge.deger = 10maingoster

goster için yeni bir çerçeve açılır; henüz yerel değişkeni yok.

sınıf alanıGolge.deger = 10maingosterdeger = 5

Yerel deger = 5 tanımlanır. Aynı ad artık bu metot içinde yereli gösterir: alan gölgelendi.

sınıf alanıGolge.deger = 10maingosterdeger = 5deger → yerel 5

deger adı önce en içteki kapsamda aranır → yerel 5 yazdırılır.

sınıf alanıGolge.deger = 10maingosterdeger = 5Golge.deger → 10

Golge.deger sınıf adıyla alana ulaşır → 10.

sınıf alanıGolge.deger = 10maindeger → alan 10

goster bitti, yerel deger silindi. main'de yerel deger yok: ad alanı gösterir → 10.

public class Golge {
    static int deger = 10;  // sınıf alanı
    static void goster() {
        int deger = 5;      // alanı gölgeler
        System.out.println(deger);
        System.out.println(Golge.deger);
    }
    public static void main(String[] args) {
        goster();
        System.out.println(deger);
    }
}

Kapsam · Adım adım kod izleme

Değişkenler Ne Zaman Doğar, Ne Zaman Ölür?

Bellekmain()static alanlarcagriSayisi0

Sınıf alanı cagriSayisi program başında oluşur ve program boyunca yaşar. carpma(2, 3) çağrılıyor.

Bellekcarpma(2, 3)sayi12sayi23main()static alanlarcagriSayisi1

Metot, sınıf alanına erişebilir: cagriSayisi 1 olur.

Bellekcarpma(2, 3)sayi12sayi23sonuc6main()static alanlarcagriSayisi1

Yerel sonuc şimdi doğar: 6.

Bellekmain()ilk6static alanlarcagriSayisi1

carpma döndü: sayi1, sayi2, sonuc yok oldu. Değer, ilk'e atandı.

Bellekcarpma(6, 4)sayi16sayi24sonuc24main()ilk6static alanlarcagriSayisi2

Yeni çerçeve: sonuc = 24, sayaç 2.

Bellekmain()ilk6ikinci24static alanlarcagriSayisi2

ikinci yalnızca iç blokta yaşayan bir yerel değişkendir.

Bellekmain()ilk6ikinci24static alanlarcagriSayisi2

Blok içinde ikinci erişilebilir: 24 yazılır.

Bellekmain()ilk6static alanlarcagriSayisi2

Blok bitti, ikinci yok oldu: 6 2.

static int cagriSayisi = 0;  // sınıf alanı
static int carpma(int sayi1, int sayi2) {
  cagriSayisi++;
  int sonuc = sayi1 * sayi2;
  return sonuc;
}
public static void main(String[] args) {
  int ilk = carpma(2, 3);
  {
    int ikinci = carpma(ilk, 4);
    System.out.println(ikinci);
  }
  System.out.println(ilk + " " + cagriSayisi);
}

Soyutlama ve Tasarım

Soyutlama

Soyutlama (abstraction), karmaşıklığı azaltmak için ayrıntıları yok saymaktır.

16 Math.sqrt nasıl hesaplıyor? (gizli ayrıntı) 4.0 ne verdim? ne aldım?
Neden?

Kodun okunabilirliğini artırır, işlemi basitleştirir; büyük ve karmaşık programları anlaşılır kılar.

Nasıl?

Kodu parçalara ayırır; her parça ayrı ayrı düşünülür. Bir metodu kullanan, onun içini bilmek zorunda değildir.

Günlük benzetme: arabayı sürmek için motorun içini bilmek gerekmez; direksiyon ve pedallar bir "arayüzdür".

Soyutlama ve Tasarım

Fonksiyonel Soyutlama

Hesaplamalar üzerinde soyutlama, işlevsel ya da yordamsal soyutlama (procedural abstraction) olarak da bilinir.

  • Bir fonksiyonun nasıl hesapladığından çok ne hesapladığını bilmek önemlidir.
  • Görevi bilindiği sürece, nasıl yaptığı umursanmaz.
  • Fonksiyonun gerçeklemesi (gövdesi) hakkında endişelenilmez.
  • Gövde değişse bile (daha hızlı bir algoritma), çağıran kod aynı kalır.
System.out.println("Merhaba");

Fonksiyon, verilen metni konsola yazar; bunu nasıl yaptığını (karakter kodlama, işletim sistemi çağrıları…) bilmek gerekmez.

// Kullanan yalnızca imzayı bilir:
static boolean asalMi(int sayi)
// "sayi asal ise true döner"
if (asalMi(17)) { ... }
17asalMigövde gizlitruekullanıcı yalnızca girdiyi ve çıktıyı bilir

Soyutlama ve Tasarım

Genelleme

Bağlam (context):

  • bir sayının, bir denklem içindeki diğer unsurlarla ilişkisi,
  • bir kelimenin anlamının cümledeki yeri ve durumuyla ilişkisi,
  • bir kod bloğu içindeki durum ve etkileşimler.

Bir ifadenin anlamı, çevresindeki diğer kelimelerden etkilenebilir.

Genelleme (generalization):

  • bir bağlama ait bir çözümü başka bağlamlara uygun hâle getirmek,
  • bir ürünü daha genel ve çok amaçlı kullanılabilir yapmak.

Kodda genellemenin aracı parametredir: sabit değerler parametreye dönüşür.

public class Genelleme {
    // Özel: yalnızca 10 tane '-' yazar
    static void cizgiCiz() {
        System.out.println("----------");
    }
    // Genel: uzunluğu ve karakteri parametre
    static void cizgiCiz(int uzunluk, char karakter) {
        for (int i = 0; i < uzunluk; i++) {
            System.out.print(karakter);
        }
        System.out.println();
    }
    public static void main(String[] args) {
        cizgiCiz();
        cizgiCiz(5, '*');
        cizgiCiz(12, '=');
    }
}
Çıktı
----------
*****
============

Soyutlama ve Tasarım

Ayrıştırma

Problemi küçük parçalara ayırmak (decomposition), programlamanın temel adımıdır. Her parça bir fonksiyon olur: kod düzenli, okunur, yeniden kullanılabilir ve sürdürülebilir olur.

main (not programı) notlariOkugirdi ortalamaHesaplaişlem harfNotukarar
// notlariOku ve harfNotu da ayrı metotlardır
static double ortalamaHesapla(int[] notlar) {
    int toplam = 0;
    for (int n : notlar) {
        toplam += n;
    }
    return (double) toplam / notlar.length;
}
public static void main(String[] args) {
    Scanner giris = new Scanner(System.in);
    int[] notlar = notlariOku(giris, 3);
    double ort = ortalamaHesapla(notlar);
    System.out.println("Ortalama: " + ort + " -> " + harfNotu(ort));
}
Çıktı (girdi: 80 90 75)
Ortalama: 81.66666666666667 -> BB

main bir "içindekiler" gibi okunur: ne yapıldığı görünür, nasıl yapıldığı alt fonksiyonlardadır.

Soyutlama ve Tasarım

Ne Zaman Fonksiyon?

Bir kural: DRY (Don't Repeat Yourself, kendini tekrar etme). Kodu kopyalayıp yapıştırma ihtiyacı doğduğu an, o kod bir fonksiyon olmaya adaydır.

Tekrarlı kod

double ort1 = (70 + 80 + 90) / 3.0;
System.out.println(ort1);
double ort2 = (55 + 60 + 100) / 3.0;
System.out.println(ort2);
// formül değişirse her yerde
// ayrı ayrı düzeltmek gerekir

Fonksiyonla

static double ortalama(int a, int b, int c) {
    return (a + b + c) / 3.0;
}
System.out.println(ortalama(70, 80, 90));
System.out.println(ortalama(55, 60, 100));
Çıktı
80.0
71.66666666666667

Tekrar kullanılabilirlik ve bakım kolaylığı için önemlidir. İyi bir fonksiyon tek bir işi yapar ve okunaklıdır.

Soyutlama ve Tasarım

İyi Fonksiyon Tasarımı

Tek sorumluluk

Her fonksiyon yalnızca bir işi yapmalı. "ve" ile anlatılıyorsa (oku ve hesapla ve yazdır) bölünmeli.

Açıklayıcı isim

Ne yaptığını anlatan fiil: ortalamaHesapla, asalMi, notlariOku. islem2 gibi isimler bir şey anlatmaz.

Parametreler

Gerekli verileri parametrelerle almalı; gizlice dış değişkenlere bağlı olmamalı. Az sayıda parametre okunurluğu artırır.

Dönüş değeri

Sonucu açıkça return ile döndürmeli. Hesaplayan metot yazdırmamalı; yazdırma işini çağıran yapsın.

Kısa ve odaklı

Bir ekrana sığan, birkaç satırlık fonksiyonlar anlaşılır ve kolay test edilir.

Yerinde çağrı

Fonksiyon yalnızca gerektiği yerde çağrılmalı; aynı sonucu döngüde tekrar tekrar hesaplamak gereksiz iştir.

Soyutlama ve Tasarım

Değişken Adlandırma

Her değişken tek bir şeyi temsil etmeli

  • Bir değişken yalnızca bir nesneyi ya da bir veriyi tutmalı; aynı değişkenin önce yaş, sonra toplam için kullanılması kafa karıştırır.
  • Kodun okunurluğunu ve yeniden kullanılabilirliğini artırır, mantıksal hataları azaltır.

İyi isim

  • Açıklayıcı ve anlamlı olmalı; temsil ettiği verinin doğasını yansıtmalı.
  • İçeriği ve kullanımı anlatmalı; anlamsız ya da tek harfli isimler okunurluğu düşürür (döngü sayacı i ve matematikteki x istisnadır).
  • Java geleneği: camelCase (ogrenciSayisi), sınıflar büyük harfle (Kitap), sabitler MAKS_DEGER.
int ogrenciSayisi;      // iyi bir adlandırma
int a;                  // anlamsız bir isim
int yas = 25;
String isim = "Ahmet";
double ortalama = 85.5;
String kitapAdi;
Kötüİyi
int x1, x2;int vizeNotu, finalNotu;
double d;double daireAlani;
boolean f;boolean asalMi;

Özet

Özet

KonuHatırlanacaklar
Tanımerişim [static] dönüşTürü ad(parametreler) { gövde }; imza = ad + parametre tipleri
Çağrıargümanlar parametrelere kopyalanır (değer ile aktarım); her çağrı yığında yeni bir çerçeve açar
return / voidreturn değeri verir ve metodu bitirir; void değer döndürmez
staticstatic metot doğrudan / Sinif.metot(); değilse nesne.metot()
Aşırı yüklemeaynı ad, farklı parametre listesi; seçim derleme zamanında
Hazır metotlarSystem.out, Math (static: Math.sqrt(16)); java.lang dışındakiler import ister
Kapsamdeğişken tanımlandığı blokta yaşar; iç blok dışı görür, tersi değil; alanlar program boyunca
Tasarımsoyutlama (ne, nasıl değil), genelleme (parametre), ayrıştırma, DRY, tek sorumluluk

Özet

İlgili Sayfalar

Değer ile Aktarım Laboratuvarı

Simülatör: metoda ilkel değer, dizi ve nesne referansı geçirmek; çağrı yığını çerçeveleri ve heap nesneleri adım adım.

Çalışma Soruları

Asal sayı, kombinasyon, öğrenci numarası çözme gibi problemler; çağrı yığını ve gölgeleme izlemeleri.

Özet

Sık Yapılan Hatalar (1)

static olmayan metodu main'den çağırmaknon-static method toplama(int,int) cannot be referenced from a static contextÇözüm: metot static yapılır ya da bir nesne oluşturulup onun üzerinden çağrılır.
Bazı yollarda return unutmakmissing return statementif/else if zincirinde her olasılık bir return ile bitmeli; sona varsayılan bir return konur.
void metodun sonucunu kullanmakincompatible types: void cannot be converted to intint x = selamla(); olmaz: void metot değer üretmez.
Eksik / fazla argümanmethod toplama in class ... cannot be applied to given types; required: int,int found: intArgüman sayısı ve tipleri imzayla aynı olmalı.

Özet

Sık Yapılan Hatalar (2)

Yerel değişkeni dışarıda kullanmakcannot find symbol … variable sonucDeğer return ile döndürülür.
İç blokta aynı adla değişkenvariable disDegisken is already defined in method fonksiyon()
Takas metodunun çalışacağını sanmakyerDegistir(int x, int y) yalnızca kopyaları takas eder; yerDegistir(dizi[0], dizi[2]) sonrası dizi aynı kalır. Dizi hücreleri için yerDegistir(int[] d, int i, int j).
Dönüş tipiyle aşırı yüklemekint f(int a) ve double f(int a) birlikte olamaz: method f(int) is already defined. İmzayı yalnız ad ve parametre tipleri belirler.
Argümanın değişeceğini sanmakarttir(sayi) sonrası sayi aynı kalır: kopya değişir. Yeni değer return ile döner.
Math sonucunun tipini unutmakint k = Math.sqrt(16); → possible lossy conversion from double to int. sqrt ve pow double döndürür.

Özet

Örnek Problemler (1)

static int f(int x) {
    x = x * 2;
    return x + 1;
}
public static void main(String[] args) {
    int a = 3;
    int b = f(a);
    System.out.println(a + " " + b);
    System.out.println(f(f(1)));
}
static int kare(int n) { return n * n; }
static int kup(int n) { return n * kare(n); }
// main içinde:
System.out.println(kup(2) + kare(3));
  1. Soldaki program ne yazdırır? a neden değişmedi?
  2. Sağdaki satır ne yazdırır? kup(2) çalışırken yığında en çok kaç çerçeve olur (main dahil)?
Cevapları göster
  1. 3 7 ve 7. f, a'nın kopyasını ikiye katlar; a = 3 kalır. f(f(1)) = f(3) = 7.
  2. 8 + 9 = 17. main → kup(2) → kare(2): en çok 3 çerçeve.

Özet

Örnek Problemler (2)

static int topla(int a, int b) { return a + b; }
static double topla(double a, double b) { return a + b; }
// main içinde:
System.out.println(topla(2, 3.0));
System.out.println(topla(2, 3));
System.out.println(Math.max(Math.abs(-8), Math.sqrt(49)));
  1. İlk iki println hangi topla metodunu çağırır, ne yazdırır?
  2. Son satır neden 8 değil de 8.0 yazdırır?
Cevapları göster
  1. topla(2, 3.0) → double sürümü (2, double'a genişler): 5.0; topla(2, 3) → int sürümü: 5.
  2. Math.sqrt double döndürür; max(int, double) double sürümünü seçer: 8.0.

Özet

Alıştırmalar

  1. boolean ciftMi(int sayi): sayı çiftse true döndürsün.
  2. int enBuyuk(int a, int b, int c): üç sayının en büyüğünü Math.max ile bulsun.
  3. int usAl(int taban, int us): döngüyle üs hesaplasın (Math.pow kullanmadan).
  4. int basamakToplami(int n): sayının rakamları toplamını döngüyle bulsun.
  5. double daireAlani(double r) yazın; sonucu printf ile 2 basamak yazdırın.
  6. Aşırı yüklenmiş double alan(double r) (daire) ve double alan(double en, double boy) (dikdörtgen).
Cevaplar / ipuçları
  1. return sayi % 2 == 0; → ciftMi(7) = false, ciftMi(10) = true.
  2. return Math.max(a, Math.max(b, c)); → enBuyuk(4, 9, 2) = 9.
  3. int sonuc = 1; for (int i = 0; i < us; i++) sonuc *= taban; return sonuc; → usAl(2, 10) = 1024.
  4. while (n != 0) { t += n % 10; n /= 10; } → basamakToplami(2024) = 8.
  5. return Math.PI * r * r; → printf("%.2f%n", daireAlani(2)) → 12,57.
  6. alan(1) → 3.14159…; alan(3, 4) → 12.0. Hangi sürümün çağrılacağını argüman sayısı belirler.

Özet

Kaynaklar

  • Oracle, The Java Tutorials: "Defining Methods", "Passing Information to a Method or a Constructor".
  • J. Gosling ve diğ., The Java Language Specification, Java SE 21 Edition (Bölüm 8.4 Method Declarations, 6.3 Scope).
  • P. Deitel ve H. Deitel, Java: How to Program, Early Objects, 11. baskı, Pearson, 2017 (Bölüm 6: Methods).
  • K. Sierra ve B. Bates, Head First Java, 3. baskı, O'Reilly, 2022.
  • C. S. Horstmann, Core Java, Volume I: Fundamentals, 12. baskı, 2022.
  • A. B. Downey ve C. Mayfield, Think Java, 2. baskı, O'Reilly, 2019 (Bölüm 4: Methods and Testing).

Son

Bölüm 3.2: Fonksiyonlar
Sonraki bölüm: Bölüm 3.3: Diziler · Terim sözlüğü
1 / 1 Sercan KÜLCÜ, Tüm hakları saklıdır.