آشنایی با تفاوت میان ClassNotFoundException و NoClassDefFoundError در جاوا

آشنایی با تفاوت میان ClassNotFoundException و NoClassDefFoundError در جاوا

همان‌طور که ممکن است بدانید، Java یک زبان به اصطلاح Object Oriented (شییٔ‌گرا) است و در این زبان تقریباً هر چیزی یک شیئ محسوب می‌شود و از سوی دیگر برای ایجاد یک آبجکت نیاز به یک کلاس داریم. به طور کلی، در حین ساخت کلاس‌ها در جاوا ممکن است با ارورها و اِکسپشن‌های مختلفی روبه‌رو شویم که دو مورد از رایج‌ترین آن‌ها ClassNotFoundException و NoClassDefFoundError است که در این مقاله قصد داریم تفاوت مابین این دو را بررسی نماییم.

اولین کسی باشید که به این سؤال پاسخ می‌دهید

وقتی برنامهٔ نوشته شده را اجرا می‌کنیم، اگر کلاسی از قبل در حافظه بارگذاری نشده باشد، JVM (ماشین مجازی جاوا) آن‌ را در حافظه بارگذاری می‌کند. به طور مثال، هنگامی که کد زیر اجرا می‌شود،‌ JVM قبل از اینکه آبجکت را از روی کلاس Employee ایجاد کند، باید با استفاده از یک به اصطلاح ClassLoader، این کلاس را بر روی حافظه بارگذاری نماید:

Employee emp = new Employee();

در این مثال، JVM این کلاس را بر روی حافظه بارگذاری خواهد نمود زیرا این کلاس در مسیر اجرای کد قرار دارد و قرار است که ماشین مجازی جاوا از روی این کلاس یک آبجکت بسازد. همچنین می‌توانیم با استفاده از نام کلاس در یکی از متدهای ()Class.forName() ،‌ClassLoader.findSystemClass و یا ()ClassLoader.loadClass از ماشین مجازی جاوا بخواهیم که یک کلاس را فقط بارگذاری کند. به‌ عنوان مثال، در کد زیر بدون اینکه تَسک دیگری صورت بگیرد، کلاس Employee فقط بارگذاری خواهد شد:

Class.forName("Employee");

هم ClassNotFoundException و هم NoClassDefFoundError هنگامی رخ می‌دهند که در حین اجرای سورس‌کد برنامه‌ای، یک کلاس خاص پیدا نمی‌شود؛ اما ماجرای رخ دادن این دو با هم متفاوت است که در ادامه این موضوع را مورد بررسی قرار خواهیم داد.

درآمدی بر ClassNotFoundException در زبان جاوا
به طور کلی اجرای برنامه بدون به‌روزرسانی Class Path در فایل JAR یکی از رایج‌ترین دلایل ایجاد این اِکسپشن است. این اِکسپشن زمانی رخ می‌دهد که با وارد کردن نام کلاس در یکی از متدهای زیر از ماشین مجازی جاوا می‌خواهیم تا کلاسی را بارگذاری نماید؛ اما کلاس مورد نظر در مسیری که انتظار می‌رود باشد، یافت نمی‌شود:

- Class.forName()
- ClassLoader.findSystemClass() 
- ClassLoader.loadClass()

به‌ عنوان مثال، هنگامی که کد JDBC را برای اتصال به دیتابیس خود (مثلاً MySQL) اجرا می‌کنید، در‌ حالی‌ که Class Path شما فایل JAR آ‌ن‌ را ندارد،‌ ClassNotFoundException رخ خواهد داد (کد JDBC یا Java DataBase Connectivity یک API زبان برنامه‌نویسی جاوا است که چگونگی دسترسی به دیتابیس را تعریف می‌کند.) برای روشن‌تر شدن این مسئله، به مثال زیر دقت کنید:

public class Test {
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("Person");
        Person person = (Person) clazz.newInstance();
        person.saySomething();
    }
}
class Person {
    void saySomething() {
        System.out.println("Hello");
    }
}

اگر کد فوق را کامپایل کنیم، کامپایلر دو کلاس‌فایل ایجاد خواهد کرد که عبارتند از Test.class و Person.class و پس از اجرای این کد کامپایل شده، همان‌طور که انتظار می‌رود کلمهٔ Hello چاپ خواهد شد اما اگر فایل Person.class را حذف نموده و مجدداً کد را اجرا کنیم،‌ این بار با ClassNotFoundException مواجه خواهیم شد.

درآمدی بر NoClassDefFoundError در زبان جاوا
این ارور یکی از زیرشاخه‌های java.lang.Error است که این گروه از خطاها تنها در حین استفاده از JVM ممکن است رخ بدهند. به عبارت دیگر، خطای NoClassDefFoundError هنگامی رخ می‌دهد که ماشین مجازی جاوا در تلاش است تا یک کلاس خاص را به‌ عنوان بخشی از فراخوانی متدهای معمول و یا بخشی از فرآیند ایجاد یک آبجکت با استفاده از کلمهٔ‌ کلیدی new در حافظه بارگذاری کند اما کلاس مورد نظر در Class Path وجود ندارد در‌ حالی‌ که در زمان کامپایل نمودن کد،‌ این کلاس وجود داشته است.

به طور کلی، اگر بخواهید کد خود را اجرا کنید، باید آن را ابتدا کامپایل کنید و اگر در این میان از کلاسی استفاده کرده باشید که دیگر وجود ندارد، با خطای کامپایل مواجه خواهید شد. مشابه آنچه در مورد مثال قبل گفته شد،‌ با اجرای کد زیر نیز دو کلاس‌فایل برای ما ایجاد خواهد شد (Test.class و Employee.class) و با اجرای این کد کلمهٔ‌ Hello چاپ خواهد شد:

public class Test {
    public static void main(String[] args) throws Exception {
        Employee emp = new Employee();
        emp.saySomething();
    }
}
class Employee {
    void saySomething() {
        System.out.println("Hello");
    }
}

اما اگر فایل Employee.class را حذف نموده و برنامه را دوباره اجرا کنیم،‌ با خطای NoClassDefFoundError مواجه خواهیم شد:

Exception in thread "main" java.lang.NoClassDefFoundError: Employee
 at Test.main(Test.java:9)
Caused by: java.lang.ClassNotFoundException: Employee
 at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
 at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
 ... 1 more

همان‌طور که در مثال فوق مشاهده کردیم، ClassNotFoundException است که موجب می‌شود NoClassDefFoundError رخ دهد زیرا ماشین مجازی جاوا قادر نیست کلاس را در مسیر مورد نظر پیدا کند.

منبع