Berk Akademi
Ana Sayfa
ÖZEL KODLAMA DERSLERİ
Yazılım Özel Ders
Tüm birebir programlara genel bakış
Python Yazılım Kursu
Sıfırdan ileri seviyeye birebir Python
Java Yazılım Kursu
OOP odaklı birebir Java eğitimi
AP Computer Science Principles
AP CSP sınav hazırlığı
GRUP DERSLERİ
Python & Django Masterclass
SINIRLI KONTENJAN
Java & Spring Boot Masterclass
SINIRLI KONTENJAN
C# .NET Masterclass
SINIRLI KONTENJAN
VİDEO DERSLER
Sıfırdan Temel Python Kursu
Kendi Hızında Öğren
ÜCRETSİZ
Seviye Testi
Ücretsiz — Python, Java, algoritma seviye testleri
Kariyerini Keşfet
Sertifika Doğrula
Belge numarası ve soyad ile doğrulama

ClassNotFoundException ve NoClassDefFoundError Arasındaki Fark

Yazar: Berk Keskin 29.08.2026 ~11 dk okuma 1 Okunma
classnotfoundexception-noclassdeffounderror-farki

ClassNotFoundException ile NoClassDefFoundError arasındaki temel fark, birinin bir istisna (exception), diğerinin ise bir hata (error) olmasıdır: ClassNotFoundException, JVM bir sınıfı adıyla ararken (genellikle Class.forName(), reflection veya JDBC sürücü yükleme sırasında) o sınıfı classpath üzerinde hiç bulamadığında fırlatılır. NoClassDefFoundError ise tam tersine, sınıf derleme sırasında mevcuttu ve kod ona referans veriyordu, fakat çalışma zamanında o sınıfın .class dosyası veya onu içeren JAR artık erişilebilir değildir ya da sınıfın statik başlatıcısı (static initializer) bir hata fırlatarak yüklemeyi yarıda bırakmıştır.

Kısacası ilki "bu sınıfı hiç tanımıyorum", ikincisi "bu sınıfı tanıyordum ama şimdi ona ulaşamıyorum veya yükleyemedim" anlamına gelir. Bu ayrımı doğru okumak, Java classpath sorunlarını ve JVM sınıf yükleme mekanizmasını hata ayıklarken zaman kazandıran en önemli adımdır.

Classpath ve JVM Sınıf Yükleme Mantığı

Bir Java programı çalışırken JVM, ihtiyaç duyduğu her sınıfı anında diskten veya JAR dosyasından okuyup belleğe yükler; bu işleme sınıf yükleme (class loading) denir ve tembel (lazy) çalışır, yani bir sınıf yalnızca ilk kez kullanıldığı anda yüklenir. Bu noktada iki farklı classpath kavramını birbirinden ayırmak gerekir: derleme zamanı classpath, javac komutunun veya IDE'nin kaynak kodu derlerken hangi kütüphanelere erişebildiğini belirler; çalışma zamanı classpath ise programı java komutuyla çalıştırırken JVM'in hangi JAR'lara ve dizinlere baktığını tanımlar. Bu iki classpath farklı olabilir ve genellikle sorunların kaynağı da tam burasıdır: kod derlenirken bir kütüphane mevcuttur ama uygulama paketlenip başka bir ortamda çalıştırıldığında o kütüphane classpath'e dahil edilmemiştir.

JVM'in sınıf arama mantığı, ClassLoader hiyerarşisi üzerinden işler. Bootstrap ClassLoader, Java'nın çekirdek sınıflarını yükler; Platform ClassLoader, JDK'nın modül sistemi içindeki sınıflardan sorumludur; Application ClassLoader ise uygulamanızın kendi sınıflarını ve classpath'te belirttiğiniz üçüncü parti kütüphaneleri yükler. Bir sınıfa ihtiyaç duyulduğunda önce üst seviyedeki loader'lara sorulur, onlar bulamazsa alt seviyeye inilir; bu delegasyon modeli sayesinde aynı isimde birden fazla sınıf tanımı varken bile tutarlı bir çözümleme sağlanır. Sınıf bulunamazsa ya da bulunduktan sonra başlatılamazsa, JVM bunu bir istisna veya hata olarak fırlatarak programı bilgilendirir.

Bu mekanizmayı derinlemesine kavramak, yalnızca hata mesajlarını çözmekle kalmaz, aynı zamanda büyük projelerde bağımlılık yönetimini ve modül tasarımını da anlamlı kılar. Sınıf yükleme, erişim belirleyiciler, statik bloklar ve JVM bellek modeli gibi temel konular birebir Java özel ders sürecinde uygulamalı örneklerle adım adım işlenir ve öğrenci kendi hatalarını okuyarak çözme alışkanlığı kazanır.

ClassNotFoundException Ne Zaman Oluşur

ClassNotFoundException Ne Zaman Oluşur

ClassNotFoundException, JVM'in bir sınıfı ismiyle dinamik olarak bulmaya çalıştığı ancak classpath üzerinde hiçbir yerde bulamadığı durumlarda fırlatılan, kontrol edilen (checked) bir istisnadır. Bu durum genellikle üç senaryoda karşımıza çıkar: Class.forName() ile bir sınıfın açıkça isim üzerinden yüklenmeye çalışılması, reflection API kullanılarak dinamik sınıf çözümlemesi yapılması ve JDBC sürücülerinin eskiden yaygın olan Class.forName("...") çağrısıyla kayıt edilmesi. Özellikle veritabanı bağlantı kodlarında sürücü JAR'ı classpath'e eklenmediğinde bu istisna sıkça görülür.

Aşağıdaki örnek, bu hatanın tipik bir tetikleyicisini gösterir:

public class SinifYukleyici {
    public static void main(String[] args) {
        try {
            Class<?> sinif = Class.forName("com.ornek.HicOlmayanSinif");
            System.out.println("Yuklendi: " + sinif.getName());
        } catch (ClassNotFoundException e) {
            System.out.println("Sinif bulunamadi: " + e.getMessage());
        }
    }
}

Burada com.ornek.HicOlmayanSinif ne derleme çıktısında ne de çalışma zamanı classpath'te bulunmaktadır; bu yüzden JVM aramayı sonlandırır ve ClassNotFoundException fırlatır. Dikkat edilmesi gereken nokta, bu istisnanın kontrol edilen türden olması nedeniyle mutlaka try-catch ile ele alınması ya da metodun imzasında fırlatılması gerektiğidir; derleyici bunu zorunlu kılar. Bu da geliştiriciye, dinamik sınıf yüklemesinin her zaman başarısız olabileceğini baştan hatırlatan bir tasarım tercihidir.

Pratikte bu hatayla en sık üç durumda karşılaşılır: bağımlılık yönetim aracına (Maven veya Gradle) eklenen bir kütüphanenin sınıf adı yanlış yazılmıştır, ilgili JAR dosyası projeye hiç dahil edilmemiştir ya da paket adı yeniden düzenleme (refactoring) sırasında değiştirilmiş ama string olarak yazılan sınıf adı güncellenmemiştir. Bu son senaryo özellikle yapılandırma dosyalarında (properties, XML) sınıf adı sabit metin olarak tutulduğunda sinsi bir kaynak hâline gelir, çünkü derleyici bu tür string referansları kontrol edemez.

NoClassDefFoundError Ne Zaman Oluşur

NoClassDefFoundError, ClassNotFoundException'dan farklı olarak, ilgili sınıf derleme sırasında tamamen mevcuttu ve kodunuz ona doğrudan referans veriyordu; sorun, çalışma zamanında bu sınıfın artık erişilebilir olmamasıdır. Bunun iki yaygın kök nedeni vardır: birincisi, sınıfı içeren JAR dosyasının çalışma zamanı classpath'ine dahil edilmemiş olması (örneğin uygulama paketlenirken bir bağımlılığın gözden kaçırılması); ikincisi ise sınıf ilk kez yüklenmeye çalışılırken statik başlatıcı bloğu (static initializer) içinde bir istisna fırlatılmış olması. İkinci durumda JVM, sınıfı "başlatılamaz" olarak işaretler ve sonraki tüm kullanım denemelerinde NoClassDefFoundError fırlatır.

Statik başlatıcı kaynaklı bir örnek şu şekildedir:

public class Yapilandirma {
    static int deger = 10 / 0; // statik blokta hata

    public static void kullan() {
        System.out.println(deger);
    }
}

public class Ana {
    public static void main(String[] args) {
        Yapilandirma.kullan();
    }
}

Bu kodun ilk çalıştırılmasında ArithmeticException statik başlatıcı sırasında fırlar ve JVM sınıfı kullanılamaz durumda işaretler; aynı sınıfa ikinci bir erişim denemesi ise doğrudan NoClassDefFoundError ile sonuçlanır. İkinci yaygın senaryo, eksik JAR durumudur:

public class Rapor {
    public static void main(String[] args) {
        ExternalKutuphane.calistir(); // JAR runtime'da yok
    }
}

Bu durumda tipik bir log çıktısı şöyle görünür:

Exception in thread "main" java.lang.NoClassDefFoundError: com/ornek/ExternalKutuphane
	at Rapor.main(Rapor.java:3)
Caused by: java.lang.ClassNotFoundException: com.ornek.ExternalKutuphane
	at java.net.URLClassLoader.findClass(URLClassLoader.java:387)
	... 1 more

Bu çıktı, iki hatanın nasıl iç içe geçebildiğini de gösterir: kod derlenirken sınıf mevcuttu, ama çalışma zamanında JAR eksik olduğu için ClassLoader sınıfı bulamamış ve bu, üst seviyede NoClassDefFoundError olarak yansımıştır. Böyle durumlarda çözüm genellikle ilgili bağımlılığın paketleme aşamasında (fat JAR, uber JAR veya dağıtım betiği) atlanıp atlanmadığını kontrol etmekten geçer.

Throwable Hiyerarşisi: Exception mı Error mı

Java'da fırlatılabilen her şey java.lang.Throwable sınıfından türer ve bu ağaç iki ana dala ayrılır: Exception ve Error. Bu ayrım kozmetik değildir; JVM'in ve dil tasarımcılarının "bu hatayı uygulama kodu yönetebilir mi, yoksa ortam düzeyinde bir sorun mu" sorusuna verdiği cevaptır. ClassNotFoundException, ReflectiveOperationException üzerinden Exception dalına bağlanır ve derleyici tarafından denetlenen (checked) bir sınıftır; yani onu fırlatabilecek bir metodu çağırıyorsanız ya try-catch ile yakalamak ya da throws ile yukarı bildirmek zorundasınız.

NoClassDefFoundError ise LinkageError üzerinden Error dalına bağlanır ve denetlenmeyen (unchecked) bir yapıdır. Bu ayrım pratikte şu anlama gelir: Exception dalı, geliştiricinin öngörebileceği ve programın akışı içinde tolere edebileceği durumlar için tasarlanmıştır; Error dalı ise JVM'in kendi çalışma bütünlüğüyle ilgili, uygulama mantığıyla düzeltilemeyecek durumları temsil eder. Bir sınıfın adını yanlış yazdığınızda veya reflection ile var olmayan bir sınıfı çağırdığınızda derleyici sizi ClassNotFoundException ile uyarır çünkü bu, kodun akışıyla ilgili bir durumdur. Ama derleme sırasında sorunsuz görünen bir sınıf çalışma zamanında classpath'ten kaybolduysa, bu JVM'in sınıf yükleme sözleşmesinin bozulduğu anlamına gelir ve dil bunu bilinçli olarak bir Error ile işaretler.

Bu noktada sık yapılan bir hata, catch (Exception e) bloklarının NoClassDefFoundError'ı da yakalayacağını sanmaktır — yakalamaz, çünkü Error, Exception'ın üst sınıfı değil kardeşidir. Genel kural olarak Error alt sınıflarını yakalayıp "yutmak" tavsiye edilmez; bu hatalar genellikle ortamın (classpath, bağımlılık sürümü, sınıf yükleyici) düzeltilmesini gerektirir, kod içinde bastırılması gereken bir durum değildir. Bu tür hiyerarşi ve checked/unchecked ayrımlarına ne kadar hakim olduğunuzu görmek isterseniz Java bilgi seviyesi ölçme testi ile kendinizi hızlıca sınayabilirsiniz.

Karşılaştırma Tablosu ve Maven/Gradle Kapsamları

Karşılaştırma Tablosu ve Maven/Gradle Kapsamları

İki hatanın davranışını yan yana görmek, ikisini birbirine karıştırmayı büyük ölçüde engeller. Aşağıdaki tablo, en çok karışan noktaları özetler:

Özellik ClassNotFoundException NoClassDefFoundError
Hiyerarşideki yeri Exception (checked) Error (unchecked)
Tipik tetikleyici Class.forName, reflection, JDBC sürücü yükleme Derleme zamanında bilinen ama çalışma zamanında classpath'te olmayan sınıf
Derleme zamanı görünürlüğü Genellikle derleme anında da sınıf bulunamaz Derleme anında sınıf mevcuttur, sorun sonradan ortaya çıkar
Yakalama zorunluluğu try-catch veya throws zorunlu Zorunlu değil, yakalanması önerilmez
Kök neden odağı Yanlış sınıf adı, eksik dinamik yükleme Bağımlılık sürüm çakışması, eksik runtime paketleme

Maven ve Gradle'daki bağımlılık kapsamları bu tabloyu doğrudan etkiler. Maven'de compile (varsayılan) kapsamındaki bir bağımlılık hem derleme hem çalışma zamanında classpath'e dahil edilir; provided kapsamı ise sınıfı derleme ve test aşamasında görünür kılar ama üretilen paketin içine koymaz, çünkü çalışma ortamının (örneğin bir uygulama sunucusunun) o sınıfı zaten sağlayacağı varsayılır. Eğer bu varsayım yanlışsa ve hedef ortamda o sınıf gerçekten yoksa, sonuç neredeyse her zaman NoClassDefFoundError olur. Gradle'da da compileOnly benzer bir rol oynar: sınıf derleme sırasında görünür fakat çalışma zamanı classpath'ine eklenmez. runtimeOnly ise tam tersi bir senaryo yaratabilir; derleme sırasında görünmeyen ama paketlemede yer alan bağımlılıklar genelde derleme hatası verir, NoClassDefFoundError değil. test kapsamındaki bağımlılıklar ise yalnızca test kaynak kümesinde geçerlidir; bir sınıfı yanlışlıkla test kapsamına koyup üretim kodunda kullanmak, üretim ortamında klasik bir "derlemede vardı, çalışırken yok" senaryosuna yol açar.

Stack Trace Okuma: Caused by Zinciri

Gerçek hata ayıklama, exception adını okumakla değil, stack trace'in tamamını doğru sırayla izlemekle başlar. Aşağıdaki örnek, tipik bir NoClassDefFoundError zincirini gösterir:

Exception in thread "main" java.lang.NoClassDefFoundError: com/example/util/JsonParser
    at com.example.App.main(App.java:12)
Caused by: java.lang.ClassNotFoundException: com.example.util.JsonParser
    at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:445)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:588)
    ... 1 more

Buradaki okuma sırası önemlidir: en üstteki satır, hatanın sizin kodunuzda nerede fark edildiğini gösterir (App.java:12), ama gerçek kök neden genellikle Caused by: ile başlayan alt zincirdedir. Bu örnekte JVM önce JsonParser sınıfını bulmaya çalışmış, sınıf yükleyici bunu bulamayınca içeride bir ClassNotFoundException oluşmuş, bu da dışarıya NoClassDefFoundError olarak yansımıştır. Birden fazla Caused by bloğu olan uzun zincirlerde en altta yer alan blok, hemen hemen her zaman asıl kaynaktır; üstteki katmanlar sadece o hatanın hangi çağrı zinciri üzerinden yukarı taşındığını gösterir.

Pratikte iz sürerken dikkat edilmesi gereken üç şey vardır: sınıfın tam paket yolu (küçük bir yazım farkı bile sınıfı "bulunamaz" yapar), hatanın oluştuğu satır numarası ve zincirdeki sınıf yükleyicinin adı (uygulama sınıf yükleyicisi mi, özel bir modül sınıf yükleyicisi mi). Özellikle çok modüllü projelerde farklı sınıf yükleyicilerin aynı sınıfı farklı zamanlarda görmesi, deneyimli geliştiricilerin bile zaman zaman şaşırdığı bir durumdur. Bu tür stack trace analizi ve JVM iç mekanizmaları üzerine daha fazla pratik örnek ve yazı için Berk Akademi blog arşivi düzenli olarak güncellenen kaynaklar sunar.

Hata Ayıklama Kontrol Listesi

ClassNotFoundException ve NoClassDefFoundError ile karşılaşıldığında rastgele deneme yanılma yerine sistemli bir sıra izlemek, çözüm süresini ciddi biçimde kısaltır. Aşağıdaki adımlar, hem Maven hem Gradle projelerinde uygulanabilecek, sınıf yükleme sorunlarının kök nedenine inen bir kontrol akışı sunar.

  1. Bağımlılık ağacını çıkarın: Maven projelerinde mvn dependency:tree, Gradle projelerinde gradle dependencies komutu çalıştırılarak eksik veya çakışan kütüphane sürümleri görsel hale getirilir. Bu çıktıda aynı kütüphanenin birden fazla sürümünün transitif olarak geldiği durumlar, çalışma zamanında yanlış sürümün classpath'e girmesine yol açabilir.
  2. Fat-jar / shaded jar içeriğini kontrol edin: Uygulama tek bir çalıştırılabilir jar olarak paketleniyorsa, jar'ın içindeki META-INF ve sınıf dizinleri incelenerek beklenen bağımlılığın gerçekten paket içine dahil edilip edilmediği doğrulanmalıdır. Derleme sırasında provided veya compileOnly gibi kapsamlarla işaretlenmiş bir kütüphane, paketleme aşamasında sessizce dışarıda kalabilir.
  3. Classpath çakışmasını tespit edin: Aynı sınıfın farklı jar dosyalarında birden fazla kez bulunması, sınıf yükleyicinin beklenmedik bir sürümü yüklemesine ve ardından uyumsuz metot imzaları nedeniyle hata fırlatılmasına neden olabilir. Uygulamanın çalıştığı ortamdaki tüm jar dosyalarını listeleyip aynı isimli sınıfları aramak bu tür çakışmaları ortaya çıkarır.
  4. Static blok ile normal kod akışını ayırın: Hata bir sınıfın static initializer bloğunda mı, yoksa normal bir metot çağrısında mı oluşuyor, bu ayrımı net biçimde yapın. Static blokta fırlatılan bir istisna, ilk çağrıda ExceptionInInitializerError'a, sonraki çağrılarda ise NoClassDefFoundError'a dönüşür; bu yüzden hatanın ilk mi yoksa tekrar eden bir çağrıda mı ortaya çıktığı önemli bir ipucudur.
  5. Sınıf yükleyici kaynağını doğrulayın: Hangi sınıf yükleyicinin (bootstrap, application, ya da özel bir yükleyici) sorunlu sınıfı yüklemeye çalıştığını belirlemek, özellikle çoklu modül veya eklenti tabanlı mimarilerde sorunun kaynağını daraltır.

Bu adımların her biri tek başına basit görünse de, gerçek projelerde birden fazla modülün iç içe geçtiği durumlarda kök nedeni bulmak zaman alabilir. Böyle durumlarda bir projeyi satır satır birlikte incelemek öğrenmeyi hızlandırır; birebir Java hata ayıklama seansları bu tür classpath ve sınıf yükleme sorunlarını canlı bir örnek üzerinden çözme fırsatı sunar.

Sık Sorulan Sorular

ClassNotFoundException hangi durumlarda checked exception olarak ele alınmalıdır?

ClassNotFoundException, Class.forName() gibi metotlarla açıkça ve dinamik biçimde bir sınıf yüklemeye çalıştığınız her yerde checked exception olarak ele alınmalıdır. Derleyici bu istisnayı ya try-catch bloğu ile yakalamanızı ya da metot imzasında throws ile bildirmenizi zorunlu kılar, çünkü sınıfın çalışma zamanında bulunamama ihtimali derleme anında öngörülebilir bir durumdur.

NoClassDefFoundError'ı try-catch ile yakalamak doğru bir çözüm müdür?

Hayır, çünkü NoClassDefFoundError bir Error alt sınıfıdır ve genellikle JVM'in veya çalışma ortamının kendisiyle ilgili ciddi bir tutarsızlığa işaret eder. Bu hatayı yakalayıp yutmak, sorunun görünürlüğünü ortadan kaldırır ama kök nedeni çözmez; doğru yaklaşım, hatayı yakalamak yerine classpath ve bağımlılık yapılandırmasını düzeltmektir.

Maven'da provided scope kullanmak neden runtime hatasına yol açabilir?

Provided scope ile işaretlenen bir bağımlılık, derleme sırasında classpath'te bulunur ama paketleme aşamasında nihai artefakta dahil edilmez; çünkü bu kapsam, ilgili kütüphanenin çalışma ortamı tarafından zaten sağlanacağı varsayımıyla kullanılır. Bu varsayım gerçekleşmezse, uygulama çalışma zamanında o sınıfı bulamaz ve NoClassDefFoundError ile karşılaşılır.

Fat-jar (shaded jar) oluşturmak bu hataları nasıl önler?

Fat-jar yaklaşımı, uygulamanın tüm bağımlılıklarını tek bir dağıtılabilir jar dosyası içine paketleyerek, çalışma ortamının ayrıca herhangi bir kütüphane sağlamasına duyulan ihtiyacı ortadan kaldırır. Bu sayede derleme zamanında var olan sınıfların çalışma zamanında da aynı şekilde erişilebilir olması güvence altına alınır ve eksik bağımlılıktan kaynaklanan hatalar büyük ölçüde azalır.

Static initializer'da fırlatılan hata neden NoClassDefFoundError olarak görünür?

Bir sınıfın static bloğu ilk yüklenme sırasında başarısız olursa, JVM o sınıfı "başlatılamamış" olarak işaretler ve bu sınıfa yönelik sonraki her erişim girişiminde, kök nedeni tekrar göstermek yerine NoClassDefFoundError fırlatır. Bu davranış, JVM'in aynı başarısız başlatmayı tekrar tekrar denemesini engellemek için tasarlanmıştır ve gerçek hatayı görmek için genellikle stack trace'teki ilk oluşum anına bakmak gerekir.

ClassNotFoundException ve NoClassDefFoundError arasındaki farkı kavramak, Java'da sınıf yükleme mekanizmasını ve derleme zamanı ile çalışma zamanı ayrımını daha derinden anlamaktan geçer. Bu tür konuları teoriden çok pratikle pekiştirmek isteyenler için bire bir Java eğitimi içeriği, gerçek proje senaryoları üzerinden ilerleyen bir çalışma alanı sunar.

Bu içeriğin üretilmesinde yapay zeka araçlarından destek alınmıştır.

İlgili Eğitimler

Berk Keskin — Yazılım Geliştirici ve Eğitmen
Yazar

Berk Keskin Kimdir?

Yazılıma 12 yaşında başladı; bugün öğrencinin seviyesine ve hedefine göre şekillenen sürdürülebilir öğrenme sistemleri tasarlıyor. 300'den fazla kişiye ezber değil, düşünerek kod yazmayı öğretti — Berk Akademi'de izlemeye değil üretmeye dayalı öğrenme kültürünü o kuruyor.

WhatsApp Hemen Ara