Force try-with-resources Java 7
Asked Answered
T

3

7

I have a class which implements AutoCloseable, and is intended to be used with Java 7's new try-with-resources construct. However, I can't figure out a way to guarantee that the user of my class uses try-with-resources. If this doesn't happen, then my class won't be able to close itself, and bad things will happen. Is there any way - language construct or otherwise - to enforce this? Even being able to detect whether or not I'm in a try-with-resources block so that I can throw an exception if not would be good (although a compile-time construct would be preferable).

Thanks!

Tied answered 2/7, 2013 at 16:7 Comment(5)
What is the user wanted to manage closeing your class manually instead of automagically with a try-with-resources? Would creating a finalize method that called close fix your problem?Hypermeter
Unfortunately, finalize is not guaranteed to be called. The GC may decide not to call it.Tied
In fact, I imagine that the unreliability of finalize is probably the reason that try-with-resources was introduced.Tied
It's better than nothing, and there is no guarantee that your user has to call close on your class before it gets GCed.Hypermeter
That's the whole point - I'm trying to figure out how to implement such a guarantee. If I can force them to use try-with-resources, then I get that guarantee.Tied
V
4

Unfortunately there's no way to protect yourself from user stupidity.

You can implement the finalize method to call close; this way you can be sure that the resource is closed at least when the object is garbage collected, even though you can't know when (or if) that happens.

If you can put restrictions on how your project is used, you may be able to enforce some policies using aspect oriented programming, but then you're not really using Java anymore.

Verona answered 2/7, 2013 at 16:12 Comment(4)
The use of Object.finalize() is highly discouraged in java.Hembree
Unless you know what you are doing and have no other option ;)Verona
@DavidHofmann: I think you have misunderstood something. It's probably (and with reason) discouraged to rely on finalize being invoked by the GC, but actually implementing the finalize method is in some cases the only option to prevent resource leakage.Vortical
I agree @jarnbjo, I would however let the client of my api die fast and keep them informed about the missuse of the api, than allowing them to have non-deterministic behaviour.Hembree
D
1

If you really care about resource management, then using a callback idiom is the safest approach. You don't expose the collection, but an API that allows the end-user to handle items in the collection:

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

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

You can change Callback.handle(T) to return a boolean if you want to support early exit:

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

If you want to stay away from defining your own callback interface, you can use Guava's Function<T, Boolean> or Predicate<T>, but note that it violates the semantics established by Guava:

Instances of Function are generally expected to be referentially transparent -- no side effects -- and to be consistent with equals, that is, a.equals(b) implies that function.apply(a).equals(function.apply(b)).

Instances of Predicate are generally expected to be side-effect-free and consistent with equals.

Durand answered 31/12, 2013 at 22:26 Comment(0)
H
-1

No, there is no way, Same bad things will happen if you keep opening files or database connections and you don't close them...

If the sensible resources can be used and discarted within the scope of one method call, you can open/close every time your api is called, if not, then just have well documented the behaviour.

Your class might also register a shutdown hook so you can at least close your resources when the jvm is going down, but I see this as a bad practice for a library anyway.

Hembree answered 2/7, 2013 at 16:12 Comment(2)
You're wrong. Both files and network or database connections are closed when finalizing the respective wrapper instances as a last possibility to prevent resource leakage. There's no good reason not to use the same implementation pattern for own purposes.Vortical
Thanks @Vortical for clarification. What I had in mind though is that if you keep opening resources without closing them, you have a leak. I think it is anyway better to see the leak sooner than later, in the case that you somehow keep references to the unclosed objects then no finalize meethod will be called. If you rely on GC, you might have non-deterministic behaviour depending on the amount of ram and gc tunning that runs your programHembree

© 2022 - 2024 — McMap. All rights reserved.