How can I throw an exception in Clojure?

ExceptionException HandlingClojureFunctional Programming

Exception Problem Overview


I wish to throw an exception and have the following:

(throw "Some text")

However it seems to be ignored.

Exception Solutions


Solution 1 - Exception

You need to wrap your string in a Throwable:

(throw (Throwable. "Some text"))

or

(throw (Exception. "Some text"))

You can set up a try/catch/finally block as well:

(defn myDivision [x y]
  (try
    (/ x y)
    (catch ArithmeticException e
      (println "Exception message: " (.getMessage e)))
    (finally 
      (println "Done."))))

REPL session:

user=> (myDivision 4 2)
Done.
2
user=> (myDivision 4 0)
Exception message:  Divide by zero
Done.
nil

Solution 2 - Exception

clojure.contrib.condition provides a Clojure-friendly means of handling exceptions. You can raise conditons with causes. Each condition can have its own handler.

There are a number of examples in the source on github.

It's quite flexible, in that you can provide your own key, value pairs when raising and then decide what to do in your handler based on the keys/values.

E.g. (mangling the example code):

(if (something-wrong x)
  (raise :type :something-is-wrong :arg 'x :value x))

You can then have a handler for :something-is-wrong:

(handler-case :type
  (do-non-error-condition-stuff)
  (handle :something-is-wrong
    (print-stack-trace *condition*)))

Solution 3 - Exception

If you want to throw an exception and include some debugging info in it (in addition to a message string), you can use the built-in ex-info function.

To extract the data from the previously-constructed ex-info object, use ex-data.

Example from clojuredocs:

(try
  (throw 
    (ex-info "The ice cream has melted!" 
       {:causes             #{:fridge-door-open :dangerously-high-temperature} 
        :current-temperature {:value 25 :unit :celcius}}))
  (catch Exception e (ex-data e))

In a comment kolen mentioned slingshot, which provides advanced functionality that allows you not only to throw objects of arbitrary type (with throw+), but also use a more flexible catch syntax to inspect data inside thrown objects (with try+). Examples from the project repo:

tensor/parse.clj

(ns tensor.parse
  (:use [slingshot.slingshot :only [throw+]]))

(defn parse-tree [tree hint]
  (if (bad-tree? tree)
    (throw+ {:type ::bad-tree :tree tree :hint hint})
    (parse-good-tree tree hint)))

math/expression.clj

(ns math.expression
  (:require [tensor.parse]
            [clojure.tools.logging :as log])
  (:use [slingshot.slingshot :only [throw+ try+]]))

(defn read-file [file]
  (try+
    [...]
    (tensor.parse/parse-tree tree)
    [...]
    (catch [:type :tensor.parse/bad-tree] {:keys [tree hint]}
      (log/error "failed to parse tensor" tree "with hint" hint)
      (throw+))
    (catch Object _
      (log/error (:throwable &throw-context) "unexpected error")
      (throw+))))

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionyazz.comView Question on Stackoverflow
Solution 1 - ExceptiondbyrneView Answer on Stackoverflow
Solution 2 - ExceptionedoloughlinView Answer on Stackoverflow
Solution 3 - ExceptiondskrvkView Answer on Stackoverflow