← Kursa Dön
📄 Text · 15 min

Scanner ile Kullanıcı Girdisi

Şimdiye kadar yazdığımız programların hepsi tek yönlüydü — program konuştu, biz dinledik. Ama gerçek programlar interaktiftir: kullanıcıdan veri alır, işler ve sonuç üretir. Bu derste Java'da kullanıcıdan girdi almanın temel yolunu öğreneceksin: Scanner sınıfı.

Bir program, kullanıcıyla konuşamıyorsa monolog yapar. Scanner ile programlarına diyalog yeteneği kazandıracaksın.


Scanner Nedir?

Scanner, Java'nın standart kütüphanesinde bulunan bir sınıftır. java.util paketinin içinde yaşar. Adı üstünde: girdi kaynağını tarar (scan) ve içinden veri okur.

Analoji: Scanner'ı bir garson gibi düşün. Müşteriye (kullanıcıya) "Ne istersiniz?" diye sorar, cevabı alır ve mutfağa (programına) iletir. Garson yemek yapmaz, sadece sipariş alır.

Scanner sadece klavyeden değil, dosyalardan ve string'lerden de okuyabilir. Ama bu derste klavyeden (standart girdi — System.in) okumaya odaklanacağız.


İlk Scanner Kullanımı

import java.util.Scanner;  // Scanner'ı import et

public class IlkScanner {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);  // Klavyeyi dinlemeye başla

        System.out.print("Adın ne? ");  // Kullanıcıya sor
        String isim = scanner.nextLine();  // Cevabı oku

        System.out.println("Merhaba, " + isim + "!");  // Cevabı kullan

        scanner.close();  // İşin bitince kapat
    }
}

Çalıştırma:

Adın ne? Ali
Merhaba, Ali!

Satır satır ne oldu:

  1. `import java.util.Scanner;` → Scanner sınıfını programa dahil ettik. Bu satır olmadan Scanner kullanamazsın.

  2. `Scanner scanner = new Scanner(System.in);` → Yeni bir Scanner nesnesi oluşturdum. System.in = klavye girdisi.

  3. `System.out.print("Adın ne? ");`println değil print kullandık — böylece kullanıcı aynı satırda yazar.

  4. `scanner.nextLine();` → Kullanıcı bir satır yazıp Enter'a basana kadar bekler, sonra yazdığını String olarak döndürür.

  5. `scanner.close();` → Scanner'ı kapattık. Kaynak sızıntısını önler.


Scanner Metodları

Scanner farklı veri tipleri için farklı metodlar sunar:

MetodNe OkurDönüş TipiÖrnek Girdi
nextLine()Satırın tamamınıStringMerhaba Dünya
next()Sonraki kelimeyiStringMerhaba
nextInt()Tam sayıint42
nextDouble()Ondalıklı sayıdouble3.14
nextLong()Büyük tam sayılong9000000000
nextFloat()Ondalıklı sayıfloat3.14
nextBoolean()Booleanbooleantrue
hasNextInt()Sıradaki int mi?boolean
hasNextLine()Başka satır var mı?boolean

Farklı Tipleri Okuma

import java.util.Scanner;

public class FarkliTipler {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.print("Adınız: ");
        String ad = scanner.nextLine();

        System.out.print("Yaşınız: ");
        int yas = scanner.nextInt();

        System.out.print("Boyunuz (m): ");
        double boy = scanner.nextDouble();

        System.out.println("\n--- Bilgileriniz ---");
        System.out.println("Ad: " + ad);
        System.out.println("Yaş: " + yas);
        System.out.println("Boy: " + boy + " m");

        scanner.close();
    }
}

Çalıştırma:

Adınız: Zeynep
Yaşınız: 22
Boyunuz (m): 1.68

--- Bilgileriniz ---
Ad: Zeynep
Yaş: 22
Boy: 1.68 m

next() vs nextLine()

Bu ikisinin farkını anlamak önemli:

import java.util.Scanner;

public class NextVsNextLine {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.print("next() ile oku: ");
        String kelime = scanner.next();       // Sadece ilk kelimeyi okur
        System.out.println("Okunan: " + kelime);

        scanner.nextLine();  // Kalan kısmı temizle (birazdan açıklayacağız)

        System.out.print("nextLine() ile oku: ");
        String satir = scanner.nextLine();    // Tüm satırı okur
        System.out.println("Okunan: " + satir);

        scanner.close();
    }
}

Girdi ve çıktı:

next() ile oku: Java çok güzel
Okunan: Java
nextLine() ile oku: Programlama eğlenceli
Okunan: Programlama eğlenceli

next() boşluğa kadar okur (tek kelime). nextLine() Enter'a kadar okur (tüm satır).


Input Buffer Sorunu (En Önemli Konu!)

Bu, Scanner kullanırken herkesin başına gelen ve herkesin kafasını karıştıran bir sorundur. Dikkatli oku.

Sorun

nextInt(), nextDouble() gibi metodlar sayıyı okur ama Enter karakterini (\n) okumaz. Bu karakter buffer'da kalır. Hemen arkasından nextLine() çağırırsan, nextLine() buffer'daki \n'i okur ve boş string döndürür.

import java.util.Scanner;

public class BufferSorunu {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.print("Yaşınız: ");
        int yas = scanner.nextInt();       // Sayıyı okur, \n buffer'da kalır

        System.out.print("Adınız: ");
        String ad = scanner.nextLine();    // Buffer'daki \n'i okur — boş string!

        System.out.println("Ad: '" + ad + "'");  // Boş!
        System.out.println("Yaş: " + yas);

        scanner.close();
    }
}

Çalıştırma:

Yaşınız: 25
Adınız: Ad: ''
Yaş: 25

Kullanıcıya isim sorulmadı bile! nextLine() buffer'daki \n'i okuyup hemen döndü.

Çözüm: Buffer'ı Temizle

nextInt() veya nextDouble()'dan sonra fazladan bir nextLine() çağırarak buffer'ı temizle:

import java.util.Scanner;

public class BufferCozum {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.print("Yaşınız: ");
        int yas = scanner.nextInt();
        scanner.nextLine();  // ← Buffer'ı temizle! Bu satır kritik.

        System.out.print("Adınız: ");
        String ad = scanner.nextLine();  // Artık düzgün çalışır

        System.out.println("Ad: " + ad);
        System.out.println("Yaş: " + yas);

        scanner.close();
    }
}

Çalıştırma:

Yaşınız: 25
Adınız: Ali
Ad: Ali
Yaş: 25

⚠️ Dikkat: Bu, Java'nın en bilinen Scanner tuzağıdır. nextInt(), nextDouble(), next() gibi metodlardan sonra nextLine() kullanacaksan, arada fazladan bir scanner.nextLine() çağrısı yap.

Alternatif Çözüm: Her Şeyi nextLine() ile Oku

Bazı geliştiriciler sorunu tamamen ortadan kaldırmak için her şeyi nextLine() ile okuyup sonra dönüştürür:

import java.util.Scanner;

public class HerSeyNextLine {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.print("Yaşınız: ");
        int yas = Integer.parseInt(scanner.nextLine());  // String → int

        System.out.print("Boyunuz: ");
        double boy = Double.parseDouble(scanner.nextLine());  // String → double

        System.out.print("Adınız: ");
        String ad = scanner.nextLine();

        System.out.printf("%s, %d yaşında, %.2f m%n", ad, yas, boy);

        scanner.close();
    }
}

Bu yaklaşım buffer sorununu tamamen ortadan kaldırır. Ama kullanıcı sayı yerine harf girerse NumberFormatException hatası fırlatır. İleride exception handling öğrendiğimizde bunu da ele alacağız.


Girdi Doğrulama (Basit)

Kullanıcıya güvenme. Sayı beklediğin yere metin girebilir. hasNextInt() gibi metodlarla kontrol edebilirsin:

import java.util.Scanner;

public class GirdiDogrulama {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.print("Bir tam sayı girin: ");

        if (scanner.hasNextInt()) {
            int sayi = scanner.nextInt();
            System.out.println("Girdiğiniz sayı: " + sayi);
        } else {
            System.out.println("Bu bir tam sayı değil!");
        }

        scanner.close();
    }
}

Çalıştırma:

Bir tam sayı girin: 42
Girdiğiniz sayı: 42

Bir tam sayı girin: abc
Bu bir tam sayı değil!

Döngü ile kullanıcıdan doğru girdi alana kadar sorma:

import java.util.Scanner;

public class DogruGirdiAl {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int sayi = 0;
        boolean gecerli = false;

        while (!gecerli) {
            System.out.print("Bir tam sayı girin: ");
            if (scanner.hasNextInt()) {
                sayi = scanner.nextInt();
                gecerli = true;
            } else {
                System.out.println("Geçersiz! Lütfen sayı girin.");
                scanner.next();  // Geçersiz girdiyi temizle
            }
        }

        System.out.println("Teşekkürler! Girdiğiniz: " + sayi);
        scanner.close();
    }
}

Locale Sorunu (Ondalık Ayırıcı)

Türkiye'de ondalık ayırıcı virgül (3,14), ABD'de nokta (3.14). Scanner, sistemin locale'ine göre davranır. Türkçe bir sistemde nextDouble() nokta beklemeyebilir.

import java.util.Scanner;
import java.util.Locale;

public class LocaleOrnegi {
    public static void main(String[] args) {
        // ABD locale'i ile Scanner oluştur (nokta = ondalık ayırıcı)
        Scanner scanner = new Scanner(System.in).useLocale(Locale.US);

        System.out.print("Bir ondalıklı sayı girin (nokta ile): ");
        double sayi = scanner.nextDouble();
        System.out.println("Girdiğiniz: " + sayi);

        scanner.close();
    }
}

💡 İpucu: scanner.useLocale(Locale.US) kullanarak ondalık ayırıcının her zaman nokta olmasını sağlayabilirsin. Bu, kodunun farklı ülkelerdeki sistemlerde tutarlı çalışmasını garanti eder.


Mini Proje 1: Selamlama Programı

import java.util.Scanner;

public class Selamlama {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.println("=== Hoş Geldiniz! ===");
        System.out.println();

        System.out.print("Adınız: ");
        String ad = scanner.nextLine();

        System.out.print("Soyadınız: ");
        String soyad = scanner.nextLine();

        System.out.print("Doğum yılınız: ");
        int dogumYili = Integer.parseInt(scanner.nextLine());

        int yas = 2026 - dogumYili;

        System.out.println();
        System.out.println("=== Bilgileriniz ===");
        System.out.printf("Ad Soyad: %s %s%n", ad, soyad);
        System.out.printf("Yaş: %d%n", yas);

        if (yas < 18) {
            System.out.println("Henüz reşit değilsiniz.");
        } else if (yas < 65) {
            System.out.println("Çalışma çağındasınız.");
        } else {
            System.out.println("Emeklilik hakkınız var.");
        }

        scanner.close();
    }
}

Çalıştırma:

=== Hoş Geldiniz! ===

Adınız: Ayşe
Soyadınız: Demir
Doğum yılınız: 2001

=== Bilgileriniz ===
Ad Soyad: Ayşe Demir
Yaş: 25
Çalışma çağındasınız.

Mini Proje 2: Basit Hesap Makinesi

import java.util.Scanner;

public class HesapMakinesi {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.println("╔═══════════════════════════╗");
        System.out.println("║   BASİT HESAP MAKİNESİ   ║");
        System.out.println("╚═══════════════════════════╝");
        System.out.println();

        System.out.print("Birinci sayıyı girin: ");
        double sayi1 = Double.parseDouble(scanner.nextLine());

        System.out.print("İkinci sayıyı girin: ");
        double sayi2 = Double.parseDouble(scanner.nextLine());

        System.out.print("İşlem seçin (+, -, *, /): ");
        String islem = scanner.nextLine().trim();

        double sonuc = 0;
        boolean gecerli = true;

        switch (islem) {
            case "+":
                sonuc = sayi1 + sayi2;
                break;
            case "-":
                sonuc = sayi1 - sayi2;
                break;
            case "*":
                sonuc = sayi1 * sayi2;
                break;
            case "/":
                if (sayi2 != 0) {
                    sonuc = sayi1 / sayi2;
                } else {
                    System.out.println("Hata: Sıfıra bölme yapılamaz!");
                    gecerli = false;
                }
                break;
            default:
                System.out.println("Hata: Geçersiz işlem!");
                gecerli = false;
        }

        if (gecerli) {
            System.out.printf("%.2f %s %.2f = %.2f%n", sayi1, islem, sayi2, sonuc);
        }

        scanner.close();
    }
}

Çalıştırma:

╔═══════════════════════════╗
║   BASİT HESAP MAKİNESİ   ║
╚═══════════════════════════╝

Birinci sayıyı girin: 15.5
İkinci sayıyı girin: 4.2
İşlem seçin (+, -, *, /): *
15.50 * 4.20 = 65.10

Mini Proje 3: Not Ortalaması Hesaplama

import java.util.Scanner;

public class NotOrtalamasi {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.print("Kaç ders var? ");
        int dersSayisi = Integer.parseInt(scanner.nextLine());

        double toplam = 0;

        for (int i = 1; i <= dersSayisi; i++) {
            System.out.printf("%d. dersin notu (0-100): ", i);
            double not_ = Double.parseDouble(scanner.nextLine());
            toplam += not_;
        }

        double ortalama = toplam / dersSayisi;

        System.out.println("\n=== SONUÇ ===");
        System.out.printf("Toplam: %.1f%n", toplam);
        System.out.printf("Ortalama: %.2f%n", ortalama);

        // Harf notu
        String harfNotu;
        if (ortalama >= 90) harfNotu = "AA";
        else if (ortalama >= 80) harfNotu = "BA";
        else if (ortalama >= 70) harfNotu = "BB";
        else if (ortalama >= 60) harfNotu = "CB";
        else if (ortalama >= 50) harfNotu = "CC";
        else harfNotu = "FF";

        System.out.println("Harf Notu: " + harfNotu);

        if (ortalama >= 50) {
            System.out.println("Durum: GEÇTİ ✓");
        } else {
            System.out.println("Durum: KALDI ✗");
        }

        scanner.close();
    }
}

Çalıştırma:

Kaç ders var? 3
1. dersin notu (0-100): 85
2. dersin notu (0-100): 72
3. dersin notu (0-100): 91

=== SONUÇ ===
Toplam: 248.0
Ortalama: 82.67
Harf Notu: BA
Durum: GEÇTİ ✓

Scanner Kapatma ve Kaynak Yönetimi

Scanner'ı kapamak iyi bir alışkanlıktır. İki yöntem var:

Manuel Kapatma

Scanner scanner = new Scanner(System.in);
// ... kullanım ...
scanner.close();  // Manuel kapat

Try-with-Resources (Önerilen)

Java 7'den itibaren try-with-resources kullanabilirsin. Blok bitince Scanner otomatik kapanır:

import java.util.Scanner;

public class TryWithResources {
    public static void main(String[] args) {
        try (Scanner scanner = new Scanner(System.in)) {
            System.out.print("Bir sayı girin: ");
            int sayi = scanner.nextInt();
            System.out.println("Girdiğiniz: " + sayi);
        }  // scanner.close() otomatik çağrılır
    }
}

⚠️ Dikkat: System.in üzerindeki Scanner'ı kapattığında, System.in de kapanır ve tekrar açılamaz. Yani programda ikinci bir Scanner oluşturamazsın. Küçük programlarda sorun olmaz ama büyük projelerde Scanner'ı başta bir kere oluşturup tüm program boyunca kullanmak daha iyi.


Delimiter (Ayırıcı) Değiştirme

Scanner varsayılan olarak boşluk ve yeni satır karakterlerini ayırıcı olarak kullanır. Bunu değiştirebilirsin:

import java.util.Scanner;

public class DelimiterOrnegi {
    public static void main(String[] args) {
        // Virgülle ayrılmış veri oku
        String veri = "Ali,25,Istanbul,Muhendis";
        Scanner scanner = new Scanner(veri);
        scanner.useDelimiter(",");

        String isim = scanner.next();
        int yas = scanner.nextInt();
        String sehir = scanner.next();
        String meslek = scanner.next();

        System.out.printf("%s, %d yaşında, %s'da %s%n", isim, yas, sehir, meslek);

        scanner.close();
    }
}

Çıktı:

Ali, 25 yaşında, Istanbul'da Muhendis

Bu özellik CSV benzeri formatları okurken çok işe yarar.


Scanner Alternatifleri (Kısa Bakış)

Scanner en basit yol ama tek yol değil:

BufferedReader (Daha Hızlı)

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class BufferedReaderOrnegi {
    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

        System.out.print("Adınız: ");
        String isim = reader.readLine();

        System.out.print("Yaşınız: ");
        int yas = Integer.parseInt(reader.readLine());

        System.out.printf("Merhaba %s, %d yaşındasın!%n", isim, yas);
    }
}

BufferedReader, Scanner'dan daha hızlıdır çünkü daha az işlem yapar. Ama kullanımı biraz daha zahmetli — her şeyi String olarak okur, tip dönüşümünü sen yaparsın.

Console Sınıfı (Parola Okuma)

import java.io.Console;

public class ConsoleOrnegi {
    public static void main(String[] args) {
        Console console = System.console();
        if (console != null) {
            String isim = console.readLine("Kullanıcı adı: ");
            char[] parola = console.readPassword("Parola: ");  // Ekranda gözükmez!
            System.out.println("Giriş yapılıyor: " + isim);
        }
    }
}

Console.readPassword() parolayı ekranda göstermeden okur. Güvenlik gerektiren uygulamalar için kullanılır. Ama IDE'lerin console'unda çalışmayabilir — terminalde çalıştırman gerekir.


Sık Yapılan Hatalar

1. Import Unutmak

// HATA — import yok
public class Test {
    public static void main(String[] args) {
        Scanner s = new Scanner(System.in);  // Derleme hatası!
    }
}

Çözüm: Dosyanın başına import java.util.Scanner; ekle.

2. InputMismatchException

System.out.print("Sayı girin: ");
int sayi = scanner.nextInt();
// Kullanıcı "abc" yazarsa → InputMismatchException!

Çözüm: hasNextInt() ile kontrol et veya nextLine() + Integer.parseInt() kullan.

3. Buffer Sorununu Unutmak

int yas = scanner.nextInt();
// scanner.nextLine();  ← BU SATIRI UNUTMAK
String isim = scanner.nextLine();  // Boş string döner!

Çözüm: nextInt() veya nextDouble()'dan sonra fazladan scanner.nextLine() çağır.


Özet

  • Scanner, java.util paketindeki bir sınıftır. import java.util.Scanner; ile dahil edilir ve new Scanner(System.in) ile oluşturulur.

  • `nextLine()` tüm satırı, `next()` tek kelimeyi, `nextInt()` tam sayıyı, `nextDouble()` ondalıklı sayıyı okur.

  • Input buffer sorunu en sık karşılaşılan tuzaktır: nextInt()/nextDouble() sonrası nextLine() kullanacaksan, arada fazladan bir scanner.nextLine() çağrısı yap.

  • Girdi doğrulama için hasNextInt(), hasNextDouble() gibi metodlar kullanılabilir.

  • Locale sorunu: scanner.useLocale(Locale.US) ile ondalık ayırıcıyı nokta olarak sabitleyebilirsin.

  • Scanner kullanımı bitince `close()` ile kapatmak veya try-with-resources kullanmak iyi bir alışkanlıktır.