---
title: 'İşleçler ve İfadeler'
source: 'https://academia.sh/tr/kurslar/java-temelleri/islecler-ve-ifadeler'
course: 'Java Temelleri'
language: tr
updated: '2026-08-17T18:09:40+00:00'
license: 'CC BY-SA 4.0'
---

# İşleçler ve İfadeler

Tek karakterlik yazımlar sınıf dosyasına sessiz adımlar bırakır: `int` ile `long` toplandığında bir çevirme eklenir, `adet += 300` kaynakta yazılmayan bir daraltma koyar ve sonuç 45 çıkar, kısa devre bir dal komutu olarak belirir — sabitlerde ise hiçbir adım eklenmez.

Önceki ders adın sınıf dosyasında nereye yazıldığını ölçtü: alana mı, yuvaya mı. Adlar
yerlerine oturduğunda sıra onları birleştiren işleçlere gelir. Bir işleç kaynakta tek
karakterdir; sınıf dosyasında ise bir ya da birkaç komuttur ve bu komutların bir bölümü
kaynakta hiç yazılmaz. Bu ders o bölümü sayar.

Programlama Temelleri kursu işleçleri, önceliği, kısa devre değerlendirmeyi ve açık/örtük
dönüşümü kavram olarak kurmuştu — **bunlar tekrarlanmaz**. Orada bir dönüşümün ne zaman
genişletme, ne zaman daraltma olduğu ve daraltmanın neden sessiz bilgi kaybı üretebildiği
anlatıldı. Burada ölçülen şey, o daraltmayı **kimin eklediğidir**: kaynakta hiçbir yerde
dönüşüm yazmayan bir satır, sınıf dosyasında bir çevirme komutu taşıyabilir.

## İşleç Bir Kısaltmadır

Java'nın aritmetik işleçleri yalnız dört genişlikte çalışır: `int`, `long`, `float` ve
`double`. `byte`, `short` ve `char` için ayrı toplama komutu yoktur. Bunun sonucu şudur:
küçük tiplerdeki değerler işleme girmeden önce `int`'e yükseltilir ve iki işlenen farklı
genişlikteyse dar olan geniş olana çevrilir. Buna **sayısal yükseltme** denir ve kaynakta
görünmez.

Yükseltmenin tersi de vardır. Bileşik atama — `+=`, `-=`, `*=` — sol tarafın tipini
korumak zorundadır. `byte` bir değişkene `+=` ile bir `int` eklendiğinde toplama `int`
genişliğinde yapılır, sonra sonuç geri `byte`'a **daraltılır**. Bu daraltma kaynakta
yazılmaz; yazılsaydı derleyici zaten istemezdi. Aynı işlem `adet = adet + 300` biçiminde
yazılsaydı derleme hatası verirdi, çünkü orada daraltmayı programcının yazması gerekir.

İki yön arasındaki asıl ayrım güvenliktir. Dar bir tipten geniş bir tipe geçiş
**genişletmedir** ve hiçbir bilgi kaybetmez; derleyici onu sormadan yapar. Geniş bir tipten
dar bir tipe geçiş **daraltmadır** ve sığmayan bitler atılır; derleyici onu normalde
yapmaz, programcının yazmasını ister. Bileşik atama bu kuralın **tek gediğidir**: sol
tarafın tipi zaten bellidir, bu yüzden derleyici daraltmayı isteyeceği yerde kendisi
koyar. Ölçüm bu gediğin sınıf dosyasındaki karşılığını arar.

Ders bu iki yönü kurs boyunca sürdürülen depo kaydının iki alanı üzerinde ölçer: `int adet`
ve `long agirlik`. Aradaki genişlik farkı, yükseltmenin ölçülebileceği en dar örnektir.

## Ölçüm Çekirdeği

Çekirdek önceki derslerinkidir; bu derste iki ölçüm okur. Birincisi **çevirme komutlarıdır**
— sınıf dosyasında bir genişliği başka bir genişliğe çeviren komutlar ayrı bir aileyi
oluşturur ve adları çevrilen iki tipi taşır (`i2l`, `i2b`). İkincisi **dal komutlarının
sayısıdır**: akışı bir noktadan başka bir noktaya götüren her komut sayılır.

- **SD11** — Sağ sütun sınıf dosyasındaki çevirmeleri, dinamik çağrıları ve çağrıları
  listeler; kaynakta yazılmış olanı okuyucu düşer, kalanı derleyici eklemiştir.
- **SD12** — Ölçülen bütün yöntemler statiktir ve gövdeleri tek satırdır; komut sayısındaki
  fark yöntem çağrısı düzeninden değil, yalnız ifadenin kendisinden gelir.

```java
// Olcek.java — işlecin sınıf dosyasına bıraktığı çevirme, çağrı ve dal komutunu okur
import java.io.PrintWriter;
import java.io.Writer;
import java.lang.classfile.*;
import java.lang.classfile.instruction.*;
import java.nio.file.*;
import java.util.*;
import java.util.spi.ToolProvider;

class Olcek {
    record Yontem(String ad, int komut, int dal, List<String> eklenen) {}

    static List<Yontem> oku(String kaynak, String sinif) throws Exception {
        Path d = Files.createTempDirectory("olcek");
        Files.writeString(d.resolve(sinif + ".java"), kaynak);
        PrintWriter bos = new PrintWriter(Writer.nullWriter());
        if (ToolProvider.findFirst("javac").orElseThrow().run(bos, bos, "-d", d.toString(),
                d.resolve(sinif + ".java").toString()) != 0)
            throw new IllegalStateException("derlenmedi: " + sinif);
        List<Yontem> yontemler = new ArrayList<>();
        for (MethodModel m : ClassFile.of().parse(d.resolve(sinif + ".class")).methods()) {
            if (m.code().isEmpty()) continue;
            List<String> eklenen = new ArrayList<>();
            int komut = 0, dal = 0;
            for (CodeElement e : m.code().get()) {
                if (e instanceof Instruction) komut++;
                if (e instanceof BranchInstruction) dal++;
                if (e instanceof ConvertInstruction c)
                    eklenen.add("cevirme " + c.opcode().name().toLowerCase(Locale.ROOT));
                else if (e instanceof InvokeDynamicInstruction id)
                    eklenen.add("dinamik:" + id.name().stringValue());
                else if (e instanceof InvokeInstruction iv)
                    eklenen.add(iv.name().stringValue());
            }
            yontemler.add(new Yontem(m.methodName().stringValue(), komut, dal, eklenen));
        }
        return yontemler;
    }
}
```

## On Üç İfade, Sınıf Dosyasında Ne Bırakıyor

Ölçülen sınıf on üç yöntem taşır ve her biri tek bir ifadedir. `daralt` ile `acikDaralt`
aynı işi yapar; tek fark, daraltmanın kaynakta yazılıp yazılmadığıdır. `gecCevirme` ile
`erkenCevirme` aynı çarpımı yapar; tek fark, çevirmenin çarpımdan önce mi sonra mı
istendiğidir. `sabitAritmetik`, `sonSabitCarpim` ve `degiskenCarpim` **aynı çarpımı** üç
ayrı yazımla verir.

```java
// Islec.java — on üç ifade, sınıf dosyasında ne bırakıyor
public class Islec {
    static final String KAYNAK = """
        class Depo {
            static long yukselt(int adet, long agirlik) { return adet + agirlik; }
            static byte daralt(byte adet) { adet += 300; return adet; }
            static byte acikDaralt(byte adet) { adet = (byte) (adet + 300); return adet; }
            static int kucukToplam(byte adet, short raf) { return adet + raf; }
            static long gecCevirme(int adet, int birim) { return adet * birim; }
            static long erkenCevirme(int adet, int birim) { return (long) adet * birim; }
            static String birlestir(String ad, int adet) { return ad + adet; }
            static String sabitBirlestir() { return "vi" + "da"; }
            static int sabitAritmetik() { return 24 * 60 * 60; }
            static final int RAF = 24;
            static int rafSayisi = 24;
            static int sonSabitCarpim() { return RAF * 60 * 60; }
            static int degiskenCarpim() { return rafSayisi * 60 * 60; }
            static boolean kisaDevre(int adet, long agirlik) { return adet > 0 && agirlik > 0; }
            static boolean tamDeger(int adet, long agirlik) { return (adet > 0) & (agirlik > 0); }
        }
        """;

    public static void main(String[] args) throws Exception {
        System.out.printf("%-16s %6s %4s  %s%n", "yontem", "komut", "dal", "kaynakta yazilmayan adim");
        for (Olcek.Yontem y : Olcek.oku(KAYNAK, "Depo")) {
            if (y.ad().startsWith("<")) continue;
            System.out.printf("%-16s %6d %4d  %s%n", y.ad(), y.komut(), y.dal(),
                    y.eklenen().isEmpty() ? "-" : String.join(", ", y.eklenen()));
        }
    }
}
```

```
yontem            komut  dal  kaynakta yazilmayan adim
yukselt               5    0  cevirme i2l
daralt                7    0  cevirme i2b
acikDaralt            7    0  cevirme i2b
kucukToplam           4    0  -
gecCevirme            5    0  cevirme i2l
erkenCevirme          6    0  cevirme i2l, cevirme i2l
birlestir             4    0  dinamik:makeConcatWithConstants
sabitBirlestir        2    0  -
sabitAritmetik        2    0  -
sonSabitCarpim        2    0  -
degiskenCarpim        6    0  -
kisaDevre            10    3  -
tamDeger             14    4  -
```

İlk satır sayısal yükseltmenin sınıf dosyasındaki adıdır. `adet + agirlik` ifadesinde
`adet` bir `int`, `agirlik` bir `long`; toplama komutu ikisini birden alamaz, bu yüzden
derleyici araya bir **`i2l`** koyar. Kaynakta hiçbir dönüşüm yazmaz. Beş komutun biri,
programcının yazmadığı bir çeviridir.

İkinci satır bu dersin en sessiz adımıdır. `adet += 300` yazımı yedi komut üretir ve
içinde bir **`i2b`** vardır: toplama `int` genişliğinde yapılır, sonuç `byte`'a daraltılır.
Daraltmayı derleyici kendiliğinden ekler. Bu, önceki kursta anlatılan sessiz bilgi kaybının
sınıf dosyasındaki karşılığıdır — kavram orada kuruldu, burada eklendiği yer gösteriliyor.

Bir alt satır bunun ne kadar birebir olduğunu ölçüyor. `acikDaralt` daraltmayı **kaynakta
yazıyor** ve sınıf dosyasında `daralt` ile aynı çıkıyor: aynı **7** komut, aynı `i2b`. İki
yazım sınıf dosyasında ayırt edilemez. `+=` bir işleç değil, bu satırın **kısaltmasıdır**;
kısalttığı şeyin içinde bir dönüşüm vardır ve kısaltma onu gizler.

Dördüncü satır yükseltmenin her zaman komut üretmediğini gösteriyor. `byte` ile `short`
toplandığında ikisi de `int`'e yükselir, ama sınıf dosyasında **hiçbir çevirme yoktur**:
dört komut, sıfır eklenen adım. Bu tipler zaten `int` genişliğinde yüklenir, dolayısıyla
yükseltmenin ödediği bir komut yoktur. Yükseltme bir kural olarak her yerde vardır; komut
olarak yalnız genişlik gerçekten değiştiğinde belirir.

Sonraki iki satır çevirmenin **yerini** karşılaştırıyor. İkisi de aynı çarpımı
`long` olarak döndürüyor. `gecCevirme` tek bir `i2l` taşıyor ve o çevirme çarpımdan
**sonradır**: iki `int` çarpılıyor, sonuç `long`'a çevriliyor. `erkenCevirme` iki `i2l`
taşıyor — biri kaynakta yazılan dönüşüm, öteki ikinci işlenen için eklenen yükseltme — ve
çarpım artık `long` genişliğinde yapılıyor. Bir komut fazla, ama başka bir hesap.

Birleştirme satırları aynı `+` işlecini iki ayrı sonuca bağlıyor. Değişken içeren
birleştirme dört komutta bir **dinamik çağrı** bırakıyor; iki sabitin birleştirilmesi ise
iki komut ve **hiçbir** eklenen adım. Aynı işleç, biri bir çağrı, biri sıfır adım.

Son iki satır kısa devre değerlendirmenin sınıf dosyasındaki izidir. `&&` kullanan biçim
**10** komut ve **3** dal, `&` kullanan biçim **14** komut ve **4** dal üretiyor. `&`
biçimi iki karşılaştırmayı da doğruluk değerine çevirmek zorundadır; `&&` ilk
karşılaştırma yanlış çıktığında ikinciye hiç girmeyen bir dal koyar. Kısa devre bir çalışma
zamanı kolaylığı değil, sınıf dosyasında duran bir **atlama**dır.

## Eklenen Çevirmenin Görünen Sonucu

Buraya kadar sayılan adımların hepsinin bir değeri değiştiren karşılığı vardır.

- **SD13** — Taşma ölçümünde kayıt sayısı 100000, birim ağırlık 50000 gramdır; çarpım
  `int` genişliğinde tutulamayacak kadar büyüktür ve iki yazım arasındaki tek fark
  çevirmenin yeridir.
- **SD14** — Kısa devre ölçümünde depo üç kayıt taşır ve ikisinin `adet` alanı sıfırdır;
  sağ işlenen bir yöntem çağrısıdır ve o yöntem her çağrılışında sayacı artırır, böylece
  atlanan dalın kaç kez atlandığı sayılabilir.

```java
// Sonuc.java — eklenen çevirmenin ve atlanan dalın görünen sonucu
public class Sonuc {
    record Kayit(String ad, byte adet, long agirlik) {}

    static int cagri = 0;

    static boolean agirMi(Kayit k) { cagri++; return k.agirlik() > 0; }

    public static void main(String[] args) {
        byte adet = 1;
        adet += 300;
        System.out.println("byte adet = 1; adet += 300      ->  " + adet);

        int kayit = 100000, birim = 50000;
        System.out.println("long gecCevirme(100000, 50000)  ->  " + (long) (kayit * birim));
        System.out.println("long erkenCevirme(100000,50000) ->  " + (long) kayit * birim);

        Kayit[] depo = { new Kayit("vida", (byte) 0, 40L),
                         new Kayit("civata", (byte) 3, 90L),
                         new Kayit("somun", (byte) 0, 12L) };
        cagri = 0;
        int a = 0;
        for (Kayit k : depo) if (k.adet() > 0 && agirMi(k)) a++;
        int kisaDevre = cagri;
        cagri = 0;
        int b = 0;
        for (Kayit k : depo) if ((k.adet() > 0) & agirMi(k)) b++;
        System.out.println("&&  sonuc: " + a + "  agirMi cagrisi: " + kisaDevre);
        System.out.println("&   sonuc: " + b + "  agirMi cagrisi: " + cagri);
    }
}
```

```
byte adet = 1; adet += 300      ->  45
long gecCevirme(100000, 50000)  ->  705032704
long erkenCevirme(100000,50000) ->  5000000000
&&  sonuc: 1  agirMi cagrisi: 1
&   sonuc: 1  agirMi cagrisi: 3
```

İlk satır `i2b` komutunun ödettiğidir. Bir kayda 300 adet eklendi ve sonuç **45** oldu.
Kaynakta hiçbir dönüşüm yazılı değildir, derleyici uyarı vermez ve program çalışmaya devam
eder. Kararı programcı değil, eklenen adım vermiştir.

İkinci ve üçüncü satırlar çevirmenin **yerinin** neye mal olduğunu gösteriyor. Çarpım
`int` genişliğinde yapıldığında sonuç **705032704**, `long` genişliğinde yapıldığında
**5000000000**. Sol taraftaki değişkenin `long` olması yetmez — sonucun genişliği,
çarpımdan sonra yapılan bir çeviriyle kurtarılamaz. Yükseltmenin işlem **başına**
uygulandığını gösteren en açık ölçüm budur.

Son iki satır kısa devrenin çalışma zamanındaki karşılığıdır. İki biçim de aynı sonucu
buluyor: **1** kayıt. Ödenen çağrı sayısı ayrı: `&&` biçimi sağ işleneni **1** kez,
`&` biçimi **3** kez çalıştırıyor. Sınıf dosyasındaki bir dal komutu farkı, burada iki
yöntem çağrısı farkına dönüşüyor. Sağ işlenen bir yan etki taşısaydı iki biçim aynı
programı vermezdi; `&` ile `&&` arasındaki seçim üslup değildir.

## Sınırlayıcı Ölçüm: Sabitte Eklenen Adım Yok

Tablodaki üç satır aynı çarpımı üç ayrı yazımla veriyor ve üçünde de eklenen adım
**sıfır**. Komut sayıları ayrı: **2**, **2** ve **6**.

- **SD15** — Üç yöntem de aynı sayıyı döndürür; aralarındaki tek fark, çarpanların
  derleme zamanında bilinip bilinmediğidir.

`sabitAritmetik` iki komutta bitiyor: sınıf dosyasında çarpma komutu **yok**, doğrudan
sonuç yazılı. Derleme zincirinde tanıtılan sabit katlama, burada ölçülen bir şeye
dönüşüyor. `sonSabitCarpim` de iki komut — çünkü `RAF` bir `static final` alandır ve
başlangıç değeri derleme zamanında bellidir; derleyici adı değil, **değeri** yerine koyar
ve katlamayı yapar. `degiskenCarpim` altı komut: `rafSayisi` sonradan değişebileceği için
değeri alınıyor ve iki çarpma çalışma zamanında yapılıyor.

Bu üçlü dersin tezini sınırlıyor. Eklenen adım bir kural değil, bir **koşula bağlı
karşılıktır**: işlenenlerin genişlikleri ayrıldığında çevirme eklenir, sol taraf dar
olduğunda daraltma eklenir, işlenenlerden biri değişken olduğunda dinamik çağrı eklenir.
İşlenenlerin hepsi derleme zamanında biliniyorsa eklenecek bir şey kalmaz — tersine, o
zaman kaynakta yazılı olan işlem sınıf dosyasından **çıkar**. Eklenen adım bazen
çıkarmadır.

Sınırın pratik karşılığı da vardır: bir sabiti `static final` bildirmek yalnız değişmezlik
bildirimi değildir, derleyiciye o değeri yerine koyma izni verir. Aynı sabit `final`
olmadan bildirildiğinde çalışma zamanında iki çarpma ödenir. Aradaki fark bu ölçümde dört
komuttur ve kaynağa bakarak görünmez.

## Özet

- Sayısal yükseltme sınıf dosyasında bir çevirme komutudur: `int` ile `long` toplandığında
  beş komutun biri kaynakta yazılmayan bir **`i2l`**'dir.
- Bileşik atama daraltmayı kendiliğinden ekler; `adet += 300` yedi komutta bir **`i2b`**
  bırakır ve sonucu **45** yapar, derleyici uyarı üretmez. Daraltmanın kaynakta yazıldığı
  biçim sınıf dosyasında bundan ayırt edilemez.
- Yükseltme her zaman komut üretmez: `byte` ile `short` toplandığında sınıf dosyasında
  hiçbir çevirme yoktur, çünkü ikisi de zaten `int` genişliğinde yüklenir.
- Yükseltme işlem başına uygulanır: aynı çarpım `int` genişliğinde **705032704**, `long`
  genişliğinde **5000000000** verir ve sonucu `long` bir değişkene atamak bunu düzeltmez.
- Kısa devre bir dal komutudur: `&&` biçimi **10** komut ve **3** dal, `&` biçimi **14**
  komut ve **4** dal üretir; çalışma zamanında sağ işlenen **1** ve **3** kez çalışır.
- İşlenenlerin hepsi derleme zamanında biliniyorsa eklenen adım kalmaz: aynı çarpım
  sabitlerle **2**, değişkenle **6** komuttur ve üçünde de eklenen adım sıfırdır.

## Sonraki Adım

Bu derste akışı bir noktadan başka bir noktaya götüren dal komutu ilk kez ölçüldü ve bir
işlecin yan ürünü olarak ortaya çıktı. Sıradaki ders dalı asıl konusu yapar: `if` ve
`switch` ile yazılan aynı davranış sınıf dosyasında **iki ayrı komuta** derlenir ve iki
komutun arama maliyeti aynı değildir. Etiketli atlamanın iç içe döngülerde ne kazandırdığı
adım sayısıyla ölçülür, gelişmiş `for` döngüsünün dizide ve listede neden ayrı adım ürettiği
gösterilir — ve kazancın okunabilirlikte ne ödettiği aynı yerde yazılır.
