> the closure solution couldn't enforce correct usage
It does. You can enforce using the closure in a library, but it would be quite hard to use.
> It really isn't hard to use.
> It's probably just different from what you are used to.
I'm used to. Runnable, Arrays.sort(.., Comparator) and so on. It is hard to use: How do you change a variable of the outer block in the inner block? It's possible (for example using one-element arrays) but it's ugly. Even accessing a variable of the main block is complicated (you need to make it final). The closure (Block.execute in the example above) needs to declare exception(s) the block can throw, and the caller has to catch that (even if he doesn't throw any). Or you don't declare, but then the caller can't use checked exceptions. Then the size of the code is bigger.
> If I call getStream(Object sync),
> I need to synchronize on sync within a second, right?
No, you need to sync on the object _before_ calling getStream. Example:
synchronized void exampleClient() throws Exception {
// anything
InputStream in = myApi.getStream(this);
// read...
// no need to call in.close() (but you can)
// the stream is closed even if you throw exceptions
}
In this case 'this' is the sync object. Another example:
Binary b = node.getProperty("jcr:content").getBinary();
synchronized(b) {
InputStream in = b.getStream();
// read... same as above
}
In this case the sync object is not even passed. Instead, the sync object is 'b' (the object where you call getStream()).
> I think you mean each and every library.
> Also, each library needs to do this.
Well, obviously. I'm quite sure you didn't understand my solution, otherwise you wouldn't ask. The 'synchronized' solution enforces using synchronized in the client code, if the 'synchronized' solution is used in the library.