Neošetřené výjimky v polních initializations

hlasů
22

Má Java nějakou syntaxi pro správu výjimek, které by mohly být vymrštěny při deklaraci a inicializaci proměnné členů třídu je?

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

Nebo takové inicializace musí vždy být přesunuty do způsobu, kde můžeme deklarovat throws IOExceptionnebo zabalit inicializaci v bloku try-catch?

Položena 22/06/2009 v 19:11
zdroj uživatelem
V jiných jazycích...                            


7 odpovědí

hlasů
3

to je nejlepší praxí přesunout tyto druhy inicializace na metody, které mohou vlastnost zpracování výjimek.

Odpovězeno 22/06/2009 v 19:14
zdroj uživatelem

hlasů
20

Použít statickou inicializaci bloku

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
  ...
}
Odpovězeno 22/06/2009 v 19:22
zdroj uživatelem

hlasů
2

Tato stavba je nezákonné, jak jste objevili. Členové, jejichž konstruktéři hodit kontrolovat výjimky nemohou být konstruovány s výjimkou, když je v kontextu, který umožňuje zpracování výjimek, jako je konstruktér, instance inicializátoru, nebo (pro statický člen) statické inicializátor.

Takže by to bylo legální způsob, jak to udělat:

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

Legální, ale spíše ošklivý. Dal bych přednost buď inicializaci v konstruktoru a prohlašuje výjimku tam, anebo dělat uživatel volání metody jej explicitně inicializovat. Ale v případě, že uživatel musí ji inicializovat, musíte pak účet v každém závislých metod možností objektu je neplatný.

Pokud píšete MyClassjako obálka pro MyFileWriter, řekl bych udělat inicializaci v konstruktoru. Jinak bych nejprve otázku, zda je třeba mít spisovatel otevřený během objektu celou dobu životnosti. Je možné refaktorovat to pryč.

Edit: Když jsem psal toto, „ static“ nebyl přidán do pole. Tím se změní věci dost: I teď bych rád věděl, proč proboha chcete mít spisovatel otevřen ClassLoader to celou dobu životnosti. Jak by to vůbec být uzavřen?

Je to podomácku přihlášení systém nějakého druhu? Pokud ano, tak bych vám, abyste se podívat na java.util.loggingnebo některý z mnoha jemných třetích stran protokolování rámců kolem.

Odpovězeno 22/06/2009 v 19:23
zdroj uživatelem

hlasů
0

V případě, že třída má jen jeden konstruktor, obvykle se pohybuji takové inicializátory do tohoto konstruktoru.

V případě, že třída má více než jeden konstruktor, mohu použít inicializační blok:

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

Zajímavou věcí kolem init. Blok je to, že je „vstřikuje“ do začátku každého konstruktéra. Tak, nemusíte duplikovat inicializátory.

Odpovězeno 22/06/2009 v 19:23
zdroj uživatelem

hlasů
0

Navrhuji tovární metodu:

  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(String path) throws IOException{

        MyFileWriter writer  = new FileWriter();

       //stuff that can throw IOException here.

       return writer;
     }

   /*protected constructor*/
    protected MyFileWriter(){

     //build object here.

    } 
  }
Odpovězeno 22/06/2009 v 19:31
zdroj uživatelem

hlasů
3

Výjimka vyvolá ze statického intialiser může znamenat problém návrhu. Opravdu byste neměli pokoušet o načtení souborů do statiky. Také statický by neměly obecně být proměnlivé.

Například práci zpět s JUnit 3.8.1 můžete použít téměř ze applet / WEBSTART, ale to se nepodařilo kvůli jedné statické initialiser dělá přístup k souborům. Zbytek třídy zapojené byl vybaven kontextovou pokutu, je to právě tento kousek statické elektřiny, které se nevešly kontext a foukal celý rámec pryč.

Existují některé legitimní případy, kdy je vyvolána výjimka. Jestli je to pravda, že prostředí nemá konkrétní funkci, řekněme, protože je to starý JDK, pak budete chtít nahradit implementace, a není nic neobvyklého. Jestli je opravdu borked třída, házet nekontrolovanou výjimku, spíše než aby zlomený třída existovat.

V závislosti na vašich preferencí a problém po ruce, je tu dva běžné způsoby, jak jít kolem něj: explicitní statické initialiser a statické metody. (I, a myslím, že většina lidí, preferují bývalý;. Domnívám se, Josh Bloch preferuje druhá)

private static final Thing thing;

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

Nebo

private static final Thing thing = newThing();

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

Poznámka: statika by měla být konečná (a obecně neměnné). Být konečný, správný jediný úkol je zkontrolovat svým přátelským kompilátoru. Určitý úkol znamená, že může zachytit zlomené zpracování výjimek - zabalit a vyhodit, netisknou / log. Kupodivu, nelze uživatelské jméno třídy kvalifikovat inicializace s názvem třídy ve statickém initialiser (Jsem si jistý, že je to dobrý důvod pro to).

Instance initialisers jsou podobné, i když si můžete udělat konstruktoru hod nebo si můžete dát initialiser uvnitř konstruktoru.

Odpovězeno 22/06/2009 v 21:29
zdroj uživatelem

hlasů
0

Tam je další způsob, jak zvládnout výjimky v polních inicializace. Pojďme zvážit svůj případ, kdy MyFileWriter vyvolá výjimku. Vezměme si tento ukázkový kód pro reference.

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

Pokusíme-li se inicializovat soubor takhle .....

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

}

Překladač nedovolí nám inicializovat tato. Místo toho, aby dělal inicializace ve statickém bloku, můžete to udělat takhle

Deklarovat výchozí konstruktor, který vyvolá IOException

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

    }    
}

To bude inicializovat MyFileWriter objekt.

Odpovězeno 14/03/2015 v 18:53
zdroj uživatelem

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more