เมื่อ override method ที่โยน checked exception ต้องปฏิบัติตามกฎของ Java compiler
กฎที่ 1: ต้องโยน Exception เดียวกัน หรือ Subclass (Covariant)
Subclass method สามารถโยน exception เดียวกับ superclass หรือ subclass ของ exception นั้น (specific มากกว่า)
ตัวอย่าง: โยน Subclass Exception (ถูกต้อง)
import java.io.*;
abstract class Super {
public void readFile(String path) throws IOException { ... }
}
public class Sub extends Super {
@Override
public void readFile(String path) throws FileNotFoundException { // IOException subclass
// FileNotFoundException extends IOException
}
}
ตัวอย่าง: โยน Exception เดียวกัน (ถูกต้อง)
abstract class Super {
public void method() throws FileNotFoundException { ... }
}
public class Sub extends Super {
@Override
public void method() throws FileNotFoundException { ... } // same exception
}
กฎที่ 2: ห้ามโยน Superclass Exception (Contravariant - ไม่ได้)
Subclass ไม่สามารถ โยน exception ที่เป็น superclass ของ exception ใน superclass method
ตัวอย่าง: ผิด (Compile Error)
abstract class Super {
public void method() throws FileNotFoundException { ... }
}
public class Sub extends Super {
@Override
public void method() throws IOException { } // Compile Error!
// IOException เป็น superclass ของ FileNotFoundException
}
Compile Error
error: method() in Sub cannot override method() in Super
overridden method does not throw IOException
กฎที่ 3: สามารถไม่โยน Exception เลยได้
Subclass method สามารถ ไม่โยน exception ใดๆ ได้ (แม้ superclass จะโยน)
ตัวอย่าง: ไม่โยน Exception (ถูกต้อง)
abstract class Super {
public void method() throws FileNotFoundException { ... }
}
public class Sub extends Super {
@Override
public void method() { // ไม่ throws อะไรเลย
System.out.println("Handled internally");
}
}
กฎที่ 4: Unchecked Exception (RuntimeException) - ไม่มีข้อจำกัด
RuntimeException และ subclass ไม่ถูกบังคับโดย compiler สามารถ override และโยนได้อิสระ
ตัวอย่าง
class Super {
public void method() { throw new RuntimeException(); }
}
class Sub extends Super {
@Override
public void method() { throw new NullPointerException(); } // OK
// หรือไม่โยนเลยก็ได้
}
สรุปตาราง
| Superclass throws | Subclass throws | Valid? |
|---|---|---|
| IOException | IOException | ✓ |
| IOException | FileNotFoundException | ✓ (subclass) |
| IOException | Exception | ✗ (superclass) |
| IOException | (none) | ✓ |
| FileNotFoundException | IOException | ✗ (superclass) |
| RuntimeException | Any RuntimeException | ✓ (unchecked) |
เหตุผลทาง Design (Liskov Substitution Principle)
Client code ที่เรียก superclass method คาดหวังว่าจะจัดการ exception ที่ระบุไว้ หาก subclass โยน exception กว้างกว่า (superclass) client อาจไม่ catch ได้ → แตก LSP
Best Practice
- Override method ควรโยน exception specific มากที่สุดที่เป็นไปได้
- หาจับ exception ไว้ใน subclass ให้ wrap เป็น custom exception ที่ specific
- หลีกเลี่ยง throws Exception / throws Throwable ใน API public