2013-07-02 19 views
5

Mam klasę, która implementuje AutoCloseable i jest przeznaczona do użycia z nową konstrukcją try-Javy Java 7. Jednak nie mogę znaleźć sposobu, aby zagwarantować, że użytkownik mojej klasy używa try-with-resources. Jeśli to się nie stanie, moja klasa nie będzie w stanie się zamknąć, a złe rzeczy się wydarzą. Czy istnieje jakiś sposób - konstruowanie języka lub w inny sposób - w celu egzekwowania tego? Nawet możliwość wykrycia, czy jestem w bloku try-with-resources, czy mogę rzucić wyjątek, jeśli nie byłaby dobra (chociaż lepiej byłoby skonstruować kompilację czasu).Wymuś wypróbuj-z-zasobami Java 7

Dzięki!

+0

Co to jest użytkownik, który chce zarządzać zamykaniem swojej klasy ręcznie, zamiast automagicznie za pomocą metody try-with-resources? Czy stworzenie metody 'finalizacji', która nazywa się' zamknij', naprawia twój problem? – Jeffrey

+0

Niestety, 'sfinalizuj' nie ma gwarancji, że zostanie wywołane. GC może zdecydować, że tego nie nazwie. – joshlf

+0

W rzeczywistości, wyobrażam sobie, że niewiarygodność 'sfinalizowania' jest prawdopodobnie powodem wprowadzenia try-for-resources. – joshlf

Odpowiedz

3

Niestety, nie ma sposobu, aby uchronić się przed głupotą użytkownika.

Możesz wdrożyć metodę finalize, aby zadzwonić pod numer close; w ten sposób możesz mieć pewność, że zasób jest zamknięty przynajmniej wtedy, gdy obiekt jest zbierany śmieci, nawet jeśli nie możesz wiedzieć, kiedy (lub jeśli) to się stanie.

Jeśli można wprowadzić ograniczenia w sposobie używania projektu, może być możliwe egzekwowanie niektórych zasad przy użyciu programowania zorientowanego na aspekt, ale w rzeczywistości nie używamy już Javy.

+1

Używanie Object.finalize() jest wysoce odradzane w java. –

+0

Jeśli nie wiesz, co robisz * i * nie masz innej opcji;) – Joni

+2

@DavidHofmann: Myślę, że coś źle zrozumiałeś. Prawdopodobnie (i z uzasadnieniem) zniechęca się do sfinalizowania wywołania przez GC, ale w rzeczywistości * wdrażanie * metody finalizacji jest w niektórych przypadkach jedyną opcją zapobiegania wyciekowi zasobów. – jarnbjo

-1

Nie, nie ma sposobu, same złe rzeczy się stanie, jeśli trzymać otwierania plików lub połączenia z bazą danych, a nie je zamknąć ...

Jeśli Sensible zasoby mogą być wykorzystane i discarted w zakresie jednego wywołania metody można otwierać/zamykać za każdym razem, gdy api jest wywoływane, jeśli nie, to po prostu dobrze udokumentowane zachowanie.

Twoja klasa może również zarejestrować hak zamknięcia, abyś mógł przynajmniej zamknąć swoje zasoby, gdy jvm jest wyłączany, ale i tak uważam to za złą praktykę biblioteki.

+1

Mylisz się. Zarówno pliki, jak i połączenia sieciowe lub bazy danych są zamykane, gdy finalizowanie odpowiednich instancji opakowania jest ostatnią możliwością zapobiegania wyciekom zasobów. Nie ma żadnego powodu, aby nie używać tego samego wzoru wdrożenia do własnych celów. – jarnbjo

+0

Dzięki @jarnbjo dla wyjaśnienia. Miałem jednak na myśli to, że jeśli otwierasz zasoby bez ich zamykania, masz przeciek. Myślę, że lepiej jest zobaczyć przeciek wcześniej niż później, w przypadku, gdy w jakiś sposób będziesz utrzymywał odniesienia do niezamkniętych obiektów, wtedy nie zostanie wywołane żadne sfinalizowanie spotkania. Jeśli polegasz na GC, możesz mieć niedeterministyczne zachowanie w zależności od ilości tuningu ramek i gc, które uruchamia twój program –

1

Jeśli naprawdę zależy Ci na zarządzaniu zasobami, najbezpieczniejszym rozwiązaniem jest używanie języka zwrotnego. Nie wystawiać kolekcję, ale API, które pozwala użytkownikowi końcowemu w obsłudze elementy w kolekcji:

public interface Callback<T> { 
    void handle(T item); 
} 

public class SuperVitalVault { 
    public void all(Callback<Precious> callback) { 
    try (...) { 
     for (Precious i : ...) { 
     callback.handle(i); 
     } 
    } 
    } 
} 

Można zmienić Callback.handle(T) zwrócić boolean jeśli chcesz wesprzeć wczesne wyjście:

try (...) { 
     for (Precious i : ...) { 
     if (callback.handle(i)) break; 
     } 
    } 

Jeśli chcesz się trzymać z dala od zdefiniowania własnego interfejsu oddzwonienia, ale można użyć Guava na Function<T, Boolean> lub Predicate<T>, trzeba pamiętać, że narusza semantykę ustanowionych przez Guava:

Instancje funkcji mają zazwyczaj wyglądać jako przejrzyste - brak efektów ubocznych - i być zgodne z wartościami równymi, to znaczy a.equals (b) oznacza, że ​​function.apply (a) .equals (function.apply (b)).

Prawdopodobieństwa wystąpienia orzeczenia są zwykle wolne od skutków ubocznych i zgodne z wartością równą.