オーバーライドするメソッドがオーバーライドされたメソッドよりも幅広い例外をスローできないのはなぜですか?


104

Kathe sierraによるSCJP 6の本を読んでいて、オーバーライドされたメソッドで例外をスローするというこの説明に出くわしました。うまく聞き取れませんでした。誰かが私にそれを説明できますか?

オーバーライドするメソッドは、オーバーライドされるメソッドによって宣言された例外よりも新しい、またはより広いチェック済み例外をスローしてはなりません。たとえば、FileNotFoundExceptionのサブクラスでない限り、FileNotFoundExceptionを宣言するメソッドは、SQLException、Exception、またはその他の非実行時例外を宣言するメソッドによってオーバーライドできません。


1
参考になるサイトを次に示し
Tim Bish

回答:


155

つまり、メソッドが特定の例外のスローを宣言した場合、サブクラスのオーバーライドメソッドは、その例外またはそのサブクラスのスローを宣言することしかできません。例えば:

class A {
   public void foo() throws IOException {..}
}

class B extends A {
   @Override
   public void foo() throws SocketException {..} // allowed

   @Override
   public void foo() throws SQLException {..} // NOT allowed
}

SocketException extends IOException、しかしSQLExceptionしません。

これはポリモーフィズムのためです:

A a = new B();
try {
    a.foo();
} catch (IOException ex) {
    // forced to catch this by the compiler
}

Bスローすることを決定した場合、スーパークラス-によってSQLExceptionのインスタンスを参照しているため、コンパイラは強制的にキャッチすることができませんでした。一方、のサブクラスは、以下を処理する句(キャッチまたはスロー)によって処理されます。BAIOExceptionIOException

スーパークラスでオブジェクトを参照できるようにするために必要なルールは、リスコフ代入原理です。

チェックされていない例外はどこにでもスローされる可能性があるため、このルールは適用されません。必要に応じて、ドキュメントの形式として、throws句に未チェックの例外を追加できますが、コンパイラはそれについて何も強制しません。


これは、インターフェイスの実装中にも適用されますか?インターフェイスの実装が引き続き「オーバーライド」と呼ばれるかどうかはわかりません。
Muhammad Gelbana 2013年

@Override public void foo(){..}についてはどうでしょうか。許可されていることはわかっていますが、この場合の説明は明確ではありません。
ナスカー2014

4
@danipオーバーライドするメソッドは、オーバーライドされるメソッドからスローされる例外のサブセットをスローできます。空のセットもサブセットです。だからこそ@Override public void foo() {...}合法です。
開発者MariusŽilėnas2016年

@Bozhoは、メソッドが特定の例外をスローするように宣言した場合であっ
Raman Sahasi

それでは、現実の世界での克服はどうでしょうか?実装されたインターフェースからメソッドをオーバーライドする必要がありますが、私の実装にはスロー減速が含まれていますが、インターフェースには含まれていません。ここでの標準的な手順は何ですか?
ap

22

オーバーライドされたメソッドが例外を宣言しているかどうかに関係なく、オーバーライドしたメソッドはチェックされていない(ランタイム)例外をスローできます

例:

class Super {
    public void test() {
        System.out.println("Super.test()");
    }
}

class Sub extends Super {
    @Override
    public void test() throws IndexOutOfBoundsException {
        // Method can throw any Unchecked Exception
        System.out.println("Sub.test()");
    }
}

class Sub2 extends Sub {
    @Override
    public void test() throws ArrayIndexOutOfBoundsException {
        // Any Unchecked Exception
        System.out.println("Sub2.test()");
    }
}

class Sub3 extends Sub2 {
    @Override
    public void test() {
        // Any Unchecked Exception or no exception
        System.out.println("Sub3.test()");
    }
}

class Sub4 extends Sub2 {
    @Override
    public void test() throws AssertionError {
        // Unchecked Exception IS-A RuntimeException or IS-A Error
        System.out.println("Sub4.test()");
    }
}

サブクラスが行うランタイム例外をインターフェイスが宣言していない場合、どのようにしてエラーまたは警告を強制しますか?文書化のために一貫性を強制しようとしています。インターフェースタイプを見つけるよりも、インターフェースタイプをチェックしてすべての例外のインターフェースタイプをチェックする方が簡単です。そうすれば、IOExceptionをスローするかIllegalArgumentExceptionをスローするかを確認するだけで実装を詳しく調べることができます。
anon58192932 2017年

14

私の意見では、Java構文設計の失敗です。ポリモーフィズムは、例外処理の使用を制限するべきではありません。実際、他のコンピューター言語はそれを行いません(C#)。

さらに、メソッドはより特殊化されたサブクラスでオーバーライドされるため、より複雑になり、このため、新しい例外をスローする可能性が高くなります。


8

オーバーライドするメソッドが何もスローしないという事実を答える答えがないため、ここで古い質問にこの答えを提供しますここでものは、次のとおりです。

1)同じ例外をスローする

public static class A 
{
    public void m1()
       throws IOException
    {
        System.out.println("A m1");
    }

}

public static class B 
    extends A
{
    @Override
    public void m1()
        throws IOException
    {
        System.out.println("B m1");
    }
}

2)オーバーライドされたメソッドのスローされた例外のサブクラスをスローします

public static class A 
{
    public void m2()
       throws Exception
    {
        System.out.println("A m2");
    }

}

public static class B 
    extends A
{
    @Override
    public void m2()
        throws IOException
    {
        System.out.println("B m2");
    }
}

3)何も投げない。

public static class A 
{   
    public void m3()
       throws IOException
    {
        System.out.println("A m3");
    }
}

public static class B 
    extends A
{   
    @Override
    public void m3()
        //throws NOTHING
    {
        System.out.println("B m3");
    }
}

4)スローにRuntimeExceptionを含める必要はありません。

スローにRuntimeExceptionsがある場合とない場合がありますが、コンパイラはそれについて文句を言いません。RuntimeExceptionsはチェックされた例外ではありません。キャッチされない場合、チェックされた例外のみがスローに表示される必要があります。


6

これを説明するために、以下を検討してください。

public interface FileOperation {
  void perform(File file) throws FileNotFoundException;
}

public class OpenOnly implements FileOperation {
  void perform(File file) throws FileNotFoundException {
    FileReader r = new FileReader(file);
  }
}

次のように書いたとします:

public class OpenClose implements FileOperation {
  void perform(File file) throws FileNotFoundException {
    FileReader r = new FileReader(file);
    r.close();
  }
}

r.close()がFileNotFoundExceptionよりも広いIOExceptionをスローするため、これによりコンパイルエラーが発生します。

これを修正するには、次のように記述します。

public class OpenClose implements FileOperation {
  void perform(File file) throws IOException {
    FileReader r = new FileReader(file);
    r.close();
  }
}

perform(...)操作を実装しているが、メソッドのインターフェースの定義に含まれていない例外をスローしているため、別のコンパイルエラーが発生します。

何でこれが大切ですか?インターフェイスのコンシューマーには次のようなものがあります。

FileOperation op = ...;
try {
  op.perform(file);
}
catch (FileNotFoundException x) {
  log(...);
}

IOExceptionのスローが許可された場合、クライアントのコードは正しくなくなります。

未チェックの例外を使用すると、この種の問題を回避できることに注意してください。(私はあなたがするかしないかを示唆していません、それは哲学的問題です)


3

インタビューの質問を受けましょう。スーパークラスにNullPointerExceptionをスローするメソッドがあります。RuntimeExceptionをスローするメソッドでオーバーライドできますか?

この質問に答えるために、未チェックおよびチェック済みの例外とは何かをお知らせください。

  1. チェックされた例外は、基本的なtry-catch-finally例外処理で説明されているように、明示的にキャッチまたは伝播する必要があります。未チェックの例外にはこの要件はありません。捕まったり、投げられたと宣言する必要はありません。

  2. Javaのチェック済み例外は、java.lang.Exceptionクラスを拡張します。未チェックの例外は、java.lang.RuntimeExceptionを拡張します。

パブリッククラスNullPointerExceptionはRuntimeExceptionを拡張します

未チェックの例外は、java.lang.RuntimeExceptionを拡張します。これが、NullPointerExceptionがUncheked例外である理由です。

例を見てみましょう:例1:

    public class Parent {
       public void name()  throws NullPointerException {
           System.out.println(" this is parent");
       }
}

public class Child  extends Parent{
     public  void name() throws RuntimeException{
             System.out.println(" child ");
     }

     public static void main(String[] args) {
        Parent parent  = new Child();
        parent.name();// output => child
    }
}

プログラムは正常にコンパイルされます。例2:

    public class Parent {
       public void name()  throws RuntimeException {
           System.out.println(" this is parent");
       }
}

public class Child  extends Parent{
     public  void name() throws  NullPointerException {
             System.out.println(" child ");
     }

     public static void main(String[] args) {
        Parent parent  = new Child();
        parent.name();// output => child
    }
}

プログラムも正常にコンパイルされます。したがって、Unchecked例外の場合は何も起こらないことは明らかです。それでは、チェック例外の場合にどうなるか見てみましょう。例3:基本クラスと子クラスの両方がチェック例外をスローする場合

    public class Parent {
       public void name()  throws IOException {
           System.out.println(" this is parent");
       }
}
public class Child  extends Parent{
     public  void name() throws IOException{
             System.out.println(" child ");
     }

     public static void main(String[] args) {
        Parent parent  = new Child();

        try {
            parent.name();// output=> child
        }catch( Exception e) {
            System.out.println(e);
        }

    }
}

プログラムは正常にコンパイルされます。例4:子クラスのメソッドが、基本クラスの同じメソッドと比較して境界チェック例外をスローしている場合。

import java.io.IOException;

public class Parent {
       public void name()  throws IOException {
           System.out.println(" this is parent");
       }
}
public class Child  extends Parent{
     public  void name() throws Exception{ // broader exception
             System.out.println(" child ");
     }

     public static void main(String[] args) {
        Parent parent  = new Child();

        try {
            parent.name();//output=> Compilation failure
        }catch( Exception e) {
            System.out.println(e);
        }

    }
}

プログラムはコンパイルに失敗します。したがって、チェック例外を使用する場合は注意が必要です。


2

E1をスローするメソッドM1を持つスーパークラスAと、M1をオーバーライドするメソッドM2を持つAから派生するクラスBがあるとします。M2は、E1とは異なり、SPECIALIZEDが少ないものはスローできません。

ポリモーフィズムがあるため、クラスAを使用するクライアントは、BをAであるかのように扱うことができるはずです。Inharitance ===> Is-a(B is-a A)。クラスAを処理するこのコードが例外E​​1を処理していて、M1がこのチェック済み例外をスローすると宣言しているのに、別のタイプの例外がスローされた場合はどうなりますか?M1がIOExceptionをスローしていた場合、M2はIOExceptionであるため、FileNotFoundExceptionをスローする可能性があります。Aのクライアントは問題なくこれを処理できます。スローされた例外の幅が広い場合、Aのクライアントはこれについて知る機会がなく、したがって、それをキャッチする機会がありません。


Perhac ::これは、チェックされた例外とチェックされていない例外の両方に当てはまりますか?それとも異なりますか?
ylnsagar

@ylnsagarこれは、チェックされた例外のみです。チェックされていない例外(RuntimeExceptionのサブタイプ)も「プログラマーエラー」と呼ばれる場合があり、一般的には試行錯誤すべきではないため、throws節で宣言する必要はありません。チェックされていない例外は、いつでも、どのコードからでも発生する可能性があります。上記の説明は、チェックされた例外のみに関するものです
PeterPerháč2016年

@Perhac ::はい、そうですが、私の理解から記事を読んでください。未チェックの例外にも当てはまります。たとえば、スーパークラスのメソッドがNull Pointer Exceptionをスローしている場合や、メソッドをオーバーライドしているサブクラスがExceptionをスローしている場合などです。ここで、ExceptionはNull Pointer Exceptionのスーパークラスです。その場合、コンパイラはこれを許可しません。
ylnsagar

1

よくjava.lang.Exceptionはjava.lang.Throwableを拡張します。java.io.FileNotFoundExceptionはjava.lang.Exceptionを拡張します。したがって、メソッドがjava.io.FileNotFoundExceptionをスローした場合、オーバーライドメソッドでは、FileNotFoundExceptionより上位の階層をスローすることはできません。たとえば、java.lang.Exceptionをスローすることはできません。ただし、FileNotFoundExceptionのサブクラスをスローすることもできます。ただし、オーバーライドされたメソッドでFileNotFoundExceptionを処理する必要があります。いくつかのコードをノックして試してみてください!

ルールがあるので、ポリモーフィズムによってスーパークラスでオーバーライドされたメソッドを呼び出すことができるので、特定性を広げて元のスロー宣言を失うことはありません。


1

オーバーライドするメソッドは、オーバーライドされるメソッドによって宣言された例外よりも新しい、またはより広いチェック済み例外をスローしてはなりません。

例:

class Super {
    public void throwCheckedExceptionMethod() throws IOException {
        FileReader r = new FileReader(new File("aFile.txt"));
        r.close();
    }
}

class Sub extends Super {    
    @Override
    public void throwCheckedExceptionMethod() throws FileNotFoundException {
        // FileNotFoundException extends IOException
        FileReader r = new FileReader(new File("afile.txt"));
        try {
            // close() method throws IOException (that is unhandled)
            r.close();
        } catch (IOException e) {
        }
    }
}

class Sub2 extends Sub {
    @Override
    public void throwCheckedExceptionMethod() {
        // Overriding method can throw no exception
    }
}

1

オーバーライドするメソッドは、オーバーライドされるメソッドによって宣言された例外よりも新しい、またはより広いチェック済み例外をスローしてはなりません。

これは単に、既存のメソッドをオーバーライドする場合、このオーバーロードされたメソッドがスローする例外は、元のメソッドがスローするのと同じ例外か、そのサブクラスのいずれかであることを意味します

チェックされたすべての例外が処理されるかどうかのチェックは、実行時ではなくコンパイル時に行われることに注意してください。したがって、コンパイル時に、Javaコンパイラはオーバーライドされたメソッドがスローしている例外のタイプをチェックします。どのオーバーライドされたメソッドが実行されるかは実行時にしか決定できないため、どのような例外をキャッチする必要があるかわかりません。


クラスAとそのサブクラスがあるとしましょうBAhasメソッドm1とクラスBがこのメソッドをオーバーライドしました(m2混乱を避けるために呼び出します)。ここで、m1throws E1と、m2throws のスーパークラスE2であるとしましょうE1。次に、次のコードを記述します。

A myAObj = new B();
myAObj.m1();

m1これは呼び出しにすぎないことに注意してくださいm2(ここでも、メソッドのシグネチャはオーバーロードされたメソッドで同じなので、m1と混同しないでくださいm2。これらは、この例で区別するためのものです...どちらも同じシグネチャを持っています)。しかし、コンパイル時にすべてのJavaコンパイラーが行うのは、参照型(Aこの場合はクラス)に移動して、メソッドが存在するかどうかをチェックし、プログラマーがそれを処理することを期待することです。だから、明らかに、あなたは投げたり捕まえたりするでしょうE1。実行時に、オーバーロードされたメソッドがのスーパークラスE2であるをスローした場合、それはE1非常に間違っています(同じ理由でとは言えませんB myBObj = new A())。したがって、Javaでは許可されていません。オーバーロードされたメソッドによってスローされるチェックされない例外は、同じ、サブクラス、または存在しないものでなければなりません。


クラスParent {void method()throws IndexOutOfBoundsException {System.out.println( "Parent method"); }}クラスChild extends Parent {void method()throws RuntimeException {System.out.println( "Child method"); 親クラスがランタイム例外の子をスローし、子がランタイム例外自体をスローする場合。有効ですか?
abhiagNitk 2017

1

これを理解するために、あるファイルを読み取り、そのファイルに対して何らかの操作を行い、クラスのインスタンスを返すメソッドをMammal定義するクラスがある例を考えてみましょう。readAndGetMammal

class Mammal {
    public Mammal readAndGet() throws IOException {//read file and return Mammal`s object}
}

クラスHumanはクラスMammalを拡張し、readAndGetメソッドをオーバーライドして、のインスタンスではHumanなくのインスタンスを返しますMammal

class Human extends Mammal {
    @Override
    public Human readAndGet() throws FileNotFoundException {//read file and return Human object}
}

呼び出すreadAndGetにはIOException、チェックされた例外と哺乳類readAndMethodがそれをスローしているため、処理する必要があります。

Mammal mammal = new Human();
try {
    Mammal obj = mammal.readAndGet();
} catch (IOException ex) {..}

そして、コンパイラーmammal.readAndGet()はクラスのオブジェクトから呼び出されていることを知っていますがMammal、実行中のJVM はを保持しているためmammal.readAndGet()、メソッド呼び出しをクラスHumanからの呼び出しに解決します。mammalnew Human()

メソッドreadAndMethodからMammal投げているIOException私たちが呼ぶ時はいつでもそれをキャッチするために私たちを強制し、それがチェック例外コンパイラであるためreadAndGetmammal

今と仮定readAndGetしてHuman、他のチェック例外などの例外を投げていると、私たちは知っているreadAndGetのインスタンスから呼び出されますHumanので、mammal保持していますnew Human()

コンパイラの場合、メソッドはから呼び出されるMammalため、コンパイラは処理のみを強制IOExceptionしますが、実行時にはメソッドがスローされることがわかりますException処理されない例外をスローし、メソッドが例外をスローするとコードが破損ます。

それがコンパイラレベル自体で防止されている理由であり、最後にJVMによって処理されないため、新しいまたはより広いチェック例外をスローすることはできません。

メソッドをオーバーライドする際に従う必要のある他のルールもあります。理由を知るには、メソッドオーバーライドルールに従う必要がある理由を参照してください。


0

以下に起因する説明は何ですか

class BaseClass {

    public  void print() {
        System.out.println("In Parent Class , Print Method");
    }

    public static void display() {
        System.out.println("In Parent Class, Display Method");
    }

}


class DerivedClass extends BaseClass {

    public  void print() throws Exception {
        System.out.println("In Derived Class, Print Method");
    }

    public static void display() {
        System.out.println("In Derived Class, Display Method");
    }
}

PrintメソッドがExceptionをスローすると、クラスDerivedClass.javaがコンパイル時例外をスローし、baseclassのprint()メソッドが例外をスローしません

これは、ExceptionがRuntimeExceptionよりも狭いという事実に起因している可能性があります。これは、No Exception(Runtime error)、RuntimeExceptionおよびそれらの子例外のいずれかです。


0

サブクラスのオーバーライドメソッドは、スーパークラスのメソッドのチェック例外のサブクラスである複数のチェック例外のみをスローできますが、スーパークラスのメソッドのチェック例外に関連しない複数のチェック例外をスローできません


0

Javaは、クライアントがキャッチする対象を制限すると想定しているため、親クラスの例外を制限する選択肢を提供しています。あなたが本質的に決してすべきではない私見、クライアントは柔軟性を必要とする可能性があるため、この「機能」を使用しください。

Javaは設計が不十分な古い言語です。現代の言語にはそのような制限はありません。この欠陥を回避する最も簡単な方法は、throw Exception常に基本クラスを作成することです。クライアントはより具体的な例外をスローできますが、基本クラスを非常に広くすることができます。


0

オーバーライドされたメソッドでのチェックおよびチェックされていない例外の処理のルール

- 親クラスのメソッドが例外を宣言しない場合、子クラスのオーバーライド-メソッドが宣言でき

 1. No exception or
 2. Any number of unchecked exception
 3. but strictly no checked exception

-親クラスのメソッドがチェックされていない例外を宣言すると、子クラスのオーバーライドメソッドはを宣言できます

 1. No exception or
 2. Any number of unchecked exception 
 3. but strictly no checked exception

- 親クラスのメソッドがチェック済み例外を宣言すると子クラスのオーバーライドメソッドが宣言できます

 1. No exception or
 2. Same checked exception or
 3. Sub-type of checked exception or
 4. any number of unchecked exception

チェックされた例外とチェックされていない例外の両方の組み合わせが親クラスのメソッドで宣言されている場合でも、上記の結論はすべて当てはまります。

参照

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.