Does Clojure have an equivalent of Java's try-with-resources construct?
If not, what is the normal way to handle this idiom in Clojure code?
The pre-Java-7 idiom for safely opening and closing resources is verbose enough that they actually added support for try-with-resources to the language. It seems strange to me that I can't find a macro for this use case in the standard Clojure library.
An example to a mainstream Clojure-based project repository—showing how this issue is handled in practice—would be very helpful.
In Java, the try-with-resources statement is a try statement that declares one or more resources. The resource is as an object that must be closed after finishing the program. The try-with-resources statement ensures that each resource is closed at the end of the statement execution.
Yes, It is possible to have a try block without a catch block by using a final block. As we know, a final block will always execute even there is an exception occurred in a try block, except System. exit() it will execute always.
We can declare multiple resources in a try block. Try initialization block can have any number of resources resulting in either null or non-null resources. In the below example, we can able to declare multiple resources in the try-with-resources statement.
The Java try with resources construct, AKA Java try-with-resources, is an exception handling mechanism that can automatically close resources like a Java InputStream or a JDBC Connection when you are done with them. To do so, you must open and use the resource within a Java try-with-resources block.
You can use with-open to bind a resource to a symbol and make sure the resource is closed once the control flow left the block.
The following example is from clojuredocs.
(with-open [r (clojure.java.io/input-stream "myfile.txt")] 
     (loop [c (.read r)] 
       (when (not= c -1)
         (print (char c)) 
         (recur (.read r)))))
This will be expanded to the following:
(let [r (clojure.java.io/input-stream "myfile.txt")] 
  (try
    (loop [c (.read r)] 
      (when (not= c -1)
        (print (char c)) 
        (recur (.read r))))
    (finally (.close r))))
You can see that a let block is created with a try-finally to the call .close() method.
you can do something more close to java, making up some macro on top of with-open. It could look like this: 
(defmacro with-open+ [[var-name resource & clauses] & body]
  (if (seq clauses)
    `(try (with-open [~var-name ~resource] ~@body)
          ~@clauses)
    `(with-open [~var-name ~resource] ~@body)))
so you can pass additional clauses alongside the binding.
(with-open+ [x 111]
  (println "body"))
expands to simple with-open:
(let*
  [x 111]
  (try (do (println "body")) (finally (. x clojure.core/close))))
while additional clauses lead to wrapping the it in try-catch:
(with-open+ [x 111
             (catch RuntimeException ex (println ex))
             (finally (println "finally!"))]
  (println "body"))
expands to
(try
  (let*
    [x 111]
    (try (do (println "body")) (finally (. x clojure.core/close))))
  (catch RuntimeException ex (println ex))
  (finally (println "finally!")))
But still it is quite an opinionated solution.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With