2009-08-14 11 views
6

Je veux que l'API de mon module ne lève MyPackageSpecificException que lorsque quelque chose ne va pas et que le module ne peut pas effectuer sa tâche. (L'exception d'origine sera donnée comme cause de l'exception MyPackageSpecificException).Exceptions d'enveloppes levées dans super/ce constructeur appelle d'autres exceptions

Maintenant, pour un constructeur, j'avais besoin d'une URL comme paramètre pour localiser une ressource. Je voudrais aussi faire un constructeur alternative à laquelle une représentation de chaîne de l'URL peut être donnée:

public MyClass(String urlString) throws MalformedURLException{ 
    this(new URL(urlString)); 
} 

Comme le constructeur URL lance MalformedURLException, je veux l'envelopper dans un MyPackageSpecificException en faisant:

public MyClass(String urlString) throws MyPackageSpecificException{ 
    try{ 
     this(new URL(urlString)); 
    } catch (MalformedURLException e){ 
     throw new MyPackageSpecificException(e); 
    } 
} 

Mais, ce qui précède n'est pas valide, car l'appel du constructeur super() ou this() doit se produire sur la première ligne du constructeur.

Le même problème s'applique si le constructeur super() ou this() renvoie une exception que je souhaite placer dans quelque chose d'autre.

Comment dois-je résoudre ce problème? Ou est ce que j'essaie de faire une mauvaise pratique?

Répondre

6

Effectuez les opérations suivantes:

public class MyClass 
{ 
    private URL url; 

    public MyClass(URL url) 
    { 
    this.url = url; 
    } 

    public MyClass(String urlString) throws MyPackageSpecificException 
    { 
    this(toURL(urlString)); 
    } 

    private static URL toURL(String urlString) throws MyPackageSpecificException 
    { 
    try 
    { 
     return new URL(urlString)); 
    } 
    catch (MalformedURLException e) 
    { 
     throw new MyPackageSpecificException(e); 
    } 
    } 
} 
+0

Je ne peux pas croire que je n'y ai pas pensé. Simple, et fait exactement ce que je veux. – Alderath

3

Si elle correspond à votre code, vous pouvez utiliser une méthode de création statique au lieu:

private MyClass(String urlString) { ... } 

public static MyClass createMyClass(String urlString) throws MyPackageSpecificException { 
    try { 
    new MyClass(urlString); 
    catch (Exception e) { 
    throw new MyPackageSpecificException(e); 
    } 
} 
+1

Ceci est en fait mieux que la réponse acceptée, car elle fonctionnera pour le cas générique, alors que la réponse acceptée ne fonctionnera que si vous pouvez trouver (et « convertir » à) un constructeur superclasse qui ne jette pas exceptions indésirables. Modèle d'usine FTW, je suppose. – Coderer

0

Au lieu d'utiliser cette() ont une méthode init commune() Cela prend l'argument URL de cette façon, il n'a pas besoin d'être la première ligne du constructeur.

public MyClass(String url) throws MyPackageSpecificException 
{ 
    try 
    { 
    init(new URL(url)); 
    } 
    catch (MalformedURLException e) 
    { 
    throw new MyPackageSpecificException(e); 
    } 
} 

public MyClass(URL url) 
{ 
    init(url); 
} 

private void init(URL url) 
{ 
    // do constructor work here 
} 
+1

Cela vous empêche d'affecter des paramètres de constructeur aux champs finaux, ce qui rend plus difficile la création de classes immuables. L'affectation de champs finaux ne peut être effectuée que dans le constructeur. –

+0

Étant une solution viable à l'exemple que j'ai posté, ceci ne fonctionne cependant pas si l'URL doit être passée à un super constructeur, c'est pourquoi j'ai préféré les autres solutions. – Alderath