break, continue ve Etiketli Döngüler
Giriş — Döngü Akışını Kontrol Etme
Bir önceki derste döngülerin nasıl çalıştığını öğrendin — koşul true olduğu sürece tekrar et. Ama ya döngünün ortasında "tamam, buldum, artık devam etmeye gerek yok" demek istersen? Ya da "bu elemanı atla, sonrakine geç" demek istersen?
İşte break ve continue tam bunun için var. Döngünün normal akışına müdahale etmeni sağlarlar.
Analoji: Bir kitabın sayfalarını çevirdiğini düşün. continue, "bu sayfayı atla, sonrakine geç" demek. break, "kitabı kapat, okumayı bırak" demek. Etiketli break ise "bu kitabı kapat ve raflara geri koy" — iç içe döngülerin tamamından çıkmak gibi.
break — Döngüden Çıkış
break ifadesi, içinde bulunduğu döngüyü anında sonlandırır. Döngünün koşulu hâlâ true olsa bile çıkar.
for (int i = 1; i <= 100; i++) {
if (i == 5) {
break; // Döngüden çık
}
System.out.println(i);
}
System.out.println("Döngü bitti.");Çıktı:
1
2
3
4
Döngü bitti.i 5 olduğunda break çalışır ve döngü tamamen sona erer. 5 yazdırılmaz çünkü break, println'den önce.
Örnek: Dizide Arama
String[] isimler = {"Ali", "Veli", "Ayşe", "Fatma", "Mehmet"};
String aranan = "Ayşe";
boolean bulundu = false;
for (String isim : isimler) {
if (isim.equals(aranan)) {
bulundu = true;
break; // Bulduk, aramaya devam etmeye gerek yok
}
}
if (bulundu) {
System.out.println(aranan + " listede var!");
} else {
System.out.println(aranan + " listede yok.");
}"Ayşe" bulununca geri kalan elemanları kontrol etmenin anlamı yok. break ile gereksiz işlemden kurtuluyoruz.
Örnek: İlk Negatif Sayıyı Bulma
int[] veriler = {12, 45, 78, -3, 56, -8, 90};
int ilkNegatif = 0;
boolean negatifVar = false;
for (int veri : veriler) {
if (veri < 0) {
ilkNegatif = veri;
negatifVar = true;
break;
}
}
if (negatifVar) {
System.out.println("İlk negatif sayı: " + ilkNegatif); // -3
} else {
System.out.println("Negatif sayı yok.");
}while ile break
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.print("Bir sayı girin (0 ile çıkış): ");
int sayi = scanner.nextInt();
if (sayi == 0) {
break;
}
System.out.println("Girdiğiniz sayı: " + sayi);
}
System.out.println("Program bitti.");while (true) sonsuz döngü ama break ile kontrollü çıkış yapıyoruz. Bu, döngü koşulunu gövdenin ortasına koymamızı sağlar.
continue — Turu Atlama
continue ifadesi, döngünün mevcut turunu atlar ve bir sonraki tura geçer. Döngüden çıkmaz, sadece o anki iterasyonu sonlandırır.
for (int i = 1; i <= 10; i++) {
if (i % 3 == 0) {
continue; // 3'ün katlarını atla
}
System.out.print(i + " ");
}
// 1 2 4 5 7 8 103, 6 ve 9 atlandı çünkü continue sonraki satırları (println) çalıştırmadan bir sonraki tura geçti.
continue'nun Akışı
for döngüsünde: güncelleme ifadesine (
i++) gider, sonra koşulu kontrol eder.while/do-while'da: doğrudan koşul kontrolüne gider.
// for'da continue — i++ hâlâ çalışır
for (int i = 0; i < 5; i++) {
if (i == 2) continue;
System.out.print(i + " ");
}
// 0 1 3 4
// while'da continue — güncellemeyi unutma!
int i = 0;
while (i < 5) {
i++; // Güncelleme continue'dan ÖNCE olmalı!
if (i == 3) continue;
System.out.print(i + " ");
}
// 1 2 4 5⚠️ Dikkat: while döngüsünde
continuekullanırken, güncelleme ifadesinin continue'dan önce olmasına dikkat et. Aksi halde sonsuz döngüye girersin:
int i = 0;
while (i < 5) {
if (i == 3) {
continue; // i++ hiç çalışmaz → sonsuz döngü!
}
System.out.println(i);
i++;
}Örnek: Sadece Çift Sayıları İşleme
int[] sayilar = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (int sayi : sayilar) {
if (sayi % 2 != 0) {
continue; // Tek sayıları atla
}
System.out.println(sayi + " çift sayıdır, karesi: " + (sayi * sayi));
}Örnek: Geçersiz Veriyi Atlama
String[] veriler = {"10", "abc", "20", "", "30", null, "40"};
for (String veri : veriler) {
if (veri == null || veri.isEmpty()) {
continue; // null veya boş veriyi atla
}
try {
int sayi = Integer.parseInt(veri);
System.out.println("İşlendi: " + sayi);
} catch (NumberFormatException e) {
System.out.println("Atlandı (sayı değil): " + veri);
}
}Bu, gerçek dünyada çok yaygın bir desen — "kötü veriyi atla, iyi veriyi işle".
break vs continue — Fark
break: Döngüyü TAMAMEN sonlandırır.
continue: Sadece MEVCUT TURU atlar, döngü devam eder.Görsel karşılaştırma:
System.out.println("--- break ---");
for (int i = 1; i <= 5; i++) {
if (i == 3) break;
System.out.print(i + " ");
}
// 1 2
System.out.println("\n--- continue ---");
for (int i = 1; i <= 5; i++) {
if (i == 3) continue;
System.out.print(i + " ");
}
// 1 2 4 5break'te döngü 3'te bitti, continue'da sadece 3 atlandı.
İç İçe Döngülerde break ve continue
break ve continue sadece en içteki döngüyü etkiler:
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
if (j == 2) break;
System.out.println("i=" + i + ", j=" + j);
}
}Çıktı:
i=1, j=1
i=2, j=1
i=3, j=1break sadece iç döngüyü (j döngüsünü) kırdı. Dış döngü (i) çalışmaya devam etti. Her i değeri için iç döngü j=1'de break oldu.
Peki ya dış döngüden de çıkmak istersek? İşte burada etiketli döngüler devreye girer.
Etiketli Döngüler (Labeled Loops)
Java'da döngülere etiket (label) verebilirsin. Sonra break etiket; veya continue etiket; ile o belirli döngüyü hedefleyebilirsin.
etiket:
for (...) {
for (...) {
break etiket; // Dış döngüden çık
continue etiket; // Dış döngünün bir sonraki turuna geç
}
}Labeled break — Dış Döngüden Çıkış
dis:
for (int i = 1; i <= 5; i++) {
for (int j = 1; j <= 5; j++) {
if (i * j > 10) {
System.out.println("i*j > 10 → i=" + i + ", j=" + j);
break dis; // Dış döngüden çık
}
System.out.print(i * j + " ");
}
System.out.println();
}
System.out.println("Döngü tamamen bitti.");Çıktı:
1 2 3 4 5
2 4 6 8 10
i*j > 10 → i=3, j=4
Döngü tamamen bitti.i=3, j=4 olduğunda 3*4=12 > 10 koşulu sağlandı ve break dis ile her iki döngüden de çıkıldı.
Labeled continue — Dış Döngünün Sonraki Turuna Geçme
dis:
for (int i = 1; i <= 4; i++) {
for (int j = 1; j <= 4; j++) {
if (j == 3) {
continue dis; // Dış döngünün sonraki turuna geç
}
System.out.print("(" + i + "," + j + ") ");
}
System.out.println(); // Bu satır hiç çalışmaz!
}Çıktı:
(1,1) (1,2) (2,1) (2,2) (3,1) (3,2) (4,1) (4,2) Her j=3 olduğunda continue dis dış döngünün sonraki turuna geçiyor. İç döngünün geri kalanı ve println() çalışmıyor.
Pratik Örnek: 2D Dizide Eleman Arama
int[][] matris = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
int aranan = 5;
int satirIndex = -1, sutunIndex = -1;
arama:
for (int i = 0; i < matris.length; i++) {
for (int j = 0; j < matris[i].length; j++) {
if (matris[i][j] == aranan) {
satirIndex = i;
sutunIndex = j;
break arama;
}
}
}
if (satirIndex != -1) {
System.out.printf("%d → [%d][%d]%n", aranan, satirIndex, sutunIndex);
} else {
System.out.println(aranan + " bulunamadı.");
}
// 5 → [1][1]break arama ile aranan elemanı bulur bulmaz her iki döngüden de çıkıyoruz. Label olmadan sadece iç döngüden çıkardık, dış döngü devam ederdi.
Pratik Örnek: Satır Bazlı İşlem Atlama
int[][] veriler = {
{10, 20, 30},
{-1, 40, 50}, // Negatif var, bu satırı atla
{60, 70, 80},
{90, -5, 100} // Negatif var, bu satırı atla
};
int toplam = 0;
satirDongusu:
for (int[] satir : veriler) {
for (int deger : satir) {
if (deger < 0) {
System.out.println("Negatif değer bulundu, satır atlanıyor.");
continue satirDongusu;
}
toplam += deger;
}
}
System.out.println("Toplam (negatif satırlar hariç): " + toplam);
// 10+20+30 + 60+70+80 = 270Bir satırda negatif değer varsa o satırın tamamını atlıyoruz. continue satirDongusu dış döngünün (satır döngüsü) sonraki turuna geçer.
Etiketli Döngüler — Ne Zaman Kullanmalı?
Etiketli döngüler güçlü ama dikkatli kullanılmalı. Kodu karmaşıklaştırabilir ve goto benzeri bir akış yaratabilir.
✅ Kullan:
2D arama — İç içe döngülerden tek seferde çıkmak için
Satır bazlı atlama — İç döngüdeki bir koşula göre dış döngüyü kontrol etmek için
Performans kritik kod — Alternatif yöntemler (boolean flag) gereksiz kontrol ekler
❌ Kullanma:
3+ seviye iç içe döngüde — Kodu metotlara ayır
Karmaşık mantık için — Okunabilirlik kaybolur
Alışkanlık olarak — Sadece gerçekten gerektiğinde
Alternatif: Boolean Flag ile Çıkış
Etiketli break yerine boolean flag de kullanabilirsin:
// Etiketli break ile
arama:
for (int i = 0; i < matris.length; i++) {
for (int j = 0; j < matris[i].length; j++) {
if (matris[i][j] == aranan) {
break arama;
}
}
}
// Boolean flag ile (etiket yerine)
boolean bulundu = false;
for (int i = 0; i < matris.length && !bulundu; i++) {
for (int j = 0; j < matris[i].length && !bulundu; j++) {
if (matris[i][j] == aranan) {
bulundu = true;
}
}
}Her ikisi de aynı işi yapıyor. Flag versiyonu biraz daha uzun ama bazı geliştiriciler etiketlerden kaçınır. Hangi stili tercih ettiğin kişisel/takım tercihi.
Alternatif: Metoda Ayırma (En İyisi)
// En temiz çözüm — aramayı metoda ayır
static int[] bul(int[][] matris, int aranan) {
for (int i = 0; i < matris.length; i++) {
for (int j = 0; j < matris[i].length; j++) {
if (matris[i][j] == aranan) {
return new int[]{i, j}; // return her şeyden çıkar
}
}
}
return null; // Bulunamadı
}return tüm metottan çıktığı için etiketli break'e gerek kalmaz. Bu, en temiz ve en okunabilir çözümdür.
break ve continue ile switch
break aynı zamanda switch'te de kullanılır. Eğer switch bir döngünün içindeyse, break switch'ten mi yoksa döngüden mi çıkacağı karışabilir:
for (int i = 0; i < 10; i++) {
switch (i % 3) {
case 0:
System.out.println(i + " → 3'e bölünür");
break; // Bu break SWITCH'ten çıkıyor, döngüden DEĞİL!
case 1:
System.out.println(i + " → kalan 1");
break;
}
// Döngü devam eder
}Döngüden çıkmak istiyorsan etiketli break kullanmalısın:
dongu:
for (int i = 0; i < 10; i++) {
switch (i % 3) {
case 0:
if (i > 5) break dongu; // DÖNGÜDEN çıkar
System.out.println(i + " → 3'e bölünür");
break; // SWITCH'ten çıkar
}
}💡 İpucu: Enhanced switch (
->) kullanıyorsanbreakgerekmez. Bu durumda döngüdekibreakkarışıklık yaratmaz.
Pratik Örnek: Asal Sayıları Listeleme
1'den 100'e kadar asal sayıları bul:
System.out.println("1-100 arası asal sayılar:");
for (int sayi = 2; sayi <= 100; sayi++) {
boolean asalMi = true;
for (int bolen = 2; bolen <= Math.sqrt(sayi); bolen++) {
if (sayi % bolen == 0) {
asalMi = false;
break; // Bölen bulduk, daha fazla aramaya gerek yok
}
}
if (asalMi) {
System.out.print(sayi + " ");
}
}İç döngüdeki break sayesinde, sayının asal olmadığını anladığımız anda aramayı durduruyoruz. Bu performansı önemli ölçüde artırır.
Pratik Örnek: Kelime Arama
Bir cümlede belirli bir kelimeyi bul ve pozisyonunu döndür:
String cumle = "Java programlama dili çok güçlüdür";
String[] kelimeler = cumle.split(" ");
String aranan = "dili";
for (int i = 0; i < kelimeler.length; i++) {
if (kelimeler[i].equals(aranan)) {
System.out.println("'" + aranan + "' kelimesi " + (i + 1) + ". sırada bulundu.");
break;
}
}Pratik Örnek: Tekrar Eden İlk Elemanı Bulma
int[] dizi = {5, 3, 8, 1, 3, 7, 5, 2};
int tekrarEden = -1;
dis:
for (int i = 0; i < dizi.length; i++) {
for (int j = i + 1; j < dizi.length; j++) {
if (dizi[i] == dizi[j]) {
tekrarEden = dizi[i];
break dis;
}
}
}
if (tekrarEden != -1) {
System.out.println("İlk tekrar eden: " + tekrarEden); // 5
}return vs break — Karıştırma!
Yeni başlayanlar break ve return'ü karıştırır:
`break`: Döngüden veya switch'ten çıkar, metot devam eder.
`return`: Metottan çıkar, döngü de biter (çünkü metot bitti).
public static void ara(int[] dizi, int hedef) {
for (int i = 0; i < dizi.length; i++) {
if (dizi[i] == hedef) {
System.out.println("Bulundu: index " + i);
return; // Metottan tamamen çık
}
}
System.out.println("Bulunamadı"); // break olsaydı burası çalışırdı
}Döngü Kontrol Desenleri
Pratikte break ve continue belirli kalıplarda kullanılır. Bu kalıpları tanımak önemli.
Desen 1: İlk Eşleşmeyi Bul ve Çık
// Bir koleksiyonda ilk uygun elemanı bul
String sonuc = null;
for (String eleman : liste) {
if (kosulKarsilaniyorMu(eleman)) {
sonuc = eleman;
break;
}
}Desen 2: Filtrele ve İşle
// Uygun olmayanları atla, kalanları işle
for (Veri veri : veriler) {
if (!gecerliMi(veri)) continue;
if (!aktifMi(veri)) continue;
isle(veri);
}Bu desen "guard clause in loops" olarak bilinir. Her continue bir filtre gibi davranır. Kodu düz tutmak için çok etkili — iç içe if'lerden kaçınırsın.
Desen 3: İşle ve Dur
// N adet geçerli eleman işle, sonra dur
int islenen = 0;
for (Veri veri : veriler) {
if (!gecerliMi(veri)) continue;
isle(veri);
islenen++;
if (islenen >= 10) break; // 10 tane yeter
}Desen 4: Hata Durumunda Erken Çıkış
boolean basarili = true;
for (Dosya dosya : dosyalar) {
if (!dosya.var()) {
System.out.println("Dosya bulunamadı: " + dosya.ad());
basarili = false;
break;
}
dosya.isle();
}
if (basarili) {
System.out.println("Tüm dosyalar işlendi.");
}Orta Noktada Çıkış Deseni (Loop-and-a-Half)
Bazen döngüden çıkış koşulunu ne başta ne sonda, döngünün ortasında kontrol etmek istersin:
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.print("Bir sayı girin: ");
if (!scanner.hasNextInt()) {
System.out.println("Geçersiz giriş, çıkılıyor.");
break;
}
int sayi = scanner.nextInt();
if (sayi == 0) {
System.out.println("Sıfır girildi, çıkılıyor.");
break;
}
System.out.println("Sayının karesi: " + (sayi * sayi));
}Bu desende kontrol noktaları döngünün farklı yerlerinde. while(true) + break kombinasyonu bunu mümkün kılıyor. Bazı programcılar bu deseni sevmez ("sonsuz döngü kötü" der), ama doğru kullanıldığında çok okunaklı ve etkilidir.
Performans Etkileri
break ve continue'nun performans üzerinde doğrudan bir maliyeti yoktur. Aslında performansı artırırlar çünkü gereksiz işlemi önlerler.
break ile Erken Çıkış
// break olmadan — tüm diziyi gezer
boolean var = false;
for (int sayi : dizi) {
if (sayi == aranan) {
var = true;
}
}
// break ile — bulunca çıkar (ortalama yarı süre)
boolean var = false;
for (int sayi : dizi) {
if (sayi == aranan) {
var = true;
break; // Gereksiz iterasyonları atlıyoruz
}
}10.000 elemanlı bir dizide aranan eleman 5. sıradaysa, break olmadan 10.000, break ile sadece 5 iterasyon yapılır. Bu devasa bir fark.
continue ile Gereksiz İşlem Atlama
for (String satir : dosyaSatirlari) {
if (satir.startsWith("#")) continue; // Yorum satırını atla
if (satir.isBlank()) continue; // Boş satırı atla
// Ağır işleme sadece geçerli satırlar için yapılır
agirIslem(satir);
}Yaygın Hatalar
1. while'da continue ile Sonsuz Döngü
int i = 0;
while (i < 10) {
if (i == 5) {
continue; // i++ asla çalışmaz → sonsuz döngü!
}
System.out.println(i);
i++;
}
// DÜZELTME
int i = 0;
while (i < 10) {
if (i == 5) {
i++; // Güncellemeyi continue'dan ÖNCE yap
continue;
}
System.out.println(i);
i++;
}2. Yanlış Döngüyü break/continue ile Hedefleme
// HATALI — break sadece iç döngüyü kırar, dış devam eder
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
if (kosul) break; // Sadece j döngüsünden çıkar!
}
// i döngüsü devam eder
}
// DÜZELTME — etiketli break kullan
dis:
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
if (kosul) break dis; // Her iki döngüden de çıkar
}
}3. Gereksiz break/continue Kullanımı
// GEREKSIZ continue — if ile de yapılır
for (int i = 0; i < 10; i++) {
if (i % 2 == 0) continue;
System.out.println(i);
}
// AYNI ŞEY — daha okunabilir olabilir
for (int i = 0; i < 10; i++) {
if (i % 2 != 0) {
System.out.println(i);
}
}Hangisi daha iyi? Eğer continue'dan sonraki kod uzunsa continue daha okunaklı (girintiyi azaltır). Kısa kodlarda if yeterli.
Özet
`break` döngüyü tamamen sonlandırır — arama bulunduğunda, sonsuz döngüden çıkışta kullan.
`continue` mevcut turu atlar, döngü devam eder — geçersiz veriyi atlamak, sadece belirli elemanları işlemek için kullan.
Etiketli (labeled) break/continue iç içe döngülerde dış döngüyü hedefler — 2D arama gibi durumlarda kullanışlı.
while'da continue kullanırken güncelleme ifadesinin continue'dan önce olmasına dikkat et — aksi halde sonsuz döngü!
switch içindeki break döngüden değil switch'ten çıkar — karışıklık için etiketli break kullan.
Alternatif olarak metoda ayırma düşün —
returnile hem döngüden hem metottan çıkarsın, en temiz çözüm genellikle budur.Döngü kontrol desenlerini öğren: "bul ve çık", "filtrele ve işle", "işle ve dur" — bu kalıplar her projede karşına çıkacak.
AI Asistan
Sorularını yanıtlamaya hazır