114 votes

Méthode en dérogation et exceptions

J'ai été en passant par SCJP 6 livre par Kathe sierra et suis tombé sur ce explications de lancer des exceptions dans la méthode redéfinie. Je n'ai pas l'obtenir. Quelqu'un peut-il me l'expliquer ?

La méthode de remplacement ne doit PAS jeter vérifié les exceptions qui sont nouveaux ou plus large que ceux déclarés par la méthode de remplacement. Par exemple, un méthode qui déclare une FileNotFoundException ne peut pas être remplacée par une méthode qui déclare une SQLException, d'Exception ou de tout autre non-exécution exception sauf si c'est une sous-classe de FileNotFoundException.

172voto

Bozho Points 273663

Cela signifie que si une méthode déclare à jeter une exception donnée, la méthode de remplacement dans une sous-classe peut seulement déclarer à jet d'exception ou de sa sous-classe. Par exemple:

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, mais SQLException ne le sont pas.

C'est à cause de polymorphisme:

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

Si B avaient décidé de jeter l' SQLException, alors le compilateur n'a pas pu vous forcer à attraper, parce que vous faites référence à l'instance d' B par sa super-classe - A. D'autre part, une sous-classe de IOException seront traitées par les paragraphes (capture ou lancers) qui gèrent IOException

La règle que vous devez être en mesure de faire référence à des objets par leur super-classe est le Principe de Substitution de Liskov.

23voto

syrus.phoenix Points 71

La méthode de substitution peut générer une exception non contrôlée (exécution), que la méthode remplacée déclare ou non l'exception.

Exemple:

 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()");
    }
}
 

15voto

caligari Points 897

À mon avis, c'est un échec dans la conception de la syntaxe Java. Le polymorphisme ne devrait pas limiter l'utilisation de la gestion des exceptions. En fait, les autres langages informatiques ne le font pas (C #).

De plus, une méthode est surchargée dans une sous-classe plus spécialisée, ce qui la rend plus complexe et, pour cette raison, plus susceptible de générer de nouvelles exceptions.

6voto

Dilum Ranatunga Points 7677

Pour illustrer cela, considérons:

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);
  }
}

Supposons que vous ecrivez:

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

Cela vous donnera une erreur de compilation, car r.close() renvoie une IOException, qui est plus large que FileNotFoundException.

Pour résoudre ce problème, si vous écrivez:

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

Vous allez obtenir une autre erreur de compilation, parce que vous êtes la mise en œuvre de l'exécution (...), mais le fait de lancer une exception non inclus dans l'interface de définition de la méthode.

Pourquoi est-ce important? Ainsi un consommateur de l'interface:

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

Si le IOException ont été autorisés à être jetés, le code du client est de ne pas corriger.

Notez que vous pouvez éviter ce genre de problème si vous utilisez décoché exceptions. (Je ne dis pas que vous faites ou ne faites pas, c'est un problème philosophique)

2voto

Peter Perháč Points 8007

dire que vous avez super classe avec la méthode M1 throwin E1 et classe B découlant d'Une méthode M2 primordial M1. M2 ne pouvez pas lancer quelque chose de DIFFÉRENT ou MOINS SPÉCIALISÉES que E1.

En raison de polymorphisme, le client à l'aide de la classe doit être en mesure de traiter la B comme si c'était A. Inharitance ===> Est-a (B-A). Si ce code relatifs à la catégorie a de la manipulation exception E1, M1 déclare qu'il jette cette case cochée exception, mais ensuite les différents type d'exception a été levée? Si M1 jetait IOException M2 pourrait bien jeter FileNotFoundException, tel qu'il est-une IOException. Les Clients de l'Un pourrait gérer cela sans problème. Si l'exception générée était plus large, les clients de l'Un n'aurait pas une chance de le savoir et, par conséquent, n'aurait pas une chance de l'attraper.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X