Exceptions non gérées dans les initialisations de champ

Est-ce que Java a une syntaxe pour gérer les exceptions qui pourraient être levées lors de la déclaration et de l’initialisation d’une variable membre de la classe?

public class MyClass { // Doesn't comstack because constructor can throw IOException private static MyFileWriter x = new MyFileWriter("foo.txt"); ... } 

Ou bien ces initialisations doivent-elles toujours être déplacées dans une méthode permettant de déclarer des throws IOException ou d’envelopper l’initialisation dans un bloc try-catch?

Utiliser un bloc d’initialisation statique

 public class MyClass { private static MyFileWriter x; static { try { x = new MyFileWriter("foo.txt"); } catch (Exception e) { logging_and _stuff_you_might_want_to_terminate_the_app_here_blah(); } // end try-catch } // end static init block ... } 

Il est recommandé de déplacer ces types d’initialisations vers des méthodes pouvant gérer les exceptions.

Une exception lancée à partir d’un initialiseur statique peut indiquer un problème de conception. En réalité, vous ne devriez pas essayer de charger des fichiers dans des statistiques. De plus, le statique ne devrait pas être mutable en général.

Par exemple, avec JUnit 3.8.1, vous pourriez presque l’utiliser à partir d’une applet / WebStart, mais cela a échoué en raison de l’initialisation par un initialiseur statique de l’access aux fichiers. Le rest de la classe impliquée a été ajusté au contexte, c’est juste ce morceau statique qui ne correspond pas au contexte et qui détruit tout le cadre.

Il existe des cas légitimes où une exception est levée. Si l’environnement ne dispose pas d’une fonctionnalité particulière, par exemple parce que c’est un ancien JDK, vous pouvez remplacer les implémentations, et il n’y a rien d’extraordinaire. Si la classe est vraiment bloquée, lancez une exception non vérifiée plutôt que de laisser une classe cassée exister.

En fonction de vos préférences et du problème à résoudre, il existe deux méthodes courantes: un initialiseur statique explicite et une méthode statique. (Je pense, et je pense que la plupart des gens préfèrent le premier, je pense que Josh Bloch préfère le second.)

 private static final Thing thing; static { try { thing = new Thing(); } catch (CheckedThingException exc) { throw new Error(exc); } } 

Ou

 private static final Thing thing = newThing(); private static Thing newThing() { try { return new Thing(); } catch (CheckedThingException exc) { throw new Error(exc); } } 

Note: la statique doit être définitive (et généralement immuable). En tant que final, l’atsortingbution simple correcte est vérifiée par votre compilateur ami. L’affectation définitive signifie qu’elle peut intercepter la gestion des exceptions cassées – wrap et jet, ne pas imprimer / log. Curieusement, vous ne pouvez pas utiliser le nom de la classe pour qualifier l’initialisation avec le nom de la classe dans l’initialiseur statique (je suis sûr qu’il y a une bonne raison à cela).

Les initialiseurs d’instance sont similaires, même si vous pouvez lancer le constructeur ou placer l’initialiseur dans le constructeur.

Cette construction est illégale, comme vous l’avez découvert. Les membres dont les constructeurs émettent des exceptions vérifiées ne peuvent pas être construits, sauf dans un contexte autorisant la gestion des exceptions, tel qu’un constructeur, un initialiseur d’instance ou (pour un membre statique) un initialiseur statique.

Donc, ce serait une façon légale de le faire:

 public class MyClass { MyFileWriter x; { try { x = new MyFileWriter("foo.txt"); } catch (IOException ex) { ex.printStackTrace(); } } ... } 

Légal, mais plutôt moche. Je préférerais soit l’initialiser dans le constructeur et y déclarer l’exception, soit faire en sorte que l’utilisateur appelle une méthode pour l’initialiser explicitement. Mais si l’utilisateur doit l’initialiser, vous devez alors comptabiliser dans les méthodes dépendantes la possibilité que l’object soit invalide.

Si vous écrivez MyClass tant que wrapper pour MyFileWriter , je dirais de faire l’initialisation dans le constructeur. Sinon, je me demande d’abord s’il est nécessaire d’avoir un écrivain ouvert pendant toute la durée de vie de l’object. Il peut être possible de le refaire.

Edit: Quand j’écrivais ceci, le ” static ” n’avait pas été ajouté au champ. Cela change un peu les choses: j’aimerais maintenant savoir pourquoi vous voulez qu’un écrivain soit ouvert pendant toute la vie du chargeur de classe . Comment pourrait-il jamais être fermé?

S’agit-il d’un système de journalisation développé à la maison? Si tel est le cas, je vous encourage à consulter java.util.logging ou l’un des nombreux environnements de journalisation tiers.

Je suggère une méthode d’usine:

  public class MyClass{ private static MyFileWriter fileWriter = MyFileWriter.getFileWriter("foo.txt"); } public class MyFileWriter { /* * Factory method. Opens files, etc etc * @throws IOException. */ public static MyFileWriter getFileWriter(Ssortingng path) throws IOException{ MyFileWriter writer = new FileWriter(); //stuff that can throw IOException here. return writer; } /*protected constructor*/ protected MyFileWriter(){ //build object here. } } 

Il existe un autre moyen de gérer les exceptions dans les initialisations de champ. Prenons votre cas, où le constructeur MyFileWriter lève une exception. Considérez cet exemple de code pour les références.

 import java.io.IOException; public class MyFileWriter { public MyFileWriter(Ssortingng file) throws IOException{ throw new IOException("welcome to [java-latte.blogpspot.in][1]"); } } 

Si nous essayons d’initialiser le fichier comme ça …..

 public class ExceptionFields{ MyFileWriter f = new MyFileWriter("Hello"); } 

Le compilateur ne nous permettra pas d’initialiser ceci. Au lieu de faire l’initialisation dans le bloc statique, vous pouvez faire comme ça

Déclarez un constructeur par défaut qui lance une exception IOException

 import java.io.IOException; public class ExceptionFields{ MyFileWriter f = new MyFileWriter("Hello"); public ExceptionFields() throws IOException{ } } 

Cela initialisera votre object MyFileWriter.

Si la classe n’a qu’un seul constructeur, je déplace généralement de tels initialiseurs dans ce constructeur.

Si la classe a plus d’un constructeur, j’utilise un bloc d’initialisation:

 public class MyClass { private static MyFileWriter x; // initialization block start here { try { x = new MyFileWriter(".."); } catch(Exception e) { // exception handling goes here } } public MyClass() { // ctor #1 } public MyClass(int n) { // ctor #2 } } 

La bonne chose à propos d’un init. block est qu’il est “injecté” au début de chaque constructeur. Ainsi, vous n’avez pas besoin de dupliquer les initialiseurs.