Schliessen mehrerer abhängiger Resourcen (Java 6)

Ich habe drei voneinander abhängige Ressourcen: (ob Closeable ist nicht sicher)
QueueConnection, QueueSession und QueueSender. Wobei diese drei aus create-Methoden erzeugt werden. Diese Methoden können alle eine XException werfen. Da in dieser Erzeugungskette an jeder Stelle etwas schiefgehen kann, muss ich im finally Block jede Resource auf null prüfen und gegebenenfalls schlieszen. Diese “Aufräumungsmethoden” können jedoch selbst wieder fehlschlagen und wieder eine XException werfen. Wenn in dieser Kette im finally Block etwas schiefgeht, bleiben mitunter Ressourcen offen. Eine Lösung wäre, für jede Ressource im finally Block einen separaten try-catch-Block zu benutzen - insgesamt etwas unschön, aber es sollte gehen. Damit hat jede Ressource einen Versuch frei.

Gibt es bessere Ansätze?

Meine Lösung:

try {
    r1 = X.create();
    r2 = Y.create();
    r3 = Z.create();
}
catch () {
    log...
}
finally {
    try {
        r1.close();
    }
    catch() {
        log...
    }
    gleiche try-catch-Blöcke für r2 und r3
}

im Moment hast du ja keine null-Prüfung für r1 im finally, wäre das noch zusätzlich angedacht?

hilfreich ist in jedem Fall eine Methode zum Aufräumen, wiederholt aufgerufen,
idealerweise etwa close(r1);
für jeden schließbaren Typ vorhanden oder noch besser gemeinsames Interface Closable

notfalls auch ein Aufruf mit Runnable als Java-8-Abkürzung

[code]
close( ()->r1.close() );

private void close(Runnable r) {
try {
r.run();
} catch …
}[/code]

wobei dann Nullprüfung nicht gut möglich ist, bei NPE evtl. nichts machen, oder das Objekt selber als zweiten Parameter und dieses auf null prüfen


https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html
auch bekannt?
wenn man dort das richtige Interface implementiert dann vielleicht auch für eigene Klassen zu nutzen,
falls nicht eh schon Standardklassen beteiligt
(edit: ok, Java 6…)

Eine Methode

private void close(Closeable stream) { try { stream.close(); } catch(IOException e) { // log... } }erstellen und im finally-Block

close(r1); close(r2); close(r3);aufrufen.

Edit: Ach ja… Null-Prüfung nicht vergessen, so wie ich. :wink:

Die Hinweise zu Java 7 und 8 sind etwas irritierend, wenn Java 6 sogar im Titel steht. Vermutlich irgendein JEE-Dinosaurier :smiley:

Aber… irgendeine Utility-Funktion sollte das ganze doch recht übersichtlich machen…?!

import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;

public class CloseMany
{
    public static void main(String[] args)
    {
        InputStream r1 = null;
        InputStream r2 = null;
        InputStream r3 = null;
        try
        {
            r1 = create();
            r2 = create();
            r3 = create();
        } 
        catch (IOException e)
        {
            log(e);
        } 
        finally
        {
            tryCloseAll(r1, r2, r3);
        }
    }
    
    private static void tryCloseAll(Closeable ... closeables)
    {
        for (Closeable closeable : closeables)
        {
            tryClose(closeable);
        }
    }
    
    private static void tryClose(Closeable closeable)
    {
        if (closeable != null)
        {
            try
            {
                closeable.close();
            } 
            catch (IOException e)
            {
                log(e);
            }
        }
    }

    private static InputStream create() throws IOException
    {
        return null;
    }
    
    private static void log(Object object)
    {
    }
}

Nun hast du explizit gesagt, dass nicht klar ist, ob die Closeable sind. Aber wenn nicht, müßte man sich was überlegen - vielleicht noch eine Art „Closer“-Interface mit implementierungen für die drei Typen erstellen oder so…

EDIT: Bzw. utility-Funktionen, die die Objekte einwickeln, und als „Closeable“ zurückgeben:

private static Closeable closeable(SomeType t) {
    return new Closeable() { 
        @Override
        public void close() {
            if (t != null) t.specificClose();
       }
   };
}

und dann eben

tryCloseAll(closeable(r1), closeable(r2),  ...);

waren Dir die Antworten hier nicht gut genug?
;o)

Doch waren alle gut. Soll ich jetzt das Thema schliessen? Oder mich explizit bedanken?

Dann tu ich das hier schon mal. Danke an alle!

[quote=„Falk, post:6, topic:19046“]
Soll ich jetzt das Thema schliessen?[/quote] So weit ich weis kannst Du eine (oder mehrere?) Antwort als „richtig“ oder „hilfreich“ o.ä. markieren.

Auf die Herzchen klicken wird auch immer gern gesehen… ;o)

bye
TT